From 29dbe99840f0076562ba7fb969d368bbf3329cd4 Mon Sep 17 00:00:00 2001 From: Hemachandar Date: Mon, 6 Oct 2025 19:58:01 +0530 Subject: [PATCH] simplify config & templates --- app/config/console.php | 41 +--- .../locale/templates/email-auth-styled.tpl | 225 ------------------ .../locale/templates/email-base-styled.tpl | 5 +- app/config/locale/templates/email-base.tpl | 15 ++ .../locale/templates/email-inner-base.tpl | 2 +- .../locale/templates/email-magic-url.tpl | 2 +- .../locale/templates/email-verification.tpl | 9 - app/config/locale/translations/en.json | 3 + app/controllers/api/account.php | 78 ++---- src/Appwrite/Platform/Workers/Mails.php | 1 + tests/e2e/Services/Account/AccountBase.php | 5 - 11 files changed, 40 insertions(+), 346 deletions(-) delete mode 100644 app/config/locale/templates/email-auth-styled.tpl delete mode 100644 app/config/locale/templates/email-verification.tpl diff --git a/app/config/console.php b/app/config/console.php index 6f44368060..70bb3523e6 100644 --- a/app/config/console.php +++ b/app/config/console.php @@ -9,8 +9,6 @@ use Appwrite\Network\Platform; use Utopia\Database\Helpers\ID; use Utopia\System\System; -$localeCodes = include __DIR__ . '/locale/codes.php'; - $console = [ '$id' => ID::custom('console'), '$sequence' => ID::custom('console'), @@ -51,44 +49,7 @@ $console = [ 'githubSecret' => System::getEnv('_APP_CONSOLE_GITHUB_SECRET', ''), 'githubAppid' => System::getEnv('_APP_CONSOLE_GITHUB_APP_ID', '') ], - 'templates' => [ - 'email.verification-en' => [ - 'subject' => 'Account Verification', - 'preview' => 'Verify your email to activate your {{project}} account.', - 'heading' => 'Verify your email to start using Appwrite Cloud', - 'hello' => 'Hello {{user}},', - 'body' => 'Thanks for signing up for Appwrite Cloud. Before you can get started, please verify your email address.', - 'footer' => 'If you didn’t create an account, you can ignore this email.', - 'buttonText' => 'Verify email', - 'thanks' => 'Thanks,', - "signature" => "{{project}} team", - ], - 'email.mfaChallenge-en' => [ - 'subject' => 'Verification Code for {{project}}', - 'preview' => 'Use code {{otp}} for two-step verification in {{project}}. Expires in 15 minutes.', - 'heading' => 'Complete two-step verification to use Appwrite Cloud', - 'hello' => 'Hello {{user}},', - 'body' => 'Enter the following code to confirm your two-step verification in {{b}}{{project}}{{/b}}. This code will expire in 15 minutes.', - 'thanks' => 'Thanks,', - "signature" => "{{project}} team", - ], - 'email.otpSession-en' => [ - 'subject' => 'OTP for {{project}} Login', - 'preview' => 'Use OTP {{otp}} to sign in to {{project}}. Expires in 15 minutes.', - 'heading' => 'Login with OTP to use Appwrite Cloud', - 'hello' => 'Hello {{user}},', - 'body' => 'Enter the following verification code when prompted to securely sign in to your {{b}}{{project}}{{/b}} account. This code will expire in 15 minutes.', - 'thanks' => 'Thanks,', - "signature" => "{{project}} team", - ], - ], - 'customEmails' => true, + 'smtpBaseTemplate' => 'email-base-styled', ]; -foreach ($localeCodes as $localeCode) { - $console['templates']['email.verification-' . $localeCode['code']] = $console['templates']['email.verification-en']; - $console['templates']['email.mfaChallenge-' . $localeCode['code']] = $console['templates']['email.mfaChallenge-en']; - $console['templates']['email.otpSession-' . $localeCode['code']] = $console['templates']['email.otpSession-en']; -} - return $console; diff --git a/app/config/locale/templates/email-auth-styled.tpl b/app/config/locale/templates/email-auth-styled.tpl deleted file mode 100644 index a826c62e95..0000000000 --- a/app/config/locale/templates/email-auth-styled.tpl +++ /dev/null @@ -1,225 +0,0 @@ - - - - - - - - - - -
- {{preview}} -
{{previewWhitespace}}
-
- -
- - - - -
- Appwrite logo -
- - - - - -
-

{{heading}}

-
- - - - - -
-{{body}} -
- - - - - -
- - - - - - - -
- - - - - -
- - - - - - -
Terms -
|
-
Privacy
-

- © {{year}} Appwrite | 251 Little Falls Drive, Wilmington 19808, - Delaware, United States -

-
- - \ No newline at end of file diff --git a/app/config/locale/templates/email-base-styled.tpl b/app/config/locale/templates/email-base-styled.tpl index 16036e792c..3f3ba8dd9c 100644 --- a/app/config/locale/templates/email-base-styled.tpl +++ b/app/config/locale/templates/email-base-styled.tpl @@ -147,6 +147,7 @@ Appwrite logo @@ -155,12 +156,12 @@
-

{{subject}}

+

{{heading}}

- +
{{body}} diff --git a/app/config/locale/templates/email-base.tpl b/app/config/locale/templates/email-base.tpl index 8c94c3f63e..5153b3e4fc 100644 --- a/app/config/locale/templates/email-base.tpl +++ b/app/config/locale/templates/email-base.tpl @@ -44,6 +44,21 @@ color: currentColor; word-break: break-all; } + a.button { + box-sizing: border-box; + display: inline-block; + text-align: center; + text-decoration: none; + padding: 9px 14px; + color: #ffffff; + background-color: #2D2D31; + border: 1px solid #414146; + border-radius: 8px; + } + a.button:hover, + a.button:focus { + opacity: 0.8; + } table { width: 100%; border-spacing: 0 !important; diff --git a/app/config/locale/templates/email-inner-base.tpl b/app/config/locale/templates/email-inner-base.tpl index 677f70ce7d..4b68f224db 100644 --- a/app/config/locale/templates/email-inner-base.tpl +++ b/app/config/locale/templates/email-inner-base.tpl @@ -1,6 +1,6 @@

{{hello}}

{{body}}

-

{{buttonText}}

+

{{buttonText}}

{{footer}}

{{thanks}} diff --git a/app/config/locale/templates/email-magic-url.tpl b/app/config/locale/templates/email-magic-url.tpl index 21988c5bc1..618993e0e9 100644 --- a/app/config/locale/templates/email-magic-url.tpl +++ b/app/config/locale/templates/email-magic-url.tpl @@ -5,7 +5,7 @@
- {{buttonText}} + {{buttonText}}
diff --git a/app/config/locale/templates/email-verification.tpl b/app/config/locale/templates/email-verification.tpl deleted file mode 100644 index 4b68f224db..0000000000 --- a/app/config/locale/templates/email-verification.tpl +++ /dev/null @@ -1,9 +0,0 @@ -

{{hello}}

-

{{body}}

-

{{buttonText}}

-

{{footer}}

-

- {{thanks}} -
- {{signature}} -

\ No newline at end of file diff --git a/app/config/locale/translations/en.json b/app/config/locale/translations/en.json index e2ee20b2d7..69328e61a7 100644 --- a/app/config/locale/translations/en.json +++ b/app/config/locale/translations/en.json @@ -5,6 +5,7 @@ "emails.sender": "{{project}} Team", "emails.verification.subject": "Account Verification", "emails.verification.preview": "Verify your email to activate your {{project}} account.", + "emails.verification.heading": "Verify your email to start using Appwrite Cloud", "emails.verification.hello": "Hello {{user}},", "emails.verification.body": "Follow this link to verify your email address to your {{b}}{{project}}{{/b}} account.", "emails.verification.footer": "If you didn’t ask to verify this address, you can ignore this message.", @@ -33,6 +34,7 @@ "emails.sessionAlert.signature": "{{project}} team", "emails.otpSession.subject": "OTP for {{project}} Login", "emails.otpSession.preview": "Use OTP {{otp}} to sign in to {{project}}. Expires in 15 minutes.", + "emails.otpSession.heading": "Login with OTP to use Appwrite Cloud", "emails.otpSession.hello": "Hello {{user}},", "emails.otpSession.description": "Enter the following verification code when prompted to securely sign in to your {{b}}{{project}}{{/b}} account. This code will expire in 15 minutes.", "emails.otpSession.clientInfo": "This sign in was requested using {{b}}{{agentClient}}{{/b}} on {{b}}{{agentDevice}}{{/b}} {{b}}{{agentOs}}{{/b}}. If you didn't request the sign in, you can safely ignore this email.", @@ -41,6 +43,7 @@ "emails.otpSession.signature": "{{project}} team", "emails.mfaChallenge.subject": "Verification Code for {{project}}", "emails.mfaChallenge.preview": "Use code {{otp}} for two-step verification in {{project}}. Expires in 15 minutes.", + "emails.mfaChallenge.heading": "Complete two-step verification to use Appwrite Cloud", "emails.mfaChallenge.hello": "Hello {{user}},", "emails.mfaChallenge.description": "Enter the following code to confirm your two-step verification in {{b}}{{project}}{{/b}}. This code will expire in 15 minutes.", "emails.mfaChallenge.clientInfo": "This verification code was requested using {{b}}{{agentClient}}{{/b}} on {{b}}{{agentDevice}}{{/b}} {{b}}{{agentOs}}{{/b}}. If you didn't request the verification code, you can safely ignore this email.", diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 3aa9678a72..e98376dfc7 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -2296,11 +2296,11 @@ App::post('/v1/account/tokens/email') $subject = $locale->getText("emails.otpSession.subject"); $preview = $locale->getText("emails.otpSession.preview"); - $customTemplate = $project->getAttribute('templates', [])['email.otpSession-' . $locale->default] ?? []; + $heading = $locale->getText("emails.otpSession.heading"); - $customEmails = $project->getAttribute('customEmails', false); - $bodyTemplate = ''; - $heading = ''; + $customTemplate = $project->getAttribute('templates', [])['email.otpSession-' . $locale->default] ?? []; + $smtpBaseTemplate = $project->getAttribute('smtpBaseTemplate', 'email-base'); + $bodyTemplate = __DIR__ . '/../../config/locale/templates/' . $smtpBaseTemplate . '.tpl'; $detector = new Detector($request->getUserAgent('UNKNOWN')); $agentOs = $detector->getOS(); @@ -2369,23 +2369,6 @@ App::post('/v1/account/tokens/email') ->setSmtpReplyTo($replyTo) ->setSmtpSenderEmail($senderEmail) ->setSmtpSenderName($senderName); - } elseif ($customEmails && !empty($customTemplate)) { - $subject = $customTemplate['subject']; - $preview = $customTemplate['preview']; - $heading = $customTemplate['heading']; - - $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-otp.tpl'); - $message - ->setParam('{{hello}}', $customTemplate['hello']) - ->setParam('{{description}}', $customTemplate['body'], escapeHtml: false) - ->setParam('{{thanks}}', $customTemplate['thanks']) - ->setParam('{{signature}}', $customTemplate['signature']) - ->setParam('{{clientInfo}}', '') - ->setParam('{{securityPhrase}}', '') - ->setParam('{{securityPhraseDividerDisplay}}', 'none'); - - $body = $message->render(); - $bodyTemplate = __DIR__ . '/../../config/locale/templates/email-auth-styled.tpl'; } $emailVariables = [ @@ -2402,7 +2385,7 @@ App::post('/v1/account/tokens/email') 'team' => '', ]; - if ($customEmails && !empty($customTemplate)) { + if ($smtpBaseTemplate === 'email-base-styled') { $emailVariables = array_merge($emailVariables, [ 'heading' => $heading, 'accentColor' => APP_EMAIL_ACCENT_COLOR, @@ -3624,7 +3607,11 @@ App::post('/v1/account/verification') $body = $locale->getText("emails.verification.body"); $preview = $locale->getText("emails.verification.preview"); $subject = $locale->getText("emails.verification.subject"); + $heading = $locale->getText("emails.verification.heading"); + $customTemplate = $project->getAttribute('templates', [])['email.verification-' . $locale->default] ?? []; + $smtpBaseTemplate = $project->getAttribute('smtpBaseTemplate', 'email-base'); + $bodyTemplate = __DIR__ . '/../../config/locale/templates/' . $smtpBaseTemplate . '.tpl'; $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl'); $message @@ -3644,10 +3631,6 @@ App::post('/v1/account/verification') $senderName = System::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server'); $replyTo = ""; - $customEmails = $project->getAttribute('customEmails', false); - $bodyTemplate = ''; - $heading = ''; - if ($smtpEnabled) { if (!empty($smtp['senderEmail'])) { $senderEmail = $smtp['senderEmail']; @@ -3685,22 +3668,6 @@ App::post('/v1/account/verification') ->setSmtpReplyTo($replyTo) ->setSmtpSenderEmail($senderEmail) ->setSmtpSenderName($senderName); - } elseif ($customEmails && !empty($customTemplate)) { - $subject = $customTemplate['subject']; - $preview = $customTemplate['preview']; - $heading = $customTemplate['heading']; - - $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-verification.tpl'); - $message - ->setParam('{{hello}}', $customTemplate['hello']) - ->setParam('{{body}}', $customTemplate['body'], escapeHtml: false) - ->setParam('{{buttonText}}', $customTemplate['buttonText']) - ->setParam('{{footer}}', $customTemplate['footer']) - ->setParam('{{thanks}}', $customTemplate['thanks']) - ->setParam('{{signature}}', $customTemplate['signature']); - - $body = $message->render(); - $bodyTemplate = __DIR__ . '/../../config/locale/templates/email-auth-styled.tpl'; } $emailVariables = [ @@ -3713,7 +3680,7 @@ App::post('/v1/account/verification') 'team' => '', ]; - if ($customEmails && !empty($customTemplate)) { + if ($smtpBaseTemplate === 'email-base-styled') { $emailVariables = array_merge($emailVariables, [ 'heading' => $heading, 'accentColor' => APP_EMAIL_ACCENT_COLOR, @@ -4736,7 +4703,11 @@ App::post('/v1/account/mfa/challenge') $subject = $locale->getText("emails.mfaChallenge.subject"); $preview = $locale->getText("emails.mfaChallenge.preview"); + $heading = $locale->getText("emails.mfaChallenge.heading"); + $customTemplate = $project->getAttribute('templates', [])['email.mfaChallenge-' . $locale->default] ?? []; + $smtpBaseTemplate = $project->getAttribute('smtpBaseTemplate', 'email-base'); + $bodyTemplate = __DIR__ . '/../../config/locale/templates/' . $smtpBaseTemplate . '.tpl'; $detector = new Detector($request->getUserAgent('UNKNOWN')); $agentOs = $detector->getOS(); @@ -4760,10 +4731,6 @@ App::post('/v1/account/mfa/challenge') $senderName = System::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server'); $replyTo = ""; - $customEmails = $project->getAttribute('customEmails', false); - $bodyTemplate = ''; - $heading = ''; - if ($smtpEnabled) { if (!empty($smtp['senderEmail'])) { $senderEmail = $smtp['senderEmail']; @@ -4801,21 +4768,6 @@ App::post('/v1/account/mfa/challenge') ->setSmtpReplyTo($replyTo) ->setSmtpSenderEmail($senderEmail) ->setSmtpSenderName($senderName); - } elseif ($customEmails && !empty($customTemplate)) { - $subject = $customTemplate['subject']; - $preview = $customTemplate['preview']; - $heading = $customTemplate['heading']; - - $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-mfa-challenge.tpl'); - $message - ->setParam('{{hello}}', $customTemplate['hello']) - ->setParam('{{description}}', $customTemplate['body'], escapeHtml: false) - ->setParam('{{thanks}}', $customTemplate['thanks']) - ->setParam('{{signature}}', $customTemplate['signature']) - ->setParam('{{clientInfo}}', ''); - - $body = $message->render(); - $bodyTemplate = __DIR__ . '/../../config/locale/templates/email-auth-styled.tpl'; } $emailVariables = [ @@ -4829,7 +4781,7 @@ App::post('/v1/account/mfa/challenge') 'agentOs' => $agentOs['osName'] ?? 'UNKNOWN', ]; - if ($customEmails && !empty($customTemplate)) { + if ($smtpBaseTemplate === 'email-base-styled') { $emailVariables = array_merge($emailVariables, [ 'heading' => $heading, 'accentColor' => APP_EMAIL_ACCENT_COLOR, diff --git a/src/Appwrite/Platform/Workers/Mails.php b/src/Appwrite/Platform/Workers/Mails.php index 117b689863..efca484ebf 100644 --- a/src/Appwrite/Platform/Workers/Mails.php +++ b/src/Appwrite/Platform/Workers/Mails.php @@ -82,6 +82,7 @@ class Mails extends Action $preview = $payload['preview'] ?? ''; $variables['subject'] = $subject; + $variables['heading'] = $variables['heading'] ?? $subject; $variables['year'] = date("Y"); $attachment = $payload['attachment'] ?? []; diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index 46283e8f86..b2f85637a8 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -192,11 +192,6 @@ trait AccountBase $this->assertStringNotContainsStringIgnoringCase('Appwrite logo', $lastEmail['html']); } - // TODO: Remove this once OTP login is supported for Console. - if ($isConsoleProject) { - return; - } - $response = $this->client->call(Client::METHOD_POST, '/account/sessions/token', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json',