diff --git a/app/config/locale/templates/email-base.tpl b/app/config/locale/templates/email-base.tpl index a93fcc84e..bcbd9c1d2 100644 --- a/app/config/locale/templates/email-base.tpl +++ b/app/config/locale/templates/email-base.tpl @@ -4,7 +4,7 @@ - {{title}} + {{subject}} @@ -191,7 +136,16 @@ - +
{{content}} +

{{hello}}

+

{{body}}

+ {{redirect}} +


{{footer}}

+

{{thanks}} +
+ {{signature}} +

+
diff --git a/app/config/locale/templates/email-cta.tpl b/app/config/locale/templates/email-cta.tpl deleted file mode 100644 index 97103f610..000000000 --- a/app/config/locale/templates/email-cta.tpl +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - -

- - {{redirect}} - -

\ No newline at end of file diff --git a/app/config/locale/translations/en.json b/app/config/locale/translations/en.json index aaa558206..f042582c0 100644 --- a/app/config/locale/translations/en.json +++ b/app/config/locale/translations/en.json @@ -2,13 +2,29 @@ "settings.inspire": "\"The art of being wise is the art of knowing what to overlook.\"", "settings.locale": "en", "settings.direction": "ltr", - "account.emails.team": "%s Team", - "account.emails.verification.title": "Account Verification", - "account.emails.verification.body": "\n Hello {{name}},\n\n\n Follow this link to verify your email address.\n\n{{cta}}\n\n If you didn’t ask to verify this address, you can ignore this message.\n\n\n Thanks,\n {{project}} team\n", - "account.emails.recovery.title": "Password Reset", - "account.emails.recovery.body": "\n Hello {{name}},\n\n\n Follow this link to reset your {{project}} password.\n\n{{cta}}\n\n If you didn’t ask to reset your password, you can ignore this message.\n\n\n Thanks,\n {{project}} team\n\n", - "account.emails.invitation.title": "Invitation to %s Team at %s", - "account.emails.invitation.body": "\n Hello,\n\n\n This mail was sent to you because {{owner}} wanted to invite you to become a member of the {{team}} team at {{project}}.\n\n{{cta}}\n\n If you are not interested, you can ignore this message.\n\n Thanks,\n {{project}} team\n\n", + "emails.sender": "%s Team", + + "emails.verification.subject": "Account Verification", + "emails.verification.hello": "Hey {{name}}", + "emails.verification.body": "Follow this link to verify your email address.", + "emails.verification.footer": "If you didn’t ask to verify this address, you can ignore this message.", + "emails.verification.thanks": "Thanks", + "emails.verification.signature": "{{project}} team", + + "emails.recovery.subject": "Password Reset", + "emails.recovery.hello": "Hello {{name}}", + "emails.recovery.body": "Follow this link to reset your {{project}} password.", + "emails.recovery.footer": "If you didn’t ask to reset your password, you can ignore this message.", + "emails.recovery.thanks": "Thanks", + "emails.recovery.signature": "{{project}} team", + + "emails.invitation.subject": "Invitation to %s Team at %s", + "emails.invitation.hello": "Hello", + "emails.invitation.body": "This mail was sent to you because {{owner}} wanted to invite you to become a member of the {{team}} team at {{project}}.", + "emails.invitation.footer": "If you are not interested, you can ignore this message.", + "emails.invitation.thanks": "Thanks", + "emails.invitation.signature": "{{project}} team", + "locale.country.unknown": "Unknown", "countries.af": "Afghanistan", "countries.ao": "Angola", diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index aa84e8d67..c84f39b7b 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1515,32 +1515,16 @@ App::post('/v1/account/recovery') $url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['userId' => $profile->getId(), 'secret' => $secret, 'expire' => $expire]); $url = Template::unParseURL($url); - $body = Template::fromFile(__DIR__.'/../../config/locale/templates/email-base.tpl'); - $content = Template::fromString($locale->getText('account.emails.recovery.body')); - $cta = Template::fromFile(__DIR__.'/../../config/locale/templates/email-cta.tpl'); - - $body - ->setParam('{{content}}', $content->render(false)) - ->setParam('{{cta}}', $cta->render()) - ->setParam('{{title}}', $locale->getText('account.emails.recovery.title')) - ->setParam('{{direction}}', $locale->getText('settings.direction')) - ->setParam('{{project}}', $project->getAttribute('name', ['[APP-NAME]'])) - ->setParam('{{name}}', $profile->getAttribute('name')) - ->setParam('{{redirect}}', $url) - ->setParam('{{bg-body}}', '#f7f7f7') - ->setParam('{{bg-content}}', '#ffffff') - ->setParam('{{bg-cta}}', '#073b4c') - ->setParam('{{text-content}}', '#000000') - ->setParam('{{text-cta}}', '#ffffff') - ; - $mails ->setParam('event', 'account.recovery.create') - ->setParam('from', ($project->getId() === 'console') ? '' : \sprintf($locale->getText('account.emails.team'), $project->getAttribute('name'))) + ->setParam('from', ($project->getId() === 'console') ? '' : \sprintf($locale->getText('emails.sender'), $project->getAttribute('name'))) ->setParam('recipient', $profile->getAttribute('email', '')) ->setParam('name', $profile->getAttribute('name', '')) - ->setParam('subject', $locale->getText('account.emails.recovery.title')) - ->setParam('body', $body->render()) + ->setParam('subject', $locale->getText('emails.recovery.subject')) + ->setParam('url', $url) + ->setParam('locale', $locale->default) + ->setParam('project', $project->getAttribute('name', ['[APP-NAME]'])) + ->setParam('type', MAIL_TYPE_RECOVERY) ->trigger(); ; @@ -1719,32 +1703,16 @@ App::post('/v1/account/verification') $url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['userId' => $user->getId(), 'secret' => $verificationSecret, 'expire' => $expire]); $url = Template::unParseURL($url); - $body = Template::fromFile(__DIR__.'/../../config/locale/templates/email-base.tpl'); - $content = Template::fromString($locale->getText('account.emails.verification.body')); - $cta = Template::fromFile(__DIR__.'/../../config/locale/templates/email-cta.tpl'); - - $body - ->setParam('{{content}}', $content->render(false)) - ->setParam('{{cta}}', $cta->render()) - ->setParam('{{title}}', $locale->getText('account.emails.verification.title')) - ->setParam('{{direction}}', $locale->getText('settings.direction')) - ->setParam('{{project}}', $project->getAttribute('name', ['[APP-NAME]'])) - ->setParam('{{name}}', $user->getAttribute('name')) - ->setParam('{{redirect}}', $url) - ->setParam('{{bg-body}}', '#f7f7f7') - ->setParam('{{bg-content}}', '#ffffff') - ->setParam('{{bg-cta}}', '#073b4c') - ->setParam('{{text-content}}', '#000000') - ->setParam('{{text-cta}}', '#ffffff') - ; - $mails ->setParam('event', 'account.verification.create') - ->setParam('from', ($project->getId() === 'console') ? '' : \sprintf($locale->getText('account.emails.team'), $project->getAttribute('name'))) + ->setParam('from', ($project->getId() === 'console') ? '' : \sprintf($locale->getText('emails.sender'), $project->getAttribute('name'))) ->setParam('recipient', $user->getAttribute('email')) ->setParam('name', $user->getAttribute('name')) - ->setParam('subject', $locale->getText('account.emails.verification.title')) - ->setParam('body', $body->render()) + ->setParam('subject', $locale->getText('emails.verification.subject')) + ->setParam('url', $url) + ->setParam('locale', $locale->default) + ->setParam('project', $project->getAttribute('name', ['[APP-NAME]'])) + ->setParam('type', MAIL_TYPE_VERIFICATION) ->trigger() ; diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index e9c2f5684..49c434faf 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -418,36 +418,21 @@ App::post('/v1/teams/:teamId/memberships') $url = Template::parseURL($url); $url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['membershipId' => $membership->getId(), 'teamId' => $team->getId(), 'userId' => $invitee->getId(), 'secret' => $secret, 'teamId' => $teamId]); $url = Template::unParseURL($url); - - $body = Template::fromFile(__DIR__.'/../../config/locale/templates/email-base.tpl'); - $content = Template::fromString($locale->getText('account.emails.invitation.body')); - $cta = Template::fromFile(__DIR__.'/../../config/locale/templates/email-cta.tpl'); - $title = \sprintf($locale->getText('account.emails.invitation.title'), $team->getAttribute('name', '[TEAM-NAME]'), $project->getAttribute('name', ['[APP-NAME]'])); - - $body - ->setParam('{{content}}', $content->render(false)) - ->setParam('{{cta}}', $cta->render()) - ->setParam('{{title}}', $title) - ->setParam('{{direction}}', $locale->getText('settings.direction')) - ->setParam('{{project}}', $project->getAttribute('name', ['[APP-NAME]'])) - ->setParam('{{team}}', $team->getAttribute('name', '[TEAM-NAME]')) - ->setParam('{{owner}}', $user->getAttribute('name', '')) - ->setParam('{{redirect}}', $url) - ->setParam('{{bg-body}}', '#f7f7f7') - ->setParam('{{bg-content}}', '#ffffff') - ->setParam('{{bg-cta}}', '#073b4c') - ->setParam('{{text-content}}', '#000000') - ->setParam('{{text-cta}}', '#ffffff') - ; + $subject = \sprintf($locale->getText('emails.invitation.subject'), $team->getAttribute('name', '[TEAM-NAME]'), $project->getAttribute('name', ['[APP-NAME]'])); if (!$isPrivilegedUser && !$isAppUser) { // No need of confirmation when in admin or app mode $mails ->setParam('event', 'teams.memberships.create') - ->setParam('from', ($project->getId() === 'console') ? '' : \sprintf($locale->getText('account.emails.team'), $project->getAttribute('name'))) + ->setParam('from', ($project->getId() === 'console') ? '' : \sprintf($locale->getText('emails.sender'), $project->getAttribute('name'))) ->setParam('recipient', $email) ->setParam('name', $name) - ->setParam('subject', $title) - ->setParam('body', $body->render()) + ->setParam('subject', $subject) + ->setParam('url', $url) + ->setParam('locale', $locale->default) + ->setParam('project', $project->getAttribute('name', ['[APP-NAME]'])) + ->setParam('owner', $user->getAttribute('name', '')) + ->setParam('team', $team->getAttribute('name', '[TEAM-NAME]')) + ->setParam('type', MAIL_TYPE_INVITATION) ->trigger() ; } diff --git a/app/init.php b/app/init.php index 725fca5ef..f11bc2e27 100644 --- a/app/init.php +++ b/app/init.php @@ -70,6 +70,10 @@ const DELETE_TYPE_EXECUTIONS = 'executions'; const DELETE_TYPE_AUDIT = 'audit'; const DELETE_TYPE_ABUSE = 'abuse'; const DELETE_TYPE_CERTIFICATES = 'certificates'; +// Mail Types +const MAIL_TYPE_VERIFICATION = 'verification'; +const MAIL_TYPE_RECOVERY = 'recovery'; +const MAIL_TYPE_INVITATION = 'invitation'; // Auth Types const APP_AUTH_TYPE_SESSION = 'Session'; const APP_AUTH_TYPE_JWT = 'JWT'; diff --git a/app/workers/mails.php b/app/workers/mails.php index aa4fb8db8..e2e01e4a3 100644 --- a/app/workers/mails.php +++ b/app/workers/mails.php @@ -1,8 +1,10 @@ args['recipient']; $name = $this->args['name']; $subject = $this->args['subject']; - $body = $this->args['body']; + $url = $this->args['url']; + $project = $this->args['project']; + $locale = new Locale($this->args['locale']); + + $type = $this->args['type']; + $prefix = ''; + $body = Template::fromFile(__DIR__.'/../config/locale/templates/email-base.tpl'); + + switch($type) { + case MAIL_TYPE_RECOVERY: + $prefix = 'emails.recovery'; + break; + case MAIL_TYPE_INVITATION: + $prefix = 'emails.invitation'; + $body->setParam('{{owner}}', $this->args['owner']); + $body->setParam('{{team}}', $this->args['team']); + break; + case MAIL_TYPE_VERIFICATION: + $prefix = 'emails.verification'; + break; + default: + throw new Exception('Undefined Mail Type : ' . $type, 500); + } + + $body + ->setParam('{{subject}}', $subject) + ->setParam('{{hello}}', $locale->getText("$prefix.hello")) + ->setParam('{{name}}', $name) + ->setParam('{{body}}', $locale->getText("$prefix.body")) + ->setParam('{{redirect}}', $url) + ->setParam('{{footer}}', $locale->getText("$prefix.footer")) + ->setParam('{{thanks}}', $locale->getText("$prefix.thanks")) + ->setParam('{{signature}}', $locale->getText("$prefix.signature")) + ->setParam('{{project}}', $project) + ->setParam('{{direction}}', $locale->getText('settings.direction')) + ->setParam('{{bg-body}}', '#f7f7f7') + ->setParam('{{bg-content}}', '#ffffff') + ->setParam('{{text-content}}', '#000000') + ; + + $body = $body->render(); /** @var \PHPMailer\PHPMailer\PHPMailer $mail */ $mail = $register->get('smtp'); diff --git a/src/Appwrite/Template/Template.php b/src/Appwrite/Template/Template.php index 9308ee11a..425014e21 100644 --- a/src/Appwrite/Template/Template.php +++ b/src/Appwrite/Template/Template.php @@ -79,6 +79,8 @@ class Template extends View throw new Exception('"'.$this->path.'" template is not readable or not found'); } + // First replace the variables inside the params. Then replace the variables in the template + $this->params = array_merge($this->params, \str_replace(\array_keys($this->params), \array_values($this->params), $this->params)); $template = \str_replace(\array_keys($this->params), \array_values($this->params), $template); return $template;