From 7f31812e3cce2157bbb2bf9809ed276eb3b27911 Mon Sep 17 00:00:00 2001 From: Harald Schilly Date: Tue, 7 Jan 2025 14:34:28 +0100 Subject: [PATCH] frontend/admin: set the user UI lang temporarily to the one of the admin --- .../frontend/admin/users/impersonate.tsx | 11 +++++++--- src/packages/server/auth/impersonate.ts | 20 +++++++++++++------ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/packages/frontend/admin/users/impersonate.tsx b/src/packages/frontend/admin/users/impersonate.tsx index 66d7373673..b0d7a3fc38 100644 --- a/src/packages/frontend/admin/users/impersonate.tsx +++ b/src/packages/frontend/admin/users/impersonate.tsx @@ -5,11 +5,13 @@ import { Alert, Card } from "antd"; import { join } from "path"; + import { Rendered, useEffect, useState } from "@cocalc/frontend/app-framework"; import { Icon, Loading } from "@cocalc/frontend/components"; import { appBasePath } from "@cocalc/frontend/customize/app-base-path"; import { webapp_client } from "@cocalc/frontend/webapp-client"; import { CopyToClipBoard } from "@cocalc/frontend/components"; +import { useLocalizationCtx } from "@cocalc/frontend/app/localize"; interface Props { account_id: string; @@ -21,11 +23,13 @@ export function Impersonate({ first_name, last_name, account_id }: Props) { const [auth_token, set_auth_token] = useState(null); const [err, set_err] = useState(null); const [extraWarning, setExtraWarning] = useState(false); + const { locale } = useLocalizationCtx(); async function get_token(): Promise { try { - const auth_token = - await webapp_client.admin_client.get_user_auth_token(account_id); + const auth_token = await webapp_client.admin_client.get_user_auth_token( + account_id, + ); set_auth_token(auth_token); set_err(null); } catch (err) { @@ -43,9 +47,10 @@ export function Impersonate({ first_name, last_name, account_id }: Props) { return ; } + // The lang_temp temporarily sets the interface language of the user to impersonate to the one of the admin const link = join( appBasePath, - `auth/impersonate?auth_token=${auth_token}&lang_temp=en`, + `auth/impersonate?auth_token=${auth_token}&lang_temp=${locale}`, ); const handleClick = (event: React.MouseEvent) => { diff --git a/src/packages/server/auth/impersonate.ts b/src/packages/server/auth/impersonate.ts index 0904c0b895..3bfb9372dd 100644 --- a/src/packages/server/auth/impersonate.ts +++ b/src/packages/server/auth/impersonate.ts @@ -1,12 +1,14 @@ /* Sign in using an impersonation auth_token. */ -import getPool from "@cocalc/database/pool"; -import { createRememberMeCookie } from "@cocalc/server/auth/remember-me"; import Cookies from "cookies"; + import { REMEMBER_ME_COOKIE_NAME } from "@cocalc/backend/auth/cookie-names"; -import clientSideRedirect from "@cocalc/server/auth/client-side-redirect"; -import { getServerSettings } from "@cocalc/database/settings/server-settings"; import base_path from "@cocalc/backend/base-path"; +import getPool from "@cocalc/database/pool"; +import { getServerSettings } from "@cocalc/database/settings/server-settings"; +import clientSideRedirect from "@cocalc/server/auth/client-side-redirect"; +import { createRememberMeCookie } from "@cocalc/server/auth/remember-me"; +import { isLocale } from "@cocalc/util/i18n/const"; export async function signInUsingImpersonateToken({ req, res }) { try { @@ -17,7 +19,7 @@ export async function signInUsingImpersonateToken({ req, res }) { } async function doIt({ req, res }) { - const { auth_token } = req.query; + const { auth_token, lang_temp } = req.query; if (!auth_token) { throw Error("invalid empty token"); } @@ -40,7 +42,13 @@ async function doIt({ req, res }) { }); const { dns } = await getServerSettings(); - const target = `https://${dns}${base_path}`; + let target = `https://${dns}${base_path}app`; + + // if lang_temp is a locale, then append it as a query parameter. + // This is usally "en" to help admins understanding the UI without changing the user's language preferences. + if (isLocale(lang_temp)) { + target += `?lang_temp=${encodeURIComponent(lang_temp)}`; + } clientSideRedirect({ res, target }); }