refactor: move email template defaults to console module and add tests

- Move GetDefault endpoint to Console module as Get.php
  (GET /v1/console/templates/email/:templateId, console.getEmailTemplate)
- Remove from Project module
- Add e2e tests for console.getEmailTemplate and reset=true
This commit is contained in:
harsh mahajan
2026-05-15 18:03:12 +05:30
parent 0e157efabe
commit a614afe5c7
4 changed files with 146 additions and 10 deletions
@@ -1,6 +1,6 @@
<?php
namespace Appwrite\Platform\Modules\Project\Http\Project\Templates\Email;
namespace Appwrite\Platform\Modules\Console\Http\Templates\Email;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
@@ -15,28 +15,28 @@ use Utopia\Platform\Scope\HTTP;
use Utopia\System\System;
use Utopia\Validator\WhiteList;
class GetDefault extends Action
class Get extends Action
{
use HTTP;
public static function getName()
public static function getName(): string
{
return 'getDefaultProjectEmailTemplate';
return 'getConsoleEmailTemplate';
}
public function __construct()
{
$this->setHttpMethod(Action::HTTP_REQUEST_METHOD_GET)
->setHttpPath('/v1/console/templates/email/:templateId')
->desc('Get default project email template')
->groups(['api', 'project'])
->label('scope', 'templates.read')
->desc('Get email template')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk', new Method(
namespace: 'console',
group: 'templates',
name: 'getEmailTemplate',
description: <<<EOT
Get the Appwrite built-in default email template for the specified type and locale. Always returns the unmodified default, ignoring any custom overrides.
Get the Appwrite built-in default email template for the specified type and locale. Always returns the unmodified default, ignoring any custom project overrides.
EOT,
auth: [AuthType::ADMIN, AuthType::KEY],
responses: [
@@ -17,6 +17,7 @@ use Appwrite\Platform\Modules\Console\Http\Redirects\Root\Get as RedirectRoot;
use Appwrite\Platform\Modules\Console\Http\Resources\Get as GetResourceAvailability;
use Appwrite\Platform\Modules\Console\Http\Scopes\Organization\XList as ListOrganizationScopes;
use Appwrite\Platform\Modules\Console\Http\Scopes\Project\XList as ListKeyScopes;
use Appwrite\Platform\Modules\Console\Http\Templates\Email\Get as GetEmailTemplate;
use Appwrite\Platform\Modules\Console\Http\Variables\Get as GetVariables;
use Utopia\Platform\Service;
@@ -31,6 +32,7 @@ class Http extends Service
$this->addAction(Web::getName(), new Web());
$this->addAction(GetVariables::getName(), new GetVariables());
$this->addAction(GetEmailTemplate::getName(), new GetEmailTemplate());
$this->addAction(ListOAuth2Providers::getName(), new ListOAuth2Providers());
$this->addAction(ListKeyScopes::getName(), new ListKeyScopes());
$this->addAction(ListOrganizationScopes::getName(), new ListOrganizationScopes());
@@ -91,7 +91,6 @@ use Appwrite\Platform\Modules\Project\Http\Project\Services\Update as UpdateProj
use Appwrite\Platform\Modules\Project\Http\Project\SMTP\Tests\Create as CreateSMTPTest;
use Appwrite\Platform\Modules\Project\Http\Project\SMTP\Update as UpdateSMTP;
use Appwrite\Platform\Modules\Project\Http\Project\Templates\Email\Get as GetTemplate;
use Appwrite\Platform\Modules\Project\Http\Project\Templates\Email\GetDefault as DefaultTemplate;
use Appwrite\Platform\Modules\Project\Http\Project\Templates\Email\Update as UpdateTemplate;
use Appwrite\Platform\Modules\Project\Http\Project\Templates\Email\XList as ListTemplates;
use Appwrite\Platform\Modules\Project\Http\Project\Variables\Create as CreateVariable;
@@ -125,7 +124,6 @@ class Http extends Service
$this->addAction(ListTemplates::getName(), new ListTemplates());
$this->addAction(GetTemplate::getName(), new GetTemplate());
$this->addAction(UpdateTemplate::getName(), new UpdateTemplate());
$this->addAction(DefaultTemplate::getName(), new DefaultTemplate());
// Variables
$this->addAction(CreateVariable::getName(), new CreateVariable());
@@ -1147,6 +1147,142 @@ trait TemplatesBase
return $this->client->call(Client::METHOD_PATCH, '/project/templates/email', $headers, $params);
}
// Console email template (default) tests
public function testGetConsoleEmailTemplate(): void
{
$response = $this->getConsoleEmailTemplate('verification', 'en');
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame('verification', $response['body']['templateId']);
$this->assertSame('en', $response['body']['locale']);
$this->assertNotEmpty($response['body']['subject']);
$this->assertNotEmpty($response['body']['message']);
$this->assertSame('', $response['body']['senderName']);
$this->assertSame('', $response['body']['senderEmail']);
$this->assertSame('', $response['body']['replyToEmail']);
$this->assertSame('', $response['body']['replyToName']);
}
public function testGetConsoleEmailTemplateIgnoresCustomOverride(): void
{
$this->ensureSMTPEnabled();
// Set a custom override on the project template.
$this->updateEmailTemplate(
templateId: 'recovery',
locale: 'en',
subject: 'Custom subject',
message: 'Custom message',
senderName: 'Custom Sender',
senderEmail: 'custom@appwrite.io',
);
// Console endpoint must always return the built-in default, not the override.
$response = $this->getConsoleEmailTemplate('recovery', 'en');
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame('recovery', $response['body']['templateId']);
$this->assertNotSame('Custom subject', $response['body']['subject']);
$this->assertSame('', $response['body']['senderName']);
$this->assertSame('', $response['body']['senderEmail']);
}
public function testGetConsoleEmailTemplateDefaultLocale(): void
{
$response = $this->getConsoleEmailTemplate('magicSession');
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame('en', $response['body']['locale']);
$this->assertNotEmpty($response['body']['subject']);
}
public function testGetConsoleEmailTemplateAllTypes(): void
{
$types = [
'verification',
'magicSession',
'recovery',
'invitation',
'mfaChallenge',
'sessionAlert',
'otpSession',
];
foreach ($types as $type) {
$response = $this->getConsoleEmailTemplate($type, 'en');
$this->assertSame(200, $response['headers']['status-code'], "type={$type}");
$this->assertNotEmpty($response['body']['subject'], "type={$type} must have subject");
$this->assertNotEmpty($response['body']['message'], "type={$type} must have message");
}
}
public function testResetEmailTemplate(): void
{
$this->ensureSMTPEnabled();
// Apply a custom override.
$this->updateEmailTemplate(
templateId: 'invitation',
locale: 'en',
subject: 'Custom invite subject',
message: 'Custom invite message',
senderName: 'Bad Sender',
senderEmail: 'bad@example.com',
);
$custom = $this->getEmailTemplate('invitation', 'en');
$this->assertSame('Custom invite subject', $custom['body']['subject']);
$this->assertSame('Bad Sender', $custom['body']['senderName']);
// Reset to default.
$response = $this->resetEmailTemplate('invitation', 'en');
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame('', $response['body']['senderName']);
$this->assertSame('', $response['body']['senderEmail']);
$this->assertNotSame('Custom invite subject', $response['body']['subject']);
// Confirm the project template now reflects the default.
$after = $this->getEmailTemplate('invitation', 'en');
$this->assertSame('', $after['body']['senderName']);
$this->assertSame('', $after['body']['senderEmail']);
}
public function testResetEmailTemplateWithoutSMTP(): void
{
// Reset must work even without SMTP enabled.
$response = $this->resetEmailTemplate('recovery', 'en');
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame('', $response['body']['senderName']);
$this->assertSame('', $response['body']['senderEmail']);
}
protected function getConsoleEmailTemplate(string $templateId, ?string $locale = null): mixed
{
$params = [];
if ($locale !== null) {
$params['locale'] = $locale;
}
return $this->client->call(Client::METHOD_GET, '/console/templates/email/' . $templateId, \array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), $params);
}
protected function resetEmailTemplate(string $templateId, ?string $locale = null): mixed
{
$params = ['templateId' => $templateId, 'reset' => true];
if ($locale !== null) {
$params['locale'] = $locale;
}
return $this->client->call(Client::METHOD_PATCH, '/project/templates/email', \array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), $params);
}
protected function ensureSMTPEnabled(): void
{
$this->client->call(