From fcc7a56f4af2354ebaebfa3758a508983e756d16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sat, 18 Apr 2026 11:01:26 +0200 Subject: [PATCH] Fix list endpoint --- .../Http/Project/Templates/Email/XList.php | 81 ++++++++++++++++--- 1 file changed, 71 insertions(+), 10 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Project/Http/Project/Templates/Email/XList.php b/src/Appwrite/Platform/Modules/Project/Http/Project/Templates/Email/XList.php index 9fdd576af1..0128a18e25 100644 --- a/src/Appwrite/Platform/Modules/Project/Http/Project/Templates/Email/XList.php +++ b/src/Appwrite/Platform/Modules/Project/Http/Project/Templates/Email/XList.php @@ -6,6 +6,7 @@ use Appwrite\Extend\Exception; use Appwrite\SDK\AuthType; use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; +use Appwrite\Template\Template; use Appwrite\Utopia\Database\InMemoryQuery; use Appwrite\Utopia\Database\Validator\Queries\ProjectTemplates; use Appwrite\Utopia\Response; @@ -13,8 +14,10 @@ use Utopia\Config\Config; use Utopia\Database\Document; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; +use Utopia\Locale\Locale; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; +use Utopia\System\System; use Utopia\Validator\Boolean; class XList extends Action @@ -85,16 +88,74 @@ class XList extends Action $key = 'email.' . $type . '-' . $locale; $stored = $projectTemplates[$key] ?? null; - $templates[] = new Document([ - 'type' => $type, - 'locale' => $locale, - 'message' => $stored['message'] ?? '', - 'subject' => $stored['subject'] ?? '', - 'senderName' => $stored['senderName'] ?? '', - 'senderEmail' => $stored['senderEmail'] ?? '', - 'replyTo' => $stored['replyTo'] ?? '', - 'custom' => !\is_null($stored), - ]); + $localeObj = new Locale($locale); + $localeObj->setFallback(System::getEnv('_APP_LOCALE', 'en')); + + if (is_null($stored)) { + /** + * different templates, different placeholders. + */ + $templateConfigs = [ + 'magicSession' => [ + 'file' => 'email-magic-url.tpl', + 'placeholders' => ['optionButton', 'buttonText', 'optionUrl', 'clientInfo', 'securityPhrase'] + ], + 'mfaChallenge' => [ + 'file' => 'email-mfa-challenge.tpl', + 'placeholders' => ['description', 'clientInfo'] + ], + 'otpSession' => [ + 'file' => 'email-otp.tpl', + 'placeholders' => ['description', 'clientInfo', 'securityPhrase'] + ], + 'sessionAlert' => [ + 'file' => 'email-session-alert.tpl', + 'placeholders' => ['body', 'listDevice', 'listIpAddress', 'listCountry', 'footer'] + ], + ]; + + // fallback to the base template. + $config = $templateConfigs[$type] ?? [ + 'file' => 'email-inner-base.tpl', + 'placeholders' => ['buttonText', 'body', 'footer'] + ]; + + $templateString = file_get_contents(APP_CE_CONFIG_DIR . '/locale/templates/' . $config['file']); + + // We use `fromString` due to the replace above + $message = Template::fromString($templateString); + + // Set type-specific parameters + foreach ($config['placeholders'] as $param) { + $escapeHtml = !in_array($param, ['clientInfo', 'body', 'footer', 'description']); + $message->setParam("{{{$param}}}", $localeObj->getText("emails.{$type}.{$param}"), escapeHtml: $escapeHtml); + } + + $message + // common placeholders on all the templates + ->setParam('{{hello}}', $localeObj->getText("emails.{$type}.hello")) + ->setParam('{{thanks}}', $localeObj->getText("emails.{$type}.thanks")) + ->setParam('{{signature}}', $localeObj->getText("emails.{$type}.signature")); + + // `useContent: false` will strip new lines! + $message = $message->render(useContent: true); + + $template = [ + 'message' => $message, + 'subject' => $localeObj->getText('emails.' . $type . '.subject'), + 'senderEmail' => '', + 'senderName' => '', + 'custom' => false, + ]; + } else { + $template = $stored; + $template['custom'] = true; + } + + $template['type'] = $type; + $template['locale'] = $locale; + + $templates[] = new Document($template); } }