From 26194a4dbf9acac8514c4ec63f6aac578c07441b Mon Sep 17 00:00:00 2001 From: Alexey Zinoviev Date: Wed, 23 Apr 2025 06:33:57 +0400 Subject: [PATCH] UBERF-10303: Always sign up with OTP (#8665) --- desktop/src/ui/platform.ts | 1 + desktop/src/ui/types.ts | 1 + dev/prod/src/platform.ts | 2 + packages/account-client/src/client.ts | 9 ++- packages/presentation/src/plugin.ts | 3 +- plugins/login-assets/lang/cs.json | 4 +- plugins/login-assets/lang/de.json | 4 +- plugins/login-assets/lang/en.json | 4 +- plugins/login-assets/lang/es.json | 4 +- plugins/login-assets/lang/fr.json | 4 +- plugins/login-assets/lang/it.json | 4 +- plugins/login-assets/lang/ja.json | 4 +- plugins/login-assets/lang/pt.json | 4 +- plugins/login-assets/lang/ru.json | 4 +- plugins/login-assets/lang/zh.json | 4 +- plugins/login-resources/src/analytics.ts | 1 + .../src/components/LoginApp.svelte | 5 +- .../src/components/LoginForm.svelte | 3 +- .../src/components/OtpForm.svelte | 5 +- .../src/components/SignupForm.svelte | 60 +++++++++++-------- plugins/login-resources/src/plugin.ts | 4 +- plugins/login-resources/src/utils.ts | 16 +++-- qms-tests/sanity/tests/model/login-page.ts | 1 - qms-tests/sanity/tests/model/signup-page.ts | 7 --- server/account/src/operations.ts | 8 ++- server/front/src/index.ts | 2 + server/front/src/starter.ts | 5 +- tests/sanity/tests/login.spec.ts | 2 - tests/sanity/tests/model/login-page.ts | 7 +-- tests/sanity/tests/model/signup-page.ts | 1 - tests/sanity/tests/workspace/create.spec.ts | 3 +- .../sanity/tests/workspace/create.spec.ts | 3 +- 32 files changed, 116 insertions(+), 73 deletions(-) diff --git a/desktop/src/ui/platform.ts b/desktop/src/ui/platform.ts index ad8b5144c8..5c9d320a3d 100644 --- a/desktop/src/ui/platform.ts +++ b/desktop/src/ui/platform.ts @@ -251,6 +251,7 @@ export async function configurePlatform (): Promise { setMetadata(presentation.metadata.UploadConfig, parseUploadConfig(config.UPLOAD_CONFIG, config.UPLOAD_URL)) setMetadata(presentation.metadata.FrontUrl, config.FRONT_URL) setMetadata(presentation.metadata.LinkPreviewUrl, config.LINK_PREVIEW_URL ?? '') + setMetadata(presentation.metadata.MailUrl, config.MAIL_URL) setMetadata(recorder.metadata.StreamUrl, config.STREAM_URL ?? '') setMetadata(presentation.metadata.StatsUrl, config.STATS_URL) diff --git a/desktop/src/ui/types.ts b/desktop/src/ui/types.ts index 16ffe051cd..3989ef9ec2 100644 --- a/desktop/src/ui/types.ts +++ b/desktop/src/ui/types.ts @@ -43,6 +43,7 @@ export interface Config { PUBLIC_SCHEDULE_URL?: string CALDAV_SERVER_URL?: string EXPORT_URL?: string + MAIL_URL?: string } export interface Branding { diff --git a/dev/prod/src/platform.ts b/dev/prod/src/platform.ts index 4c37d428e4..c61fb61c35 100644 --- a/dev/prod/src/platform.ts +++ b/dev/prod/src/platform.ts @@ -186,6 +186,7 @@ export interface Config { PUBLIC_SCHEDULE_URL?: string CALDAV_SERVER_URL?: string EXPORT_URL?: string + MAIL_URL?: string } export interface Branding { @@ -428,6 +429,7 @@ export async function configurePlatform() { setMetadata(presentation.metadata.UploadConfig, parseUploadConfig(config.UPLOAD_CONFIG, config.UPLOAD_URL)) setMetadata(presentation.metadata.StatsUrl, config.STATS_URL) setMetadata(presentation.metadata.LinkPreviewUrl, config.LINK_PREVIEW_URL) + setMetadata(presentation.metadata.MailUrl, config.MAIL_URL) setMetadata(recorder.metadata.StreamUrl, config.STREAM_URL) setMetadata(textEditor.metadata.Collaborator, config.COLLABORATOR) diff --git a/packages/account-client/src/client.ts b/packages/account-client/src/client.ts index d787b6173c..632f72a638 100644 --- a/packages/account-client/src/client.ts +++ b/packages/account-client/src/client.ts @@ -61,7 +61,7 @@ export interface AccountClient { kind?: 'external' | 'internal' | 'byregion', externalRegions?: string[] ) => Promise - validateOtp: (email: string, code: string) => Promise + validateOtp: (email: string, code: string, password?: string) => Promise loginOtp: (email: string) => Promise getLoginInfoByToken: () => Promise getLoginWithWorkspaceInfo: () => Promise @@ -98,6 +98,9 @@ export interface AccountClient { getRegionInfo: () => Promise createWorkspace: (name: string, region?: string) => Promise signUpOtp: (email: string, first: string, last: string) => Promise + /** + * Deprecated. Only to be used for dev setups without mail service. + */ signUp: (email: string, password: string, first: string, last: string) => Promise login: (email: string, password: string) => Promise getPerson: () => Promise @@ -283,10 +286,10 @@ class AccountClientImpl implements AccountClient { return await this.rpc(request) } - async validateOtp (email: string, code: string): Promise { + async validateOtp (email: string, code: string, password?: string): Promise { const request = { method: 'validateOtp' as const, - params: { email, code } + params: { email, code, password } } return await this.rpc(request) diff --git a/packages/presentation/src/plugin.ts b/packages/presentation/src/plugin.ts index b809a9e4aa..b9de0d3523 100644 --- a/packages/presentation/src/plugin.ts +++ b/packages/presentation/src/plugin.ts @@ -153,7 +153,8 @@ export default plugin(presentationId, { PreviewConfig: '' as Metadata, ClientHook: '' as Metadata, SessionId: '' as Metadata, - StatsUrl: '' as Metadata + StatsUrl: '' as Metadata, + MailUrl: '' as Metadata }, status: { FileTooLarge: '' as StatusCode diff --git a/plugins/login-assets/lang/cs.json b/plugins/login-assets/lang/cs.json index 96427f3a64..0a60153e39 100644 --- a/plugins/login-assets/lang/cs.json +++ b/plugins/login-assets/lang/cs.json @@ -70,6 +70,8 @@ "Hello": "Ahoj {name},", "ProcessingInvite": "Zpracovávám pozvánku, čekejte prosím...", "SignToProceed": "Přihlaste se, abyste mohli pokračovat", - "Proceed": "Pokračovat" + "Proceed": "Pokračovat", + "SetPasswordLater": "Nastavím heslo později", + "SetPasswordNow": "Nastavím heslo nyní" } } diff --git a/plugins/login-assets/lang/de.json b/plugins/login-assets/lang/de.json index f3df7e6097..48b2ec3106 100644 --- a/plugins/login-assets/lang/de.json +++ b/plugins/login-assets/lang/de.json @@ -70,6 +70,8 @@ "Hello": "Hallo {name},", "ProcessingInvite": "Einladung wird bearbeitet, bitte warten...", "SignToProceed": "Bitte melden Sie sich an, um fortzufahren", - "Proceed": "Fortfahren" + "Proceed": "Fortfahren", + "SetPasswordLater": "Ich werde später ein Passwort festlegen", + "SetPasswordNow": "Ich werde jetzt ein Passwort festlegen" } } diff --git a/plugins/login-assets/lang/en.json b/plugins/login-assets/lang/en.json index 6ce17ee1ba..069bdf4064 100644 --- a/plugins/login-assets/lang/en.json +++ b/plugins/login-assets/lang/en.json @@ -69,6 +69,8 @@ "Hello": "Hello {name},", "ProcessingInvite": "Processing invite, please wait...", "SignToProceed": "Please sign in to proceed", - "Proceed": "Proceed" + "Proceed": "Proceed", + "SetPasswordLater": "I'll set a password later", + "SetPasswordNow": "I'll set a password now" } } diff --git a/plugins/login-assets/lang/es.json b/plugins/login-assets/lang/es.json index 0375254ad9..b5502b64b9 100644 --- a/plugins/login-assets/lang/es.json +++ b/plugins/login-assets/lang/es.json @@ -69,6 +69,8 @@ "Hello": "Hola {name},", "ProcessingInvite": "Procesando invitación, por favor espere...", "SignToProceed": "Por favor inicie sesión para continuar", - "Proceed": "Continuar" + "Proceed": "Continuar", + "SetPasswordLater": "Estableceré una contraseña más tarde", + "SetPasswordNow": "Estableceré una contraseña ahora" } } diff --git a/plugins/login-assets/lang/fr.json b/plugins/login-assets/lang/fr.json index 4bf0743e2a..a14a343ac1 100644 --- a/plugins/login-assets/lang/fr.json +++ b/plugins/login-assets/lang/fr.json @@ -69,6 +69,8 @@ "Hello": "Bonjour {name},", "ProcessingInvite": "Invitation en cours, veuillez patienter...", "SignToProceed": "Veuillez vous connecter pour continuer", - "Proceed": "Continuer" + "Proceed": "Continuer", + "SetPasswordLater": "Je définirai un mot de passe plus tard", + "SetPasswordNow": "Je définirai un mot de passe maintenant" } } diff --git a/plugins/login-assets/lang/it.json b/plugins/login-assets/lang/it.json index 7cde3be55a..41b9433090 100644 --- a/plugins/login-assets/lang/it.json +++ b/plugins/login-assets/lang/it.json @@ -69,6 +69,8 @@ "Hello": "Ciao {name},", "ProcessingInvite": "Elaborazione invito, attendere prego...", "SignToProceed": "Accedi per procedere", - "Proceed": "Procedere" + "Proceed": "Procedere", + "SetPasswordLater": "Imposterò una password più tardi", + "SetPasswordNow": "Imposterò una password ora" } } diff --git a/plugins/login-assets/lang/ja.json b/plugins/login-assets/lang/ja.json index 05bc79b787..2a18aacee1 100644 --- a/plugins/login-assets/lang/ja.json +++ b/plugins/login-assets/lang/ja.json @@ -69,6 +69,8 @@ "Hello": "{name} さん、こんにちは", "ProcessingInvite": "招待を処理中です。しばらくお待ちください...", "SignToProceed": "続行するにはサインインしてください", - "Proceed": "続行" + "Proceed": "続行", + "SetPasswordLater": "後でパスワードを設定します", + "SetPasswordNow": "今すぐパスワードを設定します" } } diff --git a/plugins/login-assets/lang/pt.json b/plugins/login-assets/lang/pt.json index 63d7f966ca..ca73a122b9 100644 --- a/plugins/login-assets/lang/pt.json +++ b/plugins/login-assets/lang/pt.json @@ -69,6 +69,8 @@ "Hello": "Olá {name},", "ProcessingInvite": "Processando convite, aguarde...", "SignToProceed": "Por favor, inicie sessão para continuar", - "Proceed": "Continuar" + "Proceed": "Continuar", + "SetPasswordLater": "Vou definir uma senha mais tarde", + "SetPasswordNow": "Vou definir uma senha agora" } } diff --git a/plugins/login-assets/lang/ru.json b/plugins/login-assets/lang/ru.json index 2b36339512..ab550dea4b 100644 --- a/plugins/login-assets/lang/ru.json +++ b/plugins/login-assets/lang/ru.json @@ -69,6 +69,8 @@ "Hello": "Привет {name},", "ProcessingInvite": "Обработка приглашения, пожалуйста, подождите...", "SignToProceed": "Пожалуйста, войдите, чтобы продолжить", - "Proceed": "Продолжить" + "Proceed": "Продолжить", + "SetPasswordLater": "Я установлю пароль позже", + "SetPasswordNow": "Я установлю пароль сейчас" } } diff --git a/plugins/login-assets/lang/zh.json b/plugins/login-assets/lang/zh.json index 14f4434005..4bacace101 100644 --- a/plugins/login-assets/lang/zh.json +++ b/plugins/login-assets/lang/zh.json @@ -69,6 +69,8 @@ "Hello": "你好 {name},", "ProcessingInvite": "处理邀请,请稍候...", "SignToProceed": "请登录以继续", - "Proceed": "继续" + "Proceed": "继续", + "SetPasswordLater": "稍后设置密码", + "SetPasswordNow": "现在设置密码" } } diff --git a/plugins/login-resources/src/analytics.ts b/plugins/login-resources/src/analytics.ts index 7a04d43905..8f5c12d6bb 100644 --- a/plugins/login-resources/src/analytics.ts +++ b/plugins/login-resources/src/analytics.ts @@ -15,6 +15,7 @@ export const LoginEvents = { SignUpEmail: 'signup.viaEmail', + SignUpOtp: 'signup.viaOtp', SignUpGoogle: 'signup.viaGoogle', SignUpGithub: 'signup.viaGitHub', diff --git a/plugins/login-resources/src/components/LoginApp.svelte b/plugins/login-resources/src/components/LoginApp.svelte index 3d65785bca..dcf4473ff9 100644 --- a/plugins/login-resources/src/components/LoginApp.svelte +++ b/plugins/login-resources/src/components/LoginApp.svelte @@ -55,6 +55,7 @@ export let page: Pages = 'signup' const signUpDisabled = getMetadata(login.metadata.DisableSignUp) ?? false + const useOTP = getMetadata(presentation.metadata.MailUrl) != null && getMetadata(presentation.metadata.MailUrl) !== '' let navigateUrl: string | undefined onDestroy(location.subscribe(updatePageLoc)) @@ -149,9 +150,9 @@
{#if page === 'login'} - + {:else if page === 'signup'} - + {:else if page === 'createWorkspace'} {:else if page === 'password'} diff --git a/plugins/login-resources/src/components/LoginForm.svelte b/plugins/login-resources/src/components/LoginForm.svelte index 07a57b78eb..5dacdef980 100644 --- a/plugins/login-resources/src/components/LoginForm.svelte +++ b/plugins/login-resources/src/components/LoginForm.svelte @@ -25,12 +25,13 @@ export let navigateUrl: string | undefined = undefined export let signUpDisabled = false + export let useOTP = true export let email: string | undefined = undefined export let caption: IntlString | undefined = undefined export let subtitle: string | undefined = undefined export let onLogin: ((loginInfo: LoginInfo | null, status: Status) => void | Promise) | undefined = undefined - let method: LoginMethods = LoginMethods.Otp + let method: LoginMethods = useOTP ? LoginMethods.Otp : LoginMethods.Password function changeMethod (event: CustomEvent): void { method = event.detail diff --git a/plugins/login-resources/src/components/OtpForm.svelte b/plugins/login-resources/src/components/OtpForm.svelte index 42faab8fad..b1739fca84 100644 --- a/plugins/login-resources/src/components/OtpForm.svelte +++ b/plugins/login-resources/src/components/OtpForm.svelte @@ -21,7 +21,7 @@ import { LoginInfo } from '@hcengineering/account-client' import Tabs from './Tabs.svelte' - import { BottomAction, doLoginNavigate, validateOtpLogin, OtpLoginSteps, loginOtp } from '../index' + import { BottomAction, doLoginNavigate, doValidateOtp, OtpLoginSteps, loginOtp } from '../index' import login from '../plugin' import BottomActionComponent from './BottomAction.svelte' import StatusControl from './StatusControl.svelte' @@ -32,6 +32,7 @@ export let signUpDisabled = false export let loginState: 'login' | 'signup' | 'none' = 'none' export let canChangeEmail = true + export let password: string | undefined = undefined export let onLogin: ((loginInfo: LoginInfo | null, status: Status) => void | Promise) | undefined = undefined const dispatch = createEventDispatcher() @@ -66,7 +67,7 @@ status = new Status(Severity.INFO, login.status.ConnectingToServer, {}) const otp = otpData.otp1 + otpData.otp2 + otpData.otp3 + otpData.otp4 + otpData.otp5 + otpData.otp6 - const [loginStatus, result] = await validateOtpLogin(email, otp) + const [loginStatus, result] = await doValidateOtp(loginState === 'signup', email, otp, password) status = loginStatus if (onLogin !== undefined) { diff --git a/plugins/login-resources/src/components/SignupForm.svelte b/plugins/login-resources/src/components/SignupForm.svelte index 3adaf2e7dc..38e20f081e 100644 --- a/plugins/login-resources/src/components/SignupForm.svelte +++ b/plugins/login-resources/src/components/SignupForm.svelte @@ -15,23 +15,24 @@ -->