mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
527 lines
18 KiB
PHP
527 lines
18 KiB
PHP
<?php
|
|
|
|
namespace Tests\E2E\Services\Project;
|
|
|
|
use Tests\E2E\Client;
|
|
|
|
trait TemplatesBase
|
|
{
|
|
// =========================================================================
|
|
// Get email template tests
|
|
// =========================================================================
|
|
|
|
public function testGetEmailTemplateDefault(): void
|
|
{
|
|
$template = $this->getEmailTemplate('verification', 'en');
|
|
|
|
$this->assertSame(200, $template['headers']['status-code']);
|
|
$this->assertSame('verification', $template['body']['templateId']);
|
|
$this->assertSame('en', $template['body']['locale']);
|
|
$this->assertFalse($template['body']['custom']);
|
|
$this->assertNotEmpty($template['body']['subject']);
|
|
$this->assertNotEmpty($template['body']['message']);
|
|
}
|
|
|
|
public function testGetEmailTemplateDefaultLocale(): void
|
|
{
|
|
$template = $this->getEmailTemplate('verification');
|
|
|
|
$this->assertSame(200, $template['headers']['status-code']);
|
|
$this->assertSame('verification', $template['body']['templateId']);
|
|
$this->assertSame('en', $template['body']['locale']);
|
|
$this->assertFalse($template['body']['custom']);
|
|
}
|
|
|
|
public function testGetEmailTemplateCustom(): void
|
|
{
|
|
$update = $this->updateEmailTemplate('magicSession', 'en', 'Magic Subject', 'Magic Body');
|
|
$this->assertSame(200, $update['headers']['status-code']);
|
|
|
|
$get = $this->getEmailTemplate('magicSession', 'en');
|
|
|
|
$this->assertSame(200, $get['headers']['status-code']);
|
|
$this->assertSame('magicSession', $get['body']['templateId']);
|
|
$this->assertSame('en', $get['body']['locale']);
|
|
$this->assertTrue($get['body']['custom']);
|
|
$this->assertSame('Magic Subject', $get['body']['subject']);
|
|
$this->assertSame('Magic Body', $get['body']['message']);
|
|
|
|
// Cleanup
|
|
$this->deleteEmailTemplate('magicSession', 'en');
|
|
}
|
|
|
|
public function testGetEmailTemplateInvalidType(): void
|
|
{
|
|
$template = $this->getEmailTemplate('notATemplate', 'en');
|
|
|
|
$this->assertSame(400, $template['headers']['status-code']);
|
|
}
|
|
|
|
public function testGetEmailTemplateInvalidLocale(): void
|
|
{
|
|
$template = $this->getEmailTemplate('verification', 'not-a-locale');
|
|
|
|
$this->assertSame(400, $template['headers']['status-code']);
|
|
}
|
|
|
|
public function testGetEmailTemplateWithoutAuthentication(): void
|
|
{
|
|
$template = $this->getEmailTemplate('verification', 'en', false);
|
|
|
|
$this->assertSame(401, $template['headers']['status-code']);
|
|
}
|
|
|
|
// =========================================================================
|
|
// Update email template tests
|
|
// =========================================================================
|
|
|
|
public function testUpdateEmailTemplate(): void
|
|
{
|
|
$update = $this->updateEmailTemplate(
|
|
'verification',
|
|
'en',
|
|
'Please verify your email',
|
|
'Click here to verify: {{url}}',
|
|
);
|
|
|
|
$this->assertSame(200, $update['headers']['status-code']);
|
|
$this->assertSame('verification', $update['body']['templateId']);
|
|
$this->assertSame('en', $update['body']['locale']);
|
|
$this->assertSame('Please verify your email', $update['body']['subject']);
|
|
$this->assertSame('Click here to verify: {{url}}', $update['body']['message']);
|
|
$this->assertTrue($update['body']['custom']);
|
|
|
|
// Verify persisted via GET
|
|
$get = $this->getEmailTemplate('verification', 'en');
|
|
$this->assertSame(200, $get['headers']['status-code']);
|
|
$this->assertSame('Please verify your email', $get['body']['subject']);
|
|
$this->assertSame('Click here to verify: {{url}}', $get['body']['message']);
|
|
$this->assertTrue($get['body']['custom']);
|
|
|
|
// Cleanup
|
|
$this->deleteEmailTemplate('verification', 'en');
|
|
}
|
|
|
|
public function testUpdateEmailTemplateWithOptionalFields(): void
|
|
{
|
|
$update = $this->updateEmailTemplate(
|
|
'invitation',
|
|
'en',
|
|
'Team invitation',
|
|
'You have been invited',
|
|
'Appwrite Team',
|
|
'team@appwrite.io',
|
|
'reply@appwrite.io',
|
|
);
|
|
|
|
$this->assertSame(200, $update['headers']['status-code']);
|
|
$this->assertSame('Team invitation', $update['body']['subject']);
|
|
$this->assertSame('You have been invited', $update['body']['message']);
|
|
$this->assertSame('Appwrite Team', $update['body']['senderName']);
|
|
$this->assertSame('team@appwrite.io', $update['body']['senderEmail']);
|
|
$this->assertSame('reply@appwrite.io', $update['body']['replyTo']);
|
|
|
|
// Cleanup
|
|
$this->deleteEmailTemplate('invitation', 'en');
|
|
}
|
|
|
|
public function testUpdateEmailTemplateDefaultLocale(): void
|
|
{
|
|
$update = $this->updateEmailTemplate(
|
|
'sessionAlert',
|
|
null,
|
|
'Session alert',
|
|
'Someone signed in',
|
|
);
|
|
|
|
$this->assertSame(200, $update['headers']['status-code']);
|
|
$this->assertSame('sessionAlert', $update['body']['templateId']);
|
|
$this->assertSame('en', $update['body']['locale']);
|
|
|
|
// Cleanup
|
|
$this->deleteEmailTemplate('sessionAlert', 'en');
|
|
}
|
|
|
|
public function testUpdateEmailTemplateOverwrite(): void
|
|
{
|
|
$this->updateEmailTemplate('otpSession', 'en', 'First', 'First body');
|
|
|
|
$second = $this->updateEmailTemplate('otpSession', 'en', 'Second', 'Second body');
|
|
|
|
$this->assertSame(200, $second['headers']['status-code']);
|
|
$this->assertSame('Second', $second['body']['subject']);
|
|
$this->assertSame('Second body', $second['body']['message']);
|
|
|
|
$get = $this->getEmailTemplate('otpSession', 'en');
|
|
$this->assertSame('Second', $get['body']['subject']);
|
|
|
|
// Cleanup
|
|
$this->deleteEmailTemplate('otpSession', 'en');
|
|
}
|
|
|
|
public function testUpdateEmailTemplateInvalidType(): void
|
|
{
|
|
$update = $this->updateEmailTemplate('notATemplate', 'en', 'Subject', 'Message');
|
|
|
|
$this->assertSame(400, $update['headers']['status-code']);
|
|
}
|
|
|
|
public function testUpdateEmailTemplateMissingSubject(): void
|
|
{
|
|
$update = $this->updateEmailTemplate('verification', 'en', null, 'Message only');
|
|
|
|
$this->assertSame(400, $update['headers']['status-code']);
|
|
}
|
|
|
|
public function testUpdateEmailTemplateMissingMessage(): void
|
|
{
|
|
$update = $this->updateEmailTemplate('verification', 'en', 'Subject only', null);
|
|
|
|
$this->assertSame(400, $update['headers']['status-code']);
|
|
}
|
|
|
|
public function testUpdateEmailTemplateInvalidSenderEmail(): void
|
|
{
|
|
$update = $this->updateEmailTemplate(
|
|
'verification',
|
|
'en',
|
|
'Subject',
|
|
'Message',
|
|
'Sender',
|
|
'not-an-email',
|
|
);
|
|
|
|
$this->assertSame(400, $update['headers']['status-code']);
|
|
}
|
|
|
|
public function testUpdateEmailTemplateInvalidReplyTo(): void
|
|
{
|
|
$update = $this->updateEmailTemplate(
|
|
'verification',
|
|
'en',
|
|
'Subject',
|
|
'Message',
|
|
null,
|
|
null,
|
|
'not-an-email',
|
|
);
|
|
|
|
$this->assertSame(400, $update['headers']['status-code']);
|
|
}
|
|
|
|
public function testUpdateEmailTemplateWithoutAuthentication(): void
|
|
{
|
|
$update = $this->updateEmailTemplate(
|
|
'verification',
|
|
'en',
|
|
'Subject',
|
|
'Message',
|
|
null,
|
|
null,
|
|
null,
|
|
false,
|
|
);
|
|
|
|
$this->assertSame(401, $update['headers']['status-code']);
|
|
}
|
|
|
|
// =========================================================================
|
|
// Delete email template tests
|
|
// =========================================================================
|
|
|
|
public function testDeleteEmailTemplate(): void
|
|
{
|
|
$update = $this->updateEmailTemplate('mfaChallenge', 'en', 'MFA', 'Enter code');
|
|
$this->assertSame(200, $update['headers']['status-code']);
|
|
|
|
$customBefore = $this->getEmailTemplate('mfaChallenge', 'en');
|
|
$this->assertTrue($customBefore['body']['custom']);
|
|
|
|
$delete = $this->deleteEmailTemplate('mfaChallenge', 'en');
|
|
$this->assertSame(204, $delete['headers']['status-code']);
|
|
$this->assertEmpty($delete['body']);
|
|
|
|
// Verify reset back to default
|
|
$after = $this->getEmailTemplate('mfaChallenge', 'en');
|
|
$this->assertSame(200, $after['headers']['status-code']);
|
|
$this->assertFalse($after['body']['custom']);
|
|
$this->assertNotSame('MFA', $after['body']['subject']);
|
|
}
|
|
|
|
public function testDeleteEmailTemplateDefault(): void
|
|
{
|
|
// Attempt to delete a template that was never customized
|
|
$delete = $this->deleteEmailTemplate('verification', 'fr');
|
|
|
|
$this->assertSame(401, $delete['headers']['status-code']);
|
|
$this->assertSame('project_template_default_deletion', $delete['body']['type']);
|
|
}
|
|
|
|
public function testDeleteEmailTemplateInvalidType(): void
|
|
{
|
|
$delete = $this->deleteEmailTemplate('notATemplate', 'en');
|
|
|
|
$this->assertSame(400, $delete['headers']['status-code']);
|
|
}
|
|
|
|
public function testDeleteEmailTemplateWithoutAuthentication(): void
|
|
{
|
|
$update = $this->updateEmailTemplate('recovery', 'en', 'Recovery', 'Reset password');
|
|
$this->assertSame(200, $update['headers']['status-code']);
|
|
|
|
$delete = $this->deleteEmailTemplate('recovery', 'en', false);
|
|
|
|
$this->assertSame(401, $delete['headers']['status-code']);
|
|
|
|
// Verify still customized
|
|
$get = $this->getEmailTemplate('recovery', 'en');
|
|
$this->assertTrue($get['body']['custom']);
|
|
|
|
// Cleanup
|
|
$this->deleteEmailTemplate('recovery', 'en');
|
|
}
|
|
|
|
// =========================================================================
|
|
// Legacy response format tests (request + response filters)
|
|
// =========================================================================
|
|
|
|
public function testGetEmailTemplateLegacyResponseFormat(): void
|
|
{
|
|
$headers = \array_merge([
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
'x-appwrite-response-format' => '1.9.1',
|
|
], $this->getHeaders());
|
|
|
|
$template = $this->client->call(
|
|
Client::METHOD_GET,
|
|
'/project/templates/email/verification',
|
|
$headers,
|
|
);
|
|
|
|
$this->assertSame(200, $template['headers']['status-code']);
|
|
// Response filter should rename templateId -> type for < 1.9.2 clients.
|
|
$this->assertArrayHasKey('type', $template['body']);
|
|
$this->assertArrayNotHasKey('templateId', $template['body']);
|
|
$this->assertSame('verification', $template['body']['type']);
|
|
$this->assertSame('en', $template['body']['locale']);
|
|
}
|
|
|
|
public function testUpdateEmailTemplateLegacyResponseFormat(): void
|
|
{
|
|
$headers = \array_merge([
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
'x-appwrite-response-format' => '1.9.1',
|
|
], $this->getHeaders());
|
|
|
|
// Request filter should accept legacy `type` and map it to `templateId`.
|
|
$update = $this->client->call(
|
|
Client::METHOD_PATCH,
|
|
'/project/templates/email',
|
|
$headers,
|
|
[
|
|
'type' => 'magicSession',
|
|
'locale' => 'en',
|
|
'subject' => 'Legacy Subject',
|
|
'message' => 'Legacy Body',
|
|
],
|
|
);
|
|
|
|
$this->assertSame(200, $update['headers']['status-code']);
|
|
// Response filter should rename templateId -> type for < 1.9.2 clients.
|
|
$this->assertArrayHasKey('type', $update['body']);
|
|
$this->assertArrayNotHasKey('templateId', $update['body']);
|
|
$this->assertSame('magicSession', $update['body']['type']);
|
|
$this->assertSame('Legacy Subject', $update['body']['subject']);
|
|
$this->assertSame('Legacy Body', $update['body']['message']);
|
|
$this->assertTrue($update['body']['custom']);
|
|
|
|
// Verify persisted, then cleanup via legacy DELETE with `type`.
|
|
$get = $this->getEmailTemplate('magicSession', 'en');
|
|
$this->assertSame(200, $get['headers']['status-code']);
|
|
$this->assertTrue($get['body']['custom']);
|
|
|
|
$delete = $this->client->call(
|
|
Client::METHOD_DELETE,
|
|
'/project/templates/email',
|
|
$headers,
|
|
[
|
|
'type' => 'magicSession',
|
|
'locale' => 'en',
|
|
],
|
|
);
|
|
$this->assertSame(204, $delete['headers']['status-code']);
|
|
|
|
$after = $this->getEmailTemplate('magicSession', 'en');
|
|
$this->assertFalse($after['body']['custom']);
|
|
}
|
|
|
|
public function testDeleteEmailTemplateLegacyResponseFormat(): void
|
|
{
|
|
// Seed a custom template using the current API.
|
|
$update = $this->updateEmailTemplate('otpSession', 'en', 'Legacy OTP', 'Legacy OTP body');
|
|
$this->assertSame(200, $update['headers']['status-code']);
|
|
|
|
$headers = \array_merge([
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
'x-appwrite-response-format' => '1.9.1',
|
|
], $this->getHeaders());
|
|
|
|
// Request filter should accept legacy `type` and map it to `templateId`.
|
|
$delete = $this->client->call(
|
|
Client::METHOD_DELETE,
|
|
'/project/templates/email',
|
|
$headers,
|
|
[
|
|
'type' => 'otpSession',
|
|
'locale' => 'en',
|
|
],
|
|
);
|
|
|
|
$this->assertSame(204, $delete['headers']['status-code']);
|
|
$this->assertEmpty($delete['body']);
|
|
|
|
// Verify reset back to default.
|
|
$after = $this->getEmailTemplate('otpSession', 'en');
|
|
$this->assertSame(200, $after['headers']['status-code']);
|
|
$this->assertFalse($after['body']['custom']);
|
|
$this->assertNotSame('Legacy OTP', $after['body']['subject']);
|
|
}
|
|
|
|
public function testDeleteEmailTemplateLegacyInvalidType(): void
|
|
{
|
|
$headers = \array_merge([
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
'x-appwrite-response-format' => '1.9.1',
|
|
], $this->getHeaders());
|
|
|
|
$delete = $this->client->call(
|
|
Client::METHOD_DELETE,
|
|
'/project/templates/email',
|
|
$headers,
|
|
[
|
|
'type' => 'notATemplate',
|
|
'locale' => 'en',
|
|
],
|
|
);
|
|
|
|
$this->assertSame(400, $delete['headers']['status-code']);
|
|
}
|
|
|
|
public function testUpdateEmailTemplateLegacyInvalidType(): void
|
|
{
|
|
$headers = \array_merge([
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
'x-appwrite-response-format' => '1.9.1',
|
|
], $this->getHeaders());
|
|
|
|
$update = $this->client->call(
|
|
Client::METHOD_PATCH,
|
|
'/project/templates/email',
|
|
$headers,
|
|
[
|
|
'type' => 'notATemplate',
|
|
'locale' => 'en',
|
|
'subject' => 'Subject',
|
|
'message' => 'Message',
|
|
],
|
|
);
|
|
|
|
$this->assertSame(400, $update['headers']['status-code']);
|
|
}
|
|
|
|
// =========================================================================
|
|
// Helpers
|
|
// =========================================================================
|
|
|
|
protected function getEmailTemplate(string $type, ?string $locale = null, bool $authenticated = true): mixed
|
|
{
|
|
$headers = [
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
];
|
|
|
|
if ($authenticated) {
|
|
$headers = \array_merge($headers, $this->getHeaders());
|
|
}
|
|
|
|
$params = [];
|
|
if ($locale !== null) {
|
|
$params['locale'] = $locale;
|
|
}
|
|
|
|
return $this->client->call(Client::METHOD_GET, '/project/templates/email/' . $type, $headers, $params);
|
|
}
|
|
|
|
protected function updateEmailTemplate(
|
|
string $type,
|
|
?string $locale,
|
|
?string $subject,
|
|
?string $message,
|
|
?string $senderName = null,
|
|
?string $senderEmail = null,
|
|
?string $replyTo = null,
|
|
bool $authenticated = true,
|
|
): mixed {
|
|
$params = [
|
|
'templateId' => $type,
|
|
];
|
|
|
|
if ($locale !== null) {
|
|
$params['locale'] = $locale;
|
|
}
|
|
if ($subject !== null) {
|
|
$params['subject'] = $subject;
|
|
}
|
|
if ($message !== null) {
|
|
$params['message'] = $message;
|
|
}
|
|
if ($senderName !== null) {
|
|
$params['senderName'] = $senderName;
|
|
}
|
|
if ($senderEmail !== null) {
|
|
$params['senderEmail'] = $senderEmail;
|
|
}
|
|
if ($replyTo !== null) {
|
|
$params['replyTo'] = $replyTo;
|
|
}
|
|
|
|
$headers = [
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
];
|
|
|
|
if ($authenticated) {
|
|
$headers = \array_merge($headers, $this->getHeaders());
|
|
}
|
|
|
|
return $this->client->call(Client::METHOD_PATCH, '/project/templates/email', $headers, $params);
|
|
}
|
|
|
|
protected function deleteEmailTemplate(string $type, ?string $locale = null, bool $authenticated = true): mixed
|
|
{
|
|
$params = [
|
|
'templateId' => $type,
|
|
];
|
|
|
|
if ($locale !== null) {
|
|
$params['locale'] = $locale;
|
|
}
|
|
|
|
$headers = [
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
];
|
|
|
|
if ($authenticated) {
|
|
$headers = \array_merge($headers, $this->getHeaders());
|
|
}
|
|
|
|
return $this->client->call(Client::METHOD_DELETE, '/project/templates/email', $headers, $params);
|
|
}
|
|
}
|