From 74490d65944098c564331a10b7e863d5430bce68 Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sat, 1 Feb 2020 09:52:08 +0100 Subject: [PATCH 01/22] Cleanup enotify email - Removing unused fields - Move notify template to email subdirectory --- include/enotify.php | 14 ++------------ .../notify_html.tpl} | 0 .../notify_text.tpl} | 0 3 files changed, 2 insertions(+), 12 deletions(-) rename view/templates/{email_notify_html.tpl => email/notify_html.tpl} (100%) rename view/templates/{email_notify_text.tpl => email/notify_text.tpl} (100%) diff --git a/include/enotify.php b/include/enotify.php index e21adc91ac..b90f96d5aa 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -548,7 +548,6 @@ function notification($params) $datarray['source_link'] = $params['source_link'] ?? ''; $datarray['source_photo'] = $params['source_photo'] ?? ''; $datarray['uid'] = $params['uid']; - $datarray['username'] = $params['to_name'] ?? ''; $datarray['hsitelink'] = $hsitelink; $datarray['tsitelink'] = $tsitelink; $datarray['hitemlink'] = '' . $itemlink . ''; @@ -568,7 +567,7 @@ function notification($params) $content_allowed = ((!DI::config()->get('system', 'enotify_no_content')) || ($params['type'] == SYSTEM_EMAIL)); // load the template for private message notifications - $tpl = Renderer::getMarkupTemplate('email_notify_html.tpl'); + $tpl = Renderer::getMarkupTemplate('email/notify_html.tpl'); $email_html_body = Renderer::replaceMacros($tpl, [ '$banner' => $datarray['banner'], '$product' => $datarray['product'], @@ -578,7 +577,6 @@ function notification($params) '$source_name' => $datarray['source_name'], '$source_link' => $datarray['source_link'], '$source_photo' => $datarray['source_photo'], - '$username' => $datarray['username'], '$hsitelink' => $datarray['hsitelink'], '$hitemlink' => $datarray['hitemlink'], '$thanks' => $datarray['thanks'], @@ -589,17 +587,9 @@ function notification($params) ]); // load the template for private message notifications - $tpl = Renderer::getMarkupTemplate('email_notify_text.tpl'); + $tpl = Renderer::getMarkupTemplate('email/notify_text.tpl'); $email_text_body = Renderer::replaceMacros($tpl, [ - '$banner' => $datarray['banner'], - '$product' => $datarray['product'], '$preamble' => $datarray['preamble'], - '$sitename' => $datarray['sitename'], - '$siteurl' => $datarray['siteurl'], - '$source_name' => $datarray['source_name'], - '$source_link' => $datarray['source_link'], - '$source_photo' => $datarray['source_photo'], - '$username' => $datarray['username'], '$tsitelink' => $datarray['tsitelink'], '$titemlink' => $datarray['titemlink'], '$thanks' => $datarray['thanks'], diff --git a/view/templates/email_notify_html.tpl b/view/templates/email/notify_html.tpl similarity index 100% rename from view/templates/email_notify_html.tpl rename to view/templates/email/notify_html.tpl diff --git a/view/templates/email_notify_text.tpl b/view/templates/email/notify_text.tpl similarity index 100% rename from view/templates/email_notify_text.tpl rename to view/templates/email/notify_text.tpl From 3291728059f2016dc57b6b4b2fa6305e93de601c Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sat, 1 Feb 2020 20:08:54 +0100 Subject: [PATCH 02/22] Extract System emails from enotify - Removed every SYSTEM_EMAIL occurrence in enotify - Introduced a "SystemMailBuilder" for build system emails - Replaced every SYSTEM_EMAIL usage in the classes with calling this builder - Added tests for this new Builder - Split the email templates between "base" template for email and concrete usages for different use cases --- boot.php | 2 - include/enotify.php | 50 +---- mod/lostpass.php | 34 ++-- mod/removeme.php | 21 +- src/Core/Update.php | 36 ++-- src/Model/User.php | 30 ++- src/Module/Admin/Users.php | 16 +- src/Object/EMail/IEmail.php | 1 + src/Util/EMailer/MailBuilder.php | 186 ++++++++++++++++++ src/Util/EMailer/SystemMailBuilder.php | 110 +++++++++++ src/Util/Emailer.php | 14 ++ tests/Util/SampleMailBuilder.php | 57 ++++++ tests/src/Util/Emailer/MailBuilderTest.php | 176 +++++++++++++++++ view/templates/email/html.tpl | 22 +++ .../email/{ => notify}/notify_html.tpl | 0 .../email/{ => notify}/notify_text.tpl | 0 view/templates/email/system/html.tpl | 3 + view/templates/email/system/text.tpl | 7 + 18 files changed, 647 insertions(+), 118 deletions(-) create mode 100644 src/Util/EMailer/MailBuilder.php create mode 100644 src/Util/EMailer/SystemMailBuilder.php create mode 100644 tests/Util/SampleMailBuilder.php create mode 100644 tests/src/Util/Emailer/MailBuilderTest.php create mode 100644 view/templates/email/html.tpl rename view/templates/email/{ => notify}/notify_html.tpl (100%) rename view/templates/email/{ => notify}/notify_text.tpl (100%) create mode 100644 view/templates/email/system/html.tpl create mode 100644 view/templates/email/system/text.tpl diff --git a/boot.php b/boot.php index 2bcbb4ebdd..3852c3279a 100644 --- a/boot.php +++ b/boot.php @@ -152,8 +152,6 @@ define('NOTIFY_TAGSHARE', 256); define('NOTIFY_POKE', 512); define('NOTIFY_SHARE', 1024); -define('SYSTEM_EMAIL', 16384); - define('NOTIFY_SYSTEM', 32768); /* @}*/ diff --git a/include/enotify.php b/include/enotify.php index b90f96d5aa..54bf482341 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -74,18 +74,14 @@ function notification($params) $sender_email = $a->getSenderEmailAddress(); - if ($params['type'] != SYSTEM_EMAIL) { - $user = DBA::selectFirst('user', ['nickname', 'page-flags'], - ['uid' => $params['uid']]); + $user = DBA::selectFirst('user', ['nickname', 'page-flags'], + ['uid' => $params['uid']]); - // There is no need to create notifications for forum accounts - if (!DBA::isResult($user) || in_array($user["page-flags"], [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP])) { - return false; - } - $nickname = $user["nickname"]; - } else { - $nickname = ''; + // There is no need to create notifications for forum accounts + if (!DBA::isResult($user) || in_array($user["page-flags"], [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP])) { + return false; } + $nickname = $user["nickname"]; // with $params['show_in_notification_page'] == false, the notification isn't inserted into // the database, and an email is sent if applicable. @@ -428,30 +424,6 @@ function notification($params) } } - if ($params['type'] == SYSTEM_EMAIL) { - // not part of the notifications. - // it just send a mail to the user. - // It will be used by the system to send emails to users (like - // password reset, invitations and so) using one look (but without - // add a notification to the user, with could be inexistent) - if (!isset($params['subject'])) { - Logger::warning('subject isn\'t set.', ['type' => $params['type']]); - } - $subject = $params['subject'] ?? ''; - - if (!isset($params['preamble'])) { - Logger::warning('preamble isn\'t set.', ['type' => $params['type'], 'subject' => $subject]); - } - $preamble = $params['preamble'] ?? ''; - - if (!isset($params['body'])) { - Logger::warning('body isn\'t set.', ['type' => $params['type'], 'subject' => $subject, 'preamble' => $preamble]); - } - $body = $params['body'] ?? ''; - - $show_in_notification_page = false; - } - $subject .= " (".$nickname."@".$hostname.")"; $h = [ @@ -506,8 +478,7 @@ function notification($params) // send email notification if notification preferences permit if ((intval($params['notify_flags']) & intval($params['type'])) - || $params['type'] == NOTIFY_SYSTEM - || $params['type'] == SYSTEM_EMAIL) { + || $params['type'] == NOTIFY_SYSTEM) { Logger::log('sending notification email'); @@ -563,11 +534,10 @@ function notification($params) Hook::callAll('enotify_mail', $datarray); // check whether sending post content in email notifications is allowed - // always true for SYSTEM_EMAIL - $content_allowed = ((!DI::config()->get('system', 'enotify_no_content')) || ($params['type'] == SYSTEM_EMAIL)); + $content_allowed = (!DI::config()->get('system', 'enotify_no_content')); // load the template for private message notifications - $tpl = Renderer::getMarkupTemplate('email/notify_html.tpl'); + $tpl = Renderer::getMarkupTemplate('email/notify/html.tpl'); $email_html_body = Renderer::replaceMacros($tpl, [ '$banner' => $datarray['banner'], '$product' => $datarray['product'], @@ -587,7 +557,7 @@ function notification($params) ]); // load the template for private message notifications - $tpl = Renderer::getMarkupTemplate('email/notify_text.tpl'); + $tpl = Renderer::getMarkupTemplate('email/notify/text.tpl'); $email_text_body = Renderer::replaceMacros($tpl, [ '$preamble' => $datarray['preamble'], '$tsitelink' => $datarray['tsitelink'], diff --git a/mod/lostpass.php b/mod/lostpass.php index 59426a1af8..d125cab5fb 100644 --- a/mod/lostpass.php +++ b/mod/lostpass.php @@ -64,17 +64,14 @@ function lostpass_post(App $a) Site Location: %2$s Login Name: %3$s', $resetlink, DI::baseUrl(), $user['nickname'])); - notification([ - 'type' => SYSTEM_EMAIL, - 'language' => $user['language'], - 'to_name' => $user['username'], - 'to_email' => $user['email'], - 'uid' => $user['uid'], - 'subject' => DI::l10n()->t('Password reset requested at %s', $sitename), - 'preamble' => $preamble, - 'body' => $body - ]); + $email = DI::emailer() + ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) + ->withMessage(DI::l10n()->t('Password reset requested at %s', $sitename), $preamble, $body) + ->forUser($user['uid'] ?? 0) + ->withRecipient($user['to_email']) + ->build(); + DI::emailer()->send($email); DI::baseUrl()->redirect(); } @@ -159,16 +156,13 @@ function lostpass_generate_password($user) You may change that password from your account settings page after logging in. ', DI::baseUrl(), $user['nickname'], $new_password)); - notification([ - 'type' => SYSTEM_EMAIL, - 'language' => $user['language'], - 'to_name' => $user['username'], - 'to_email' => $user['email'], - 'uid' => $user['uid'], - 'subject' => DI::l10n()->t('Your password has been changed at %s', $sitename), - 'preamble' => $preamble, - 'body' => $body - ]); + $email = DI::emailer() + ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) + ->withMessage(DI::l10n()->t('Your password has been changed at %s', $sitename), $preamble, $body) + ->forUser($user['uid'] ?? 0) + ->withRecipient($user['to_email']) + ->build(); + DI::emailer()->send($email); } return $o; diff --git a/mod/removeme.php b/mod/removeme.php index 48d4e0e0fe..86d1f04e34 100644 --- a/mod/removeme.php +++ b/mod/removeme.php @@ -40,17 +40,16 @@ function removeme_post(App $a) if (!DBA::isResult($admin)) { continue; } - notification([ - 'type' => SYSTEM_EMAIL, - 'subject' => DI::l10n()->t('[Friendica System Notify]') . ' ' . DI::l10n()->t('User deleted their account'), - 'preamble' => DI::l10n()->t('On your Friendica node an user deleted their account. Please ensure that their data is removed from the backups.'), - 'body' => DI::l10n()->t('The user id is %d', local_user()), - 'to_email' => $admin['email'], - 'to_name' => $admin['username'], - 'uid' => $admin['uid'], - 'language' => $admin['language'] ? $admin['language'] : 'en', - 'show_in_notification_page' => false - ]); + + $email = DI::emailer() + ->newSystemMail((!empty($admin['language'])) ? DI::l10n()->withLang($admin['language']) : DI::l10n()->withLang('en')) + ->withMessage(DI::l10n()->t('[Friendica System Notify]') . ' ' . DI::l10n()->t('User deleted their account'), + DI::l10n()->t('On your Friendica node an user deleted their account. Please ensure that their data is removed from the backups.'), + DI::l10n()->t('The user id is %d', local_user())) + ->forUser($admin['uid'] ?? 0) + ->withRecipient($admin['email']) + ->build(); + DI::emailer()->send($email); } if (User::getIdFromPasswordAuthentication($a->user, trim($_POST['qxz_password']))) { diff --git a/src/Core/Update.php b/src/Core/Update.php index 5a151b8380..2a3b3a68d6 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -252,7 +252,7 @@ class Update } $sent[] = $admin['email']; - $lang = (($admin['language'])?$admin['language']:'en'); + $lang = (($admin['language']) ? $admin['language'] : 'en'); $l10n = DI::l10n()->withLang($lang); $preamble = Strings::deindent($l10n->t(" @@ -261,17 +261,15 @@ class Update This needs to be fixed soon and I can't do it alone. Please contact a friendica developer if you can not help me on your own. My database might be invalid.", $update_id)); - $body = $l10n->t("The error message is\n[pre]%s[/pre]", $error_message); + $body = $l10n->t("The error message is\n[pre]%s[/pre]", $error_message); - notification([ - 'uid' => $admin['uid'], - 'type' => SYSTEM_EMAIL, - 'to_email' => $admin['email'], - 'subject' => $l10n->t('[Friendica Notify] Database update'), - 'preamble' => $preamble, - 'body' => $body, - 'language' => $lang] - ); + $email = DI::emailer() + ->newSystemMail($l10n) + ->withMessage($l10n->t('[Friendica Notify] Database update'), $preamble, $body) + ->forUser($admin['uid'] ?? 0) + ->withRecipient($admin['email']) + ->build(); + DI::emailer()->send($email); } //try the logger @@ -301,15 +299,13 @@ class Update The friendica database was successfully updated from %s to %s.", $from_build, $to_build)); - notification([ - 'uid' => $admin['uid'], - 'type' => SYSTEM_EMAIL, - 'to_email' => $admin['email'], - 'subject' => DI::l10n()->t('[Friendica Notify] Database update'), - 'preamble' => $preamble, - 'body' => $preamble, - 'language' => $lang] - ); + $email = DI::emailer() + ->newSystemMail($l10n) + ->withMessage($l10n->t('[Friendica Notify] Database update'), $preamble) + ->forUser($admin['uid'] ?? 0) + ->withRecipient($admin['email']) + ->build(); + DI::emailer()->send($email); } } diff --git a/src/Model/User.php b/src/Model/User.php index fd7238819d..cc6b96ae58 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -897,13 +897,13 @@ class User $password )); - return notification([ - 'type' => SYSTEM_EMAIL, - 'uid' => $user['uid'], - 'to_email' => $user['email'], - 'subject' => DI::l10n()->t('Registration at %s', $sitename), - 'body' => $body - ]); + $email = DI::emailer() + ->newSystemMail(DI::l10n()) + ->withMessage(DI::l10n()->t('Registration at %s', $sitename), $body) + ->forUser($user['uid'] ?? 0) + ->withRecipient($user['email']) + ->build(); + return DI::emailer()->send($email); } /** @@ -965,15 +965,13 @@ class User $password )); - return notification([ - 'uid' => $user['uid'], - 'language' => $user['language'], - 'type' => SYSTEM_EMAIL, - 'to_email' => $user['email'], - 'subject' => DI::l10n()->t('Registration details for %s', $sitename), - 'preamble' => $preamble, - 'body' => $body - ]); + $email = DI::emailer() + ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) + ->withMessage(DI::l10n()->t('Registration details for %s', $sitename), $preamble, $body) + ->forUser($user['uid'] ?? 0) + ->withRecipient($user['email']) + ->build(); + return DI::emailer()->send($email); } /** diff --git a/src/Module/Admin/Users.php b/src/Module/Admin/Users.php index 0498a80da1..5ca50d11ac 100644 --- a/src/Module/Admin/Users.php +++ b/src/Module/Admin/Users.php @@ -76,15 +76,13 @@ class Users extends BaseAdmin $preamble = sprintf($preamble, $user['username'], DI::config()->get('config', 'sitename')); $body = sprintf($body, DI::baseUrl()->get(), $user['nickname'], $result['password'], DI::config()->get('config', 'sitename')); - notification([ - 'type' => SYSTEM_EMAIL, - 'language' => $user['language'], - 'to_name' => $user['username'], - 'to_email' => $user['email'], - 'uid' => $user['uid'], - 'subject' => DI::l10n()->t('Registration details for %s', DI::config()->get('config', 'sitename')), - 'preamble' => $preamble, - 'body' => $body]); + $email = DI::emailer() + ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) + ->withMessage(DI::l10n()->t('Registration details for %s', DI::config()->get('config', 'sitename')), $preamble, $body) + ->forUser($user['uid'] ?? 0) + ->withRecipient($user['email']) + ->build(); + return DI::emailer()->send($email); } if (!empty($_POST['page_users_block'])) { diff --git a/src/Object/EMail/IEmail.php b/src/Object/EMail/IEmail.php index ec8ae88158..220cddc42f 100644 --- a/src/Object/EMail/IEmail.php +++ b/src/Object/EMail/IEmail.php @@ -2,6 +2,7 @@ namespace Friendica\Object\EMail; +use Friendica\Core\L10n; use Friendica\Util\Emailer; use JsonSerializable; diff --git a/src/Util/EMailer/MailBuilder.php b/src/Util/EMailer/MailBuilder.php new file mode 100644 index 0000000000..419edfc36d --- /dev/null +++ b/src/Util/EMailer/MailBuilder.php @@ -0,0 +1,186 @@ +l10n = $l10n; + $this->baseUrl = $baseUrl; + $this->config = $config; + + $hostname = $baseUrl->getHostname(); + if (strpos($hostname, ':')) { + $hostname = substr($hostname, 0, strpos($hostname, ':')); + } + + $this->headers = ""; + $this->headers .= "Precedence: list\n"; + $this->headers .= "X-Friendica-Host: " . $hostname . "\n"; + $this->headers .= "X-Friendica-Platform: " . FRIENDICA_PLATFORM . "\n"; + $this->headers .= "X-Friendica-Version: " . FRIENDICA_VERSION . "\n"; + $this->headers .= "List-ID: \n"; + $this->headers .= "List-Archive: <" . $baseUrl->get() . "/notifications/system>\n"; + } + + /** + * Gets the subject of the concrete builder, which inherits this base class + * + * @return string + */ + abstract protected function getSubject(); + + /** + * Gets the HTML version of the body of the concrete builder, which inherits this base class + * + * @return string + */ + abstract protected function getHtmlMessage(); + + /** + * Gets the Plaintext version of the body of the concrete builder, which inherits this base class + * + * @return string + */ + abstract protected function getPlaintextMessage(); + + /** + * Adds the User ID to the email in case the mail sending needs additional properties of this user + * + * @param int $uid The User ID + * + * @return static + */ + public function forUser(int $uid) + { + $this->recipientUid = $uid; + + return $this; + } + + /** + * Adds the sender to the email (if not called/set, the sender will get loaded with the help of the user id) + * + * @param string $name The name of the sender + * @param string $address The (email) address of the sender + * @param string|null $noReply Optional "no-reply" (email) address (if not set, it's the same as the address) + * + * @return static + */ + public function withSender(string $name, string $address, string $noReply = null) + { + $this->senderName = $name; + $this->senderAddress = $address; + $this->senderNoReply = $noReply ?? $this->senderNoReply; + + return $this; + } + + /** + * Adds a recipient to the email + * + * @param string $address The (email) address of the recipient + * + * @return static + */ + public function withRecipient(string $address) + { + $this->recipientAddress = $address; + + return $this; + } + + /** + * Build a email based on the given attributes + * + * @param bool $raw True, if the email shouldn't get extended by the default email-template + * + * @return IEmail A new generated email + * + * @throws InternalServerErrorException + * @throws Exception + */ + public function build(bool $raw = false) + { + if (empty($this->recipientAddress)) { + throw new InternalServerErrorException('Recipient address is missing.'); + } + + if ((empty($this->senderName) || empty($this->senderAddress)) && + !empty($this->recipientUid)) { + $user = User::getById($this->recipientUid, ['username', 'email']); + + if (!empty($user)) { + $this->senderName = $user['username']; + $this->senderAddress = $user['email']; + } + } + + if (empty($this->senderAddress) || empty($this->senderName)) { + throw new InternalServerErrorException('Sender address or name is missing.'); + } + + $this->senderNoReply = $this->senderNoReply ?? $this->senderAddress; + + $msgHtml = $this->getHtmlMessage() ?? ''; + + if (!$raw) { + // load the template for private message notifications + $tpl = Renderer::getMarkupTemplate('email/notify/html.tpl'); + $msgHtml = Renderer::replaceMacros($tpl, [ + '$banner' => $this->l10n->t('Friendica Notification'), + '$product' => FRIENDICA_PLATFORM, + '$htmlversion' => $msgHtml, + '$sitename' => $this->config->get('config', 'sitename'), + '$siteurl' => $this->baseUrl->get(true), + ]); + } + + return new Email( + $this->senderName, + $this->senderAddress, + $this->senderNoReply, + $this->recipientAddress, + $this->getSubject() ?? '', + $msgHtml, + $this->getPlaintextMessage() ?? '', + $this->headers, + $this->recipientUid ?? null); + } +} diff --git a/src/Util/EMailer/SystemMailBuilder.php b/src/Util/EMailer/SystemMailBuilder.php new file mode 100644 index 0000000000..56ae620ec9 --- /dev/null +++ b/src/Util/EMailer/SystemMailBuilder.php @@ -0,0 +1,110 @@ +config->get('config', 'sitename'); + + if ($this->config->get('config', 'admin_name')) { + $this->siteAdmin = $l10n->t('%1$s, %2$s Administrator', $this->config->get('config', 'admin_name'), $siteName); + } else { + $this->siteAdmin = $l10n->t('%s Administrator', $siteName); + } + } + + /** + * Adds a message + * + * @param string $subject The subject of the email + * @param string $preamble The preamble of the email + * @param string|null $body The body of the email (if not set, the preamble will get used as body) + * + * @return static + */ + public function withMessage(string $subject, string $preamble, string $body = null) + { + if (!isset($body)) { + $body = $preamble; + } + + $this->subject = $subject; + $this->preamble = $preamble; + $this->body = $body; + + return $this; + } + + /** + * {@inheritDoc} + */ + protected function getSubject() + { + return $this->subject; + } + + /** + * {@inheritDoc} + * + * @throws InternalServerErrorException + * @throws Exception + */ + protected function getHtmlMessage() + { + $htmlVersion = BBCode::convert($this->body); + + // load the template for private message notifications + $tpl = Renderer::getMarkupTemplate('email/system/html.tpl'); + return Renderer::replaceMacros($tpl, [ + '$preamble' => str_replace("\n", "
\n", $this->preamble), + '$thanks' => $this->l10n->t('thanks'), + '$site_admin' => $this->siteAdmin, + '$htmlversion' => $htmlVersion, + ]); + } + + /** + * {@inheritDoc} + * + * @throws Exception + */ + protected function getPlaintextMessage() + { + $textVersion = BBCode::toPlaintext($this->body); + + // load the template for private message notifications + $tpl = Renderer::getMarkupTemplate('email/system/text.tpl'); + return Renderer::replaceMacros($tpl, [ + '$preamble' => $this->preamble, + '$thanks' => $this->l10n->t('thanks'), + '$site_admin' => $this->siteAdmin, + '$textversion' => $textVersion, + ]); + } +} diff --git a/src/Util/Emailer.php b/src/Util/Emailer.php index 19755bebda..ed4ea4d87c 100644 --- a/src/Util/Emailer.php +++ b/src/Util/Emailer.php @@ -7,10 +7,12 @@ namespace Friendica\Util; use Friendica\App; use Friendica\Core\Config\IConfig; use Friendica\Core\Hook; +use Friendica\Core\L10n; use Friendica\Core\PConfig\IPConfig; use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Object\EMail\IEmail; use Friendica\Protocol\Email; +use Friendica\Util\EMailer\SystemMailBuilder; use Psr\Log\LoggerInterface; /** @@ -35,6 +37,18 @@ class Emailer $this->baseUrl = $baseURL; } + /** + * Creates a new system email + * + * @param L10n $l10n The chosen language for the new email + * + * @return SystemMailBuilder + */ + public function newSystemMail(L10n $l10n) + { + return new SystemMailBuilder($l10n, $this->baseUrl, $this->config); + } + /** * Send a multipart/alternative message with Text and HTML versions * diff --git a/tests/Util/SampleMailBuilder.php b/tests/Util/SampleMailBuilder.php new file mode 100644 index 0000000000..59638eea97 --- /dev/null +++ b/tests/Util/SampleMailBuilder.php @@ -0,0 +1,57 @@ +subject = $subject; + $this->html = $html; + $this->text = $text; + + return $this; + } + + /** + * @inheritDoc + */ + protected function getSubject() + { + return $this->subject; + } + + /** + * @inheritDoc + */ + protected function getHtmlMessage() + { + return $this->html; + } + + /** + * @inheritDoc + */ + protected function getPlaintextMessage() + { + return $this->text; + } +} diff --git a/tests/src/Util/Emailer/MailBuilderTest.php b/tests/src/Util/Emailer/MailBuilderTest.php new file mode 100644 index 0000000000..564e79f803 --- /dev/null +++ b/tests/src/Util/Emailer/MailBuilderTest.php @@ -0,0 +1,176 @@ +setUpVfsDir(); + + $this->config = \Mockery::mock(IConfig::class); + $this->l10n = \Mockery::mock(L10n::class); + $this->baseUrl = \Mockery::mock(BaseURL::class); + $this->baseUrl->shouldReceive('getHostname')->andReturn('friendica.local'); + $this->baseUrl->shouldReceive('get')->andReturn('http://friendica.local'); + + $this->defaultHeaders = ""; + } + + public function assertEmail(IEmail $email, array $asserts) + { + $this->assertEquals($asserts['subject'] ?? $email->getSubject(), $email->getSubject()); + $this->assertEquals($asserts['html'] ?? $email->getMessage(), $email->getMessage()); + $this->assertEquals($asserts['text'] ?? $email->getMessage(true), $email->getMessage(true)); + $this->assertEquals($asserts['toAddress'] ?? $email->getToAddress(), $email->getToAddress()); + $this->assertEquals($asserts['fromAddress'] ?? $email->getFromAddress(), $email->getFromAddress()); + $this->assertEquals($asserts['fromName'] ?? $email->getFromName(), $email->getFromName()); + $this->assertEquals($asserts['replyTo'] ?? $email->getReplyTo(), $email->getReplyTo()); + $this->assertEquals($asserts['uid'] ?? $email->getRecipientUid(), $email->getRecipientUid()); + $this->assertEquals($asserts['header'] ?? $email->getAdditionalMailHeader(), $email->getAdditionalMailHeader()); + } + + /** + * Test if the builder instance can get created + */ + public function testBuilderInstance() + { + $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config); + + $this->assertInstanceOf(MailBuilder::class, $builder); + } + + /** + * Test if the builder can create full rendered emails + * + * @todo Create test once "Renderer" and "BBCode" are dynamic + */ + public function testBuilderWithNonRawEmail() + { + $this->markTestIncomplete('Cannot easily mock Renderer and BBCode, so skipping tests wit them'); + } + + /** + * Test if the builder can create a "simple" raw mail + */ + public function testBuilderWithRawEmail() + { + $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config); + + $testEmail = $builder + ->withMessage('Subject', 'Html', 'text') + ->withRecipient('recipient@friendica.local') + ->withSender('Sender', 'sender@friendica.local', 'no-reply@friendica.local') + ->forUser(100) + ->build(true); + + $this->assertEmail($testEmail, [ + 'subject' => 'Subject', + 'html' => 'Html', + 'text' => 'text', + 'toAddress' => 'recipient@friendica.local', + 'fromName' => 'Sender', + 'fromAddress' => 'sender@friendica.local', + 'noReply' => 'no-reply@friendica.local', + 'uid' => 100, + 'headers' => $this->defaultHeaders, + ]); + } + + /** + * Test if the builder throws an exception in case no recipient + * + * @expectedException \Friendica\Network\HTTPException\InternalServerErrorException + * @expectedExceptionMessage Recipient address is missing. + */ + public function testBuilderWithEmptyMail() + { + $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config); + + $builder->build(true); + } + + /** + * Test if the builder throws an exception in case no sender + * + * @expectedException \Friendica\Network\HTTPException\InternalServerErrorException + * @expectedExceptionMessage Sender address or name is missing. + */ + public function testBuilderWithEmptySender() + { + $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config); + + $builder + ->withRecipient('test@friendica.local') + ->build(true); + } + + /** + * Test if the builder is capable of creating "empty" mails if needed (not the decision of the builder if so ..) + */ + public function testBuilderWithoutMessage() + { + $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config); + + $testEmail = $builder + ->withRecipient('recipient@friendica.local') + ->withSender('Sender', 'sender@friendica.local') + ->build(true); + + $this->assertEmail($testEmail, [ + 'toAddress' => 'recipient@friendica.local', + 'fromName' => 'Sender', + 'fromAddress' => 'sender@friendica.local', + 'noReply' => 'sender@friendica.local', // no-reply is set same as address in case it's not set + 'headers' => $this->defaultHeaders, + ]); + } + + /** + * Test if the builder sets for the text the same as for + */ + public function testBuilderWithJustPreamble() + { + $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config); + + $testEmail = $builder + ->withRecipient('recipient@friendica.local') + ->withSender('Sender', 'sender@friendica.local') + ->build(true); + + $this->assertEmail($testEmail, [ + 'toAddress' => 'recipient@friendica.local', + 'fromName' => 'Sender', + 'fromAddress' => 'sender@friendica.local', + 'noReply' => 'sender@friendica.local', // no-reply is set same as address in case it's not set, + 'headers' => $this->defaultHeaders, + ]); + } +} diff --git a/view/templates/email/html.tpl b/view/templates/email/html.tpl new file mode 100644 index 0000000000..65af182c55 --- /dev/null +++ b/view/templates/email/html.tpl @@ -0,0 +1,22 @@ + + + + {{$banner}} + + + + + + + + + + {{$htmlversion nofilter}} + +
+ +
{{$product}}
+
+
+ + diff --git a/view/templates/email/notify_html.tpl b/view/templates/email/notify/notify_html.tpl similarity index 100% rename from view/templates/email/notify_html.tpl rename to view/templates/email/notify/notify_html.tpl diff --git a/view/templates/email/notify_text.tpl b/view/templates/email/notify/notify_text.tpl similarity index 100% rename from view/templates/email/notify_text.tpl rename to view/templates/email/notify/notify_text.tpl diff --git a/view/templates/email/system/html.tpl b/view/templates/email/system/html.tpl new file mode 100644 index 0000000000..ebef956b93 --- /dev/null +++ b/view/templates/email/system/html.tpl @@ -0,0 +1,3 @@ +{{$htmlversion nofilter}} +{{$thanks}} +{{$site_admin}} \ No newline at end of file diff --git a/view/templates/email/system/text.tpl b/view/templates/email/system/text.tpl new file mode 100644 index 0000000000..4dd7c8ccbd --- /dev/null +++ b/view/templates/email/system/text.tpl @@ -0,0 +1,7 @@ + +{{$preamble nofilter}} + +{{$textversion nofilter}} + +{{$thanks nofilter}} +{{$site_admin nofilter}} From 05dfff4bb4ba6743c8f1846b812f1262ed9cc49e Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sat, 1 Feb 2020 22:04:38 +0100 Subject: [PATCH 03/22] Remove unused dependency --- src/Object/EMail/IEmail.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Object/EMail/IEmail.php b/src/Object/EMail/IEmail.php index 220cddc42f..ec8ae88158 100644 --- a/src/Object/EMail/IEmail.php +++ b/src/Object/EMail/IEmail.php @@ -2,7 +2,6 @@ namespace Friendica\Object\EMail; -use Friendica\Core\L10n; use Friendica\Util\Emailer; use JsonSerializable; From 16d9b9ff7d706b1afc3ca37ddfe4f5dd89e28976 Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sat, 1 Feb 2020 22:11:36 +0100 Subject: [PATCH 04/22] Fixed wrong email field --- mod/lostpass.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/lostpass.php b/mod/lostpass.php index d125cab5fb..e412c49586 100644 --- a/mod/lostpass.php +++ b/mod/lostpass.php @@ -68,7 +68,7 @@ function lostpass_post(App $a) ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) ->withMessage(DI::l10n()->t('Password reset requested at %s', $sitename), $preamble, $body) ->forUser($user['uid'] ?? 0) - ->withRecipient($user['to_email']) + ->withRecipient($user['email']) ->build(); DI::emailer()->send($email); @@ -160,7 +160,7 @@ function lostpass_generate_password($user) ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) ->withMessage(DI::l10n()->t('Your password has been changed at %s', $sitename), $preamble, $body) ->forUser($user['uid'] ?? 0) - ->withRecipient($user['to_email']) + ->withRecipient($user['email']) ->build(); DI::emailer()->send($email); } From 7a8eca90f955d82290f79e437eab96f0e39a51d5 Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sat, 1 Feb 2020 22:13:09 +0100 Subject: [PATCH 05/22] renamed templates for notify --- view/templates/email/notify/{notify_html.tpl => html.tpl} | 0 view/templates/email/notify/{notify_text.tpl => text.tpl} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename view/templates/email/notify/{notify_html.tpl => html.tpl} (100%) rename view/templates/email/notify/{notify_text.tpl => text.tpl} (100%) diff --git a/view/templates/email/notify/notify_html.tpl b/view/templates/email/notify/html.tpl similarity index 100% rename from view/templates/email/notify/notify_html.tpl rename to view/templates/email/notify/html.tpl diff --git a/view/templates/email/notify/notify_text.tpl b/view/templates/email/notify/text.tpl similarity index 100% rename from view/templates/email/notify/notify_text.tpl rename to view/templates/email/notify/text.tpl From abad42f7d24c6df741b3e857d67ecb8cd10cab57 Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sat, 1 Feb 2020 22:17:19 +0100 Subject: [PATCH 06/22] fix wrong template --- src/Util/EMailer/MailBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Util/EMailer/MailBuilder.php b/src/Util/EMailer/MailBuilder.php index 419edfc36d..fab6c8862d 100644 --- a/src/Util/EMailer/MailBuilder.php +++ b/src/Util/EMailer/MailBuilder.php @@ -162,7 +162,7 @@ abstract class MailBuilder if (!$raw) { // load the template for private message notifications - $tpl = Renderer::getMarkupTemplate('email/notify/html.tpl'); + $tpl = Renderer::getMarkupTemplate('email/html.tpl'); $msgHtml = Renderer::replaceMacros($tpl, [ '$banner' => $this->l10n->t('Friendica Notification'), '$product' => FRIENDICA_PLATFORM, From 0966cdbb26046cace15f47f5e51fd78d6e4d4ffe Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sat, 1 Feb 2020 22:19:10 +0100 Subject: [PATCH 07/22] cleanup template --- view/templates/email/system/html.tpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/view/templates/email/system/html.tpl b/view/templates/email/system/html.tpl index ebef956b93..6b1408f7cc 100644 --- a/view/templates/email/system/html.tpl +++ b/view/templates/email/system/html.tpl @@ -1,3 +1,3 @@ {{$htmlversion nofilter}} -{{$thanks}} -{{$site_admin}} \ No newline at end of file +{{$thanks}} +{{$site_admin}} \ No newline at end of file From 9428466d1dde7a5456694916d92c142c69367db4 Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sat, 1 Feb 2020 22:30:10 +0100 Subject: [PATCH 08/22] Set Sitename / site email as sender for system emails --- mod/lostpass.php | 4 ++-- mod/removeme.php | 2 +- src/Core/Update.php | 4 ++-- src/Model/User.php | 4 ++-- src/Module/Admin/Users.php | 2 +- src/Util/EMailer/MailBuilder.php | 6 +----- src/Util/EMailer/SystemMailBuilder.php | 17 +++++++++++++++-- src/Util/Emailer.php | 5 +++-- 8 files changed, 27 insertions(+), 17 deletions(-) diff --git a/mod/lostpass.php b/mod/lostpass.php index e412c49586..04316a0996 100644 --- a/mod/lostpass.php +++ b/mod/lostpass.php @@ -65,7 +65,7 @@ function lostpass_post(App $a) Login Name: %3$s', $resetlink, DI::baseUrl(), $user['nickname'])); $email = DI::emailer() - ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) + ->newSystemMail(DI::app(), (!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) ->withMessage(DI::l10n()->t('Password reset requested at %s', $sitename), $preamble, $body) ->forUser($user['uid'] ?? 0) ->withRecipient($user['email']) @@ -157,7 +157,7 @@ function lostpass_generate_password($user) ', DI::baseUrl(), $user['nickname'], $new_password)); $email = DI::emailer() - ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) + ->newSystemMail(DI::app(), (!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) ->withMessage(DI::l10n()->t('Your password has been changed at %s', $sitename), $preamble, $body) ->forUser($user['uid'] ?? 0) ->withRecipient($user['email']) diff --git a/mod/removeme.php b/mod/removeme.php index 86d1f04e34..01a9b86da8 100644 --- a/mod/removeme.php +++ b/mod/removeme.php @@ -42,7 +42,7 @@ function removeme_post(App $a) } $email = DI::emailer() - ->newSystemMail((!empty($admin['language'])) ? DI::l10n()->withLang($admin['language']) : DI::l10n()->withLang('en')) + ->newSystemMail(DI::app(), (!empty($admin['language'])) ? DI::l10n()->withLang($admin['language']) : DI::l10n()->withLang('en')) ->withMessage(DI::l10n()->t('[Friendica System Notify]') . ' ' . DI::l10n()->t('User deleted their account'), DI::l10n()->t('On your Friendica node an user deleted their account. Please ensure that their data is removed from the backups.'), DI::l10n()->t('The user id is %d', local_user())) diff --git a/src/Core/Update.php b/src/Core/Update.php index 2a3b3a68d6..6eb056f573 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -264,7 +264,7 @@ class Update $body = $l10n->t("The error message is\n[pre]%s[/pre]", $error_message); $email = DI::emailer() - ->newSystemMail($l10n) + ->newSystemMail(DI::app(), $l10n) ->withMessage($l10n->t('[Friendica Notify] Database update'), $preamble, $body) ->forUser($admin['uid'] ?? 0) ->withRecipient($admin['email']) @@ -300,7 +300,7 @@ class Update $from_build, $to_build)); $email = DI::emailer() - ->newSystemMail($l10n) + ->newSystemMail(DI::app(), $l10n) ->withMessage($l10n->t('[Friendica Notify] Database update'), $preamble) ->forUser($admin['uid'] ?? 0) ->withRecipient($admin['email']) diff --git a/src/Model/User.php b/src/Model/User.php index cc6b96ae58..dd94413758 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -898,7 +898,7 @@ class User )); $email = DI::emailer() - ->newSystemMail(DI::l10n()) + ->newSystemMail(DI::app(), DI::l10n()) ->withMessage(DI::l10n()->t('Registration at %s', $sitename), $body) ->forUser($user['uid'] ?? 0) ->withRecipient($user['email']) @@ -966,7 +966,7 @@ class User )); $email = DI::emailer() - ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) + ->newSystemMail(DI::app(), $l10n) ->withMessage(DI::l10n()->t('Registration details for %s', $sitename), $preamble, $body) ->forUser($user['uid'] ?? 0) ->withRecipient($user['email']) diff --git a/src/Module/Admin/Users.php b/src/Module/Admin/Users.php index 5ca50d11ac..d4e19da479 100644 --- a/src/Module/Admin/Users.php +++ b/src/Module/Admin/Users.php @@ -77,7 +77,7 @@ class Users extends BaseAdmin $body = sprintf($body, DI::baseUrl()->get(), $user['nickname'], $result['password'], DI::config()->get('config', 'sitename')); $email = DI::emailer() - ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) + ->newSystemMail(DI::app(), (!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) ->withMessage(DI::l10n()->t('Registration details for %s', DI::config()->get('config', 'sitename')), $preamble, $body) ->forUser($user['uid'] ?? 0) ->withRecipient($user['email']) diff --git a/src/Util/EMailer/MailBuilder.php b/src/Util/EMailer/MailBuilder.php index fab6c8862d..fe801bd562 100644 --- a/src/Util/EMailer/MailBuilder.php +++ b/src/Util/EMailer/MailBuilder.php @@ -138,11 +138,7 @@ abstract class MailBuilder */ public function build(bool $raw = false) { - if (empty($this->recipientAddress)) { - throw new InternalServerErrorException('Recipient address is missing.'); - } - - if ((empty($this->senderName) || empty($this->senderAddress)) && + if ((empty($this->recipientAddress)) && !empty($this->recipientUid)) { $user = User::getById($this->recipientUid, ['username', 'email']); diff --git a/src/Util/EMailer/SystemMailBuilder.php b/src/Util/EMailer/SystemMailBuilder.php index 56ae620ec9..41d758ba0a 100644 --- a/src/Util/EMailer/SystemMailBuilder.php +++ b/src/Util/EMailer/SystemMailBuilder.php @@ -3,13 +3,13 @@ namespace Friendica\Util\EMailer; use Exception; +use Friendica\App; use Friendica\App\BaseURL; use Friendica\Content\Text\BBCode; use Friendica\Core\Config\IConfig; use Friendica\Core\L10n; use Friendica\Core\Renderer; use Friendica\Network\HTTPException\InternalServerErrorException; -use Friendica\Util\Emailer; /** * Builder for system-wide emails without any dependency to concrete entities (like items, activities, ..) @@ -26,7 +26,7 @@ class SystemMailBuilder extends MailBuilder /** @var string */ protected $siteAdmin; - public function __construct(L10n $l10n, BaseURL $baseUrl, IConfig $config) + public function __construct(App $a, L10n $l10n, BaseURL $baseUrl, IConfig $config) { parent::__construct($l10n, $baseUrl, $config); @@ -37,6 +37,8 @@ class SystemMailBuilder extends MailBuilder } else { $this->siteAdmin = $l10n->t('%s Administrator', $siteName); } + + $this->senderAddress = $a->getSenderEmailAddress(); } /** @@ -107,4 +109,15 @@ class SystemMailBuilder extends MailBuilder '$textversion' => $textVersion, ]); } + + /** + * {@inheritDoc} + */ + public function build(bool $raw = false) + { + // for system emails, always use the sitename/site address as the sender + $this->withSender($this->config->get('config', 'sitename'), $this->senderAddress); + + return parent::build($raw); + } } diff --git a/src/Util/Emailer.php b/src/Util/Emailer.php index ed4ea4d87c..3f9a491d76 100644 --- a/src/Util/Emailer.php +++ b/src/Util/Emailer.php @@ -40,13 +40,14 @@ class Emailer /** * Creates a new system email * + * @param App $a The Friendica app * @param L10n $l10n The chosen language for the new email * * @return SystemMailBuilder */ - public function newSystemMail(L10n $l10n) + public function newSystemMail(App $a, L10n $l10n) { - return new SystemMailBuilder($l10n, $this->baseUrl, $this->config); + return new SystemMailBuilder($a, $l10n, $this->baseUrl, $this->config); } /** From 206b53477ec4d0538be5ce92619f8ec920019848 Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sat, 1 Feb 2020 22:42:36 +0100 Subject: [PATCH 09/22] Fix Lookup --- src/Util/EMailer/MailBuilder.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Util/EMailer/MailBuilder.php b/src/Util/EMailer/MailBuilder.php index fe801bd562..c2c2f75dc5 100644 --- a/src/Util/EMailer/MailBuilder.php +++ b/src/Util/EMailer/MailBuilder.php @@ -140,14 +140,17 @@ abstract class MailBuilder { if ((empty($this->recipientAddress)) && !empty($this->recipientUid)) { - $user = User::getById($this->recipientUid, ['username', 'email']); + $user = User::getById($this->recipientUid, ['email']); if (!empty($user)) { - $this->senderName = $user['username']; - $this->senderAddress = $user['email']; + $this->recipientAddress = $user['email']; } } + if (empty($this->recipientAddress)) { + throw new InternalServerErrorException('Recipient address is missing.'); + } + if (empty($this->senderAddress) || empty($this->senderName)) { throw new InternalServerErrorException('Sender address or name is missing.'); } From 0e13428210b32766dd7736799fae933f7efe45a2 Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sat, 1 Feb 2020 23:32:03 +0100 Subject: [PATCH 10/22] Move "App::getSenderEmailAddress()" to "Emailer::getSiteEmailAddress()" --- include/enotify.php | 2 +- src/App.php | 21 ------------- src/Module/Invite.php | 2 +- src/Util/EMailer/SystemMailBuilder.php | 18 ++--------- src/Util/Emailer.php | 43 ++++++++++++++++++++++++-- 5 files changed, 45 insertions(+), 41 deletions(-) diff --git a/include/enotify.php b/include/enotify.php index 54bf482341..4423a36a08 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -72,7 +72,7 @@ function notification($params) $hostname = substr($hostname, 0, strpos($hostname, ':')); } - $sender_email = $a->getSenderEmailAddress(); + $sender_email = DI::emailer()->getSiteEmailAddress(); $user = DBA::selectFirst('user', ['nickname', 'page-flags'], ['uid' => $params['uid']]); diff --git a/src/App.php b/src/App.php index ceb11dd797..892a4c7790 100644 --- a/src/App.php +++ b/src/App.php @@ -242,27 +242,6 @@ class App $this->baseURL->get(); } - /** - * Generates the site's default sender email address - * - * @return string - * @throws HTTPException\InternalServerErrorException - */ - public function getSenderEmailAddress() - { - $sender_email = $this->config->get('config', 'sender_email'); - if (empty($sender_email)) { - $hostname = $this->baseURL->getHostname(); - if (strpos($hostname, ':')) { - $hostname = substr($hostname, 0, strpos($hostname, ':')); - } - - $sender_email = 'noreply@' . $hostname; - } - - return $sender_email; - } - /** * Returns the current theme name. May be overriden by the mobile theme name. * diff --git a/src/Module/Invite.php b/src/Module/Invite.php index df569377b9..fc8b4abf90 100644 --- a/src/Module/Invite.php +++ b/src/Module/Invite.php @@ -77,7 +77,7 @@ class Invite extends BaseModule } $additional_headers = 'From: ' . $app->user['email'] . "\n" - . 'Sender: ' . $app->getSenderEmailAddress() . "\n" + . 'Sender: ' . DI::emailer()->getSiteEmailAddress() . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit'; diff --git a/src/Util/EMailer/SystemMailBuilder.php b/src/Util/EMailer/SystemMailBuilder.php index 41d758ba0a..93e5cc349f 100644 --- a/src/Util/EMailer/SystemMailBuilder.php +++ b/src/Util/EMailer/SystemMailBuilder.php @@ -26,19 +26,18 @@ class SystemMailBuilder extends MailBuilder /** @var string */ protected $siteAdmin; - public function __construct(App $a, L10n $l10n, BaseURL $baseUrl, IConfig $config) + public function __construct(L10n $l10n, BaseURL $baseUrl, IConfig $config, string $siteEmailAddress, string $siteName) { parent::__construct($l10n, $baseUrl, $config); - $siteName = $this->config->get('config', 'sitename'); - if ($this->config->get('config', 'admin_name')) { $this->siteAdmin = $l10n->t('%1$s, %2$s Administrator', $this->config->get('config', 'admin_name'), $siteName); } else { $this->siteAdmin = $l10n->t('%s Administrator', $siteName); } - $this->senderAddress = $a->getSenderEmailAddress(); + // Set the system wide site address/name as sender (default for system mails) + $this->withSender($siteEmailAddress, $siteName); } /** @@ -109,15 +108,4 @@ class SystemMailBuilder extends MailBuilder '$textversion' => $textVersion, ]); } - - /** - * {@inheritDoc} - */ - public function build(bool $raw = false) - { - // for system emails, always use the sitename/site address as the sender - $this->withSender($this->config->get('config', 'sitename'), $this->senderAddress); - - return parent::build($raw); - } } diff --git a/src/Util/Emailer.php b/src/Util/Emailer.php index 3f9a491d76..485857b9d7 100644 --- a/src/Util/Emailer.php +++ b/src/Util/Emailer.php @@ -29,25 +29,62 @@ class Emailer /** @var App\BaseURL */ private $baseUrl; + /** @var string */ + private $siteEmailAddress; + /** @var string */ + private $siteEmailName; + public function __construct(IConfig $config, IPConfig $pConfig, App\BaseURL $baseURL, LoggerInterface $logger) { $this->config = $config; $this->pConfig = $pConfig; $this->logger = $logger; $this->baseUrl = $baseURL; + + $this->siteEmailAddress = $this->config->get('config', 'sender_email'); + if (empty($sysEmailAddress)) { + $hostname = $this->baseUrl->getHostname(); + if (strpos($hostname, ':')) { + $hostname = substr($hostname, 0, strpos($hostname, ':')); + } + + $this->siteEmailAddress = 'noreply@' . $hostname; + } + + $this->siteEmailName = $this->config->get('config', 'sitename', 'Friendica Social Network'); + } + + /** + * Gets the site's default sender email address + * + * @return string + */ + public function getSiteEmailAddress() + { + return $this->siteEmailAddress; + } + + /** + * Gets the site's default sender name + * + * @return string + */ + public function getSiteEmailName() + { + return $this->siteEmailName; } /** * Creates a new system email * - * @param App $a The Friendica app * @param L10n $l10n The chosen language for the new email * * @return SystemMailBuilder */ - public function newSystemMail(App $a, L10n $l10n) + public function newSystemMail(L10n $l10n) { - return new SystemMailBuilder($a, $l10n, $this->baseUrl, $this->config); + return new SystemMailBuilder($l10n, $this->baseUrl, $this->config, + $this->getSiteEmailAddress(), $this->getSiteEmailName()); } /** From 0b309245b1cfc50aeb4a3981c0d2250e4a83c19c Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sat, 1 Feb 2020 23:32:34 +0100 Subject: [PATCH 11/22] Improve check --- src/Util/EMailer/MailBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Util/EMailer/MailBuilder.php b/src/Util/EMailer/MailBuilder.php index c2c2f75dc5..389874efde 100644 --- a/src/Util/EMailer/MailBuilder.php +++ b/src/Util/EMailer/MailBuilder.php @@ -142,7 +142,7 @@ abstract class MailBuilder !empty($this->recipientUid)) { $user = User::getById($this->recipientUid, ['email']); - if (!empty($user)) { + if (!empty($user['email'])) { $this->recipientAddress = $user['email']; } } From 97e708f2e2f57b4833eb94b4758a0768a09d9ead Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sat, 1 Feb 2020 23:34:50 +0100 Subject: [PATCH 12/22] Remove DI::app() dependency again --- mod/lostpass.php | 4 ++-- mod/removeme.php | 2 +- src/Core/Update.php | 4 ++-- src/Model/User.php | 4 ++-- src/Module/Admin/Users.php | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mod/lostpass.php b/mod/lostpass.php index 04316a0996..e412c49586 100644 --- a/mod/lostpass.php +++ b/mod/lostpass.php @@ -65,7 +65,7 @@ function lostpass_post(App $a) Login Name: %3$s', $resetlink, DI::baseUrl(), $user['nickname'])); $email = DI::emailer() - ->newSystemMail(DI::app(), (!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) + ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) ->withMessage(DI::l10n()->t('Password reset requested at %s', $sitename), $preamble, $body) ->forUser($user['uid'] ?? 0) ->withRecipient($user['email']) @@ -157,7 +157,7 @@ function lostpass_generate_password($user) ', DI::baseUrl(), $user['nickname'], $new_password)); $email = DI::emailer() - ->newSystemMail(DI::app(), (!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) + ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) ->withMessage(DI::l10n()->t('Your password has been changed at %s', $sitename), $preamble, $body) ->forUser($user['uid'] ?? 0) ->withRecipient($user['email']) diff --git a/mod/removeme.php b/mod/removeme.php index 01a9b86da8..86d1f04e34 100644 --- a/mod/removeme.php +++ b/mod/removeme.php @@ -42,7 +42,7 @@ function removeme_post(App $a) } $email = DI::emailer() - ->newSystemMail(DI::app(), (!empty($admin['language'])) ? DI::l10n()->withLang($admin['language']) : DI::l10n()->withLang('en')) + ->newSystemMail((!empty($admin['language'])) ? DI::l10n()->withLang($admin['language']) : DI::l10n()->withLang('en')) ->withMessage(DI::l10n()->t('[Friendica System Notify]') . ' ' . DI::l10n()->t('User deleted their account'), DI::l10n()->t('On your Friendica node an user deleted their account. Please ensure that their data is removed from the backups.'), DI::l10n()->t('The user id is %d', local_user())) diff --git a/src/Core/Update.php b/src/Core/Update.php index 6eb056f573..2a3b3a68d6 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -264,7 +264,7 @@ class Update $body = $l10n->t("The error message is\n[pre]%s[/pre]", $error_message); $email = DI::emailer() - ->newSystemMail(DI::app(), $l10n) + ->newSystemMail($l10n) ->withMessage($l10n->t('[Friendica Notify] Database update'), $preamble, $body) ->forUser($admin['uid'] ?? 0) ->withRecipient($admin['email']) @@ -300,7 +300,7 @@ class Update $from_build, $to_build)); $email = DI::emailer() - ->newSystemMail(DI::app(), $l10n) + ->newSystemMail($l10n) ->withMessage($l10n->t('[Friendica Notify] Database update'), $preamble) ->forUser($admin['uid'] ?? 0) ->withRecipient($admin['email']) diff --git a/src/Model/User.php b/src/Model/User.php index dd94413758..1431dd0d82 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -898,7 +898,7 @@ class User )); $email = DI::emailer() - ->newSystemMail(DI::app(), DI::l10n()) + ->newSystemMail(DI::l10n()) ->withMessage(DI::l10n()->t('Registration at %s', $sitename), $body) ->forUser($user['uid'] ?? 0) ->withRecipient($user['email']) @@ -966,7 +966,7 @@ class User )); $email = DI::emailer() - ->newSystemMail(DI::app(), $l10n) + ->newSystemMail($l10n) ->withMessage(DI::l10n()->t('Registration details for %s', $sitename), $preamble, $body) ->forUser($user['uid'] ?? 0) ->withRecipient($user['email']) diff --git a/src/Module/Admin/Users.php b/src/Module/Admin/Users.php index d4e19da479..5ca50d11ac 100644 --- a/src/Module/Admin/Users.php +++ b/src/Module/Admin/Users.php @@ -77,7 +77,7 @@ class Users extends BaseAdmin $body = sprintf($body, DI::baseUrl()->get(), $user['nickname'], $result['password'], DI::config()->get('config', 'sitename')); $email = DI::emailer() - ->newSystemMail(DI::app(), (!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) + ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) ->withMessage(DI::l10n()->t('Registration details for %s', DI::config()->get('config', 'sitename')), $preamble, $body) ->forUser($user['uid'] ?? 0) ->withRecipient($user['email']) From ca67e3111c755be8448d43878e65f7238489bdc2 Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sat, 1 Feb 2020 23:42:56 +0100 Subject: [PATCH 13/22] Set sender data directly --- src/Util/EMailer/SystemMailBuilder.php | 4 +- .../Util/Emailer/SystemMailBuilderTest.php | 58 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 tests/src/Util/Emailer/SystemMailBuilderTest.php diff --git a/src/Util/EMailer/SystemMailBuilder.php b/src/Util/EMailer/SystemMailBuilder.php index 93e5cc349f..07cbca4e27 100644 --- a/src/Util/EMailer/SystemMailBuilder.php +++ b/src/Util/EMailer/SystemMailBuilder.php @@ -37,7 +37,9 @@ class SystemMailBuilder extends MailBuilder } // Set the system wide site address/name as sender (default for system mails) - $this->withSender($siteEmailAddress, $siteName); + $this->senderName = $siteName; + $this->senderAddress = $siteEmailAddress; + $this->senderNoReply = $siteEmailAddress; } /** diff --git a/tests/src/Util/Emailer/SystemMailBuilderTest.php b/tests/src/Util/Emailer/SystemMailBuilderTest.php new file mode 100644 index 0000000000..5c531bf3cd --- /dev/null +++ b/tests/src/Util/Emailer/SystemMailBuilderTest.php @@ -0,0 +1,58 @@ +setUpVfsDir(); + + $this->config = \Mockery::mock(IConfig::class); + $this->config->shouldReceive('get')->with('config', 'admin_name')->andReturn('Admin'); + $this->l10n = \Mockery::mock(L10n::class); + $this->l10n->shouldReceive('t')->andReturnUsing(function ($msg) { + return $msg; + }); + $this->baseUrl = \Mockery::mock(BaseURL::class); + $this->baseUrl->shouldReceive('getHostname')->andReturn('friendica.local'); + $this->baseUrl->shouldReceive('get')->andReturn('http://friendica.local'); + + $this->defaultHeaders = ""; + } + + /** + * Test if the builder instance can get created + */ + public function testBuilderInstance() + { + $builder = new SystemMailBuilder($this->l10n, $this->baseUrl, $this->config, 'moreply@friendica.local', 'FriendicaSite'); + + $this->assertInstanceOf(MailBuilder::class, $builder); + $this->assertInstanceOf(SystemMailBuilder::class, $builder); + } +} From ed9756225d0dba15ed284822d7442d69283ac77d Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sun, 2 Feb 2020 08:45:10 +0100 Subject: [PATCH 14/22] improvements --- include/enotify.php | 3 +-- src/Core/Update.php | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/enotify.php b/include/enotify.php index 4423a36a08..42aee55690 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -74,8 +74,7 @@ function notification($params) $sender_email = DI::emailer()->getSiteEmailAddress(); - $user = DBA::selectFirst('user', ['nickname', 'page-flags'], - ['uid' => $params['uid']]); + $user = User::getById($params['uid'], ['nickname', 'page-flags']); // There is no need to create notifications for forum accounts if (!DBA::isResult($user) || in_array($user["page-flags"], [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP])) { diff --git a/src/Core/Update.php b/src/Core/Update.php index 2a3b3a68d6..b1e0a7cf17 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -252,7 +252,7 @@ class Update } $sent[] = $admin['email']; - $lang = (($admin['language']) ? $admin['language'] : 'en'); + $lang = $admin['language'] ?? 'en'; $l10n = DI::l10n()->withLang($lang); $preamble = Strings::deindent($l10n->t(" From 6700467ed41d840fca2d5a959c69632fae400994 Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sun, 2 Feb 2020 09:15:05 +0100 Subject: [PATCH 15/22] switched intend --- mod/lostpass.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mod/lostpass.php b/mod/lostpass.php index e412c49586..5856148d7d 100644 --- a/mod/lostpass.php +++ b/mod/lostpass.php @@ -157,11 +157,11 @@ function lostpass_generate_password($user) ', DI::baseUrl(), $user['nickname'], $new_password)); $email = DI::emailer() - ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) - ->withMessage(DI::l10n()->t('Your password has been changed at %s', $sitename), $preamble, $body) - ->forUser($user['uid'] ?? 0) - ->withRecipient($user['email']) - ->build(); + ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) + ->withMessage(DI::l10n()->t('Your password has been changed at %s', $sitename), $preamble, $body) + ->forUser($user['uid'] ?? 0) + ->withRecipient($user['email']) + ->build(); DI::emailer()->send($email); } From 262c94f12f4e28f3291716ffe8082e9b6b5cf7d7 Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sun, 2 Feb 2020 09:22:30 +0100 Subject: [PATCH 16/22] Fix indents --- mod/lostpass.php | 10 +++++----- mod/removeme.php | 15 ++++++++------- src/Core/Update.php | 20 ++++++++++---------- src/Model/User.php | 20 ++++++++++---------- src/Module/Admin/Users.php | 10 +++++----- 5 files changed, 38 insertions(+), 37 deletions(-) diff --git a/mod/lostpass.php b/mod/lostpass.php index 5856148d7d..34daeffd7d 100644 --- a/mod/lostpass.php +++ b/mod/lostpass.php @@ -65,11 +65,11 @@ function lostpass_post(App $a) Login Name: %3$s', $resetlink, DI::baseUrl(), $user['nickname'])); $email = DI::emailer() - ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) - ->withMessage(DI::l10n()->t('Password reset requested at %s', $sitename), $preamble, $body) - ->forUser($user['uid'] ?? 0) - ->withRecipient($user['email']) - ->build(); + ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) + ->withMessage(DI::l10n()->t('Password reset requested at %s', $sitename), $preamble, $body) + ->forUser($user['uid'] ?? 0) + ->withRecipient($user['email']) + ->build(); DI::emailer()->send($email); DI::baseUrl()->redirect(); diff --git a/mod/removeme.php b/mod/removeme.php index 86d1f04e34..d6b24eb0cc 100644 --- a/mod/removeme.php +++ b/mod/removeme.php @@ -42,13 +42,14 @@ function removeme_post(App $a) } $email = DI::emailer() - ->newSystemMail((!empty($admin['language'])) ? DI::l10n()->withLang($admin['language']) : DI::l10n()->withLang('en')) - ->withMessage(DI::l10n()->t('[Friendica System Notify]') . ' ' . DI::l10n()->t('User deleted their account'), - DI::l10n()->t('On your Friendica node an user deleted their account. Please ensure that their data is removed from the backups.'), - DI::l10n()->t('The user id is %d', local_user())) - ->forUser($admin['uid'] ?? 0) - ->withRecipient($admin['email']) - ->build(); + ->newSystemMail((!empty($admin['language'])) ? DI::l10n()->withLang($admin['language']) : DI::l10n()->withLang('en')) + ->withMessage( + DI::l10n()->t('[Friendica System Notify]') . ' ' . DI::l10n()->t('User deleted their account'), + DI::l10n()->t('On your Friendica node an user deleted their account. Please ensure that their data is removed from the backups.'), + DI::l10n()->t('The user id is %d', local_user())) + ->forUser($admin['uid'] ?? 0) + ->withRecipient($admin['email']) + ->build(); DI::emailer()->send($email); } diff --git a/src/Core/Update.php b/src/Core/Update.php index b1e0a7cf17..620519a236 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -264,11 +264,11 @@ class Update $body = $l10n->t("The error message is\n[pre]%s[/pre]", $error_message); $email = DI::emailer() - ->newSystemMail($l10n) - ->withMessage($l10n->t('[Friendica Notify] Database update'), $preamble, $body) - ->forUser($admin['uid'] ?? 0) - ->withRecipient($admin['email']) - ->build(); + ->newSystemMail($l10n) + ->withMessage($l10n->t('[Friendica Notify] Database update'), $preamble, $body) + ->forUser($admin['uid'] ?? 0) + ->withRecipient($admin['email']) + ->build(); DI::emailer()->send($email); } @@ -300,11 +300,11 @@ class Update $from_build, $to_build)); $email = DI::emailer() - ->newSystemMail($l10n) - ->withMessage($l10n->t('[Friendica Notify] Database update'), $preamble) - ->forUser($admin['uid'] ?? 0) - ->withRecipient($admin['email']) - ->build(); + ->newSystemMail($l10n) + ->withMessage($l10n->t('[Friendica Notify] Database update'), $preamble) + ->forUser($admin['uid'] ?? 0) + ->withRecipient($admin['email']) + ->build(); DI::emailer()->send($email); } } diff --git a/src/Model/User.php b/src/Model/User.php index 1431dd0d82..6deb1c6aee 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -898,11 +898,11 @@ class User )); $email = DI::emailer() - ->newSystemMail(DI::l10n()) - ->withMessage(DI::l10n()->t('Registration at %s', $sitename), $body) - ->forUser($user['uid'] ?? 0) - ->withRecipient($user['email']) - ->build(); + ->newSystemMail(DI::l10n()) + ->withMessage(DI::l10n()->t('Registration at %s', $sitename), $body) + ->forUser($user['uid'] ?? 0) + ->withRecipient($user['email']) + ->build(); return DI::emailer()->send($email); } @@ -966,11 +966,11 @@ class User )); $email = DI::emailer() - ->newSystemMail($l10n) - ->withMessage(DI::l10n()->t('Registration details for %s', $sitename), $preamble, $body) - ->forUser($user['uid'] ?? 0) - ->withRecipient($user['email']) - ->build(); + ->newSystemMail($l10n) + ->withMessage(DI::l10n()->t('Registration details for %s', $sitename), $preamble, $body) + ->forUser($user['uid'] ?? 0) + ->withRecipient($user['email']) + ->build(); return DI::emailer()->send($email); } diff --git a/src/Module/Admin/Users.php b/src/Module/Admin/Users.php index 5ca50d11ac..cbb2fa7ac6 100644 --- a/src/Module/Admin/Users.php +++ b/src/Module/Admin/Users.php @@ -77,11 +77,11 @@ class Users extends BaseAdmin $body = sprintf($body, DI::baseUrl()->get(), $user['nickname'], $result['password'], DI::config()->get('config', 'sitename')); $email = DI::emailer() - ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) - ->withMessage(DI::l10n()->t('Registration details for %s', DI::config()->get('config', 'sitename')), $preamble, $body) - ->forUser($user['uid'] ?? 0) - ->withRecipient($user['email']) - ->build(); + ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) + ->withMessage(DI::l10n()->t('Registration details for %s', DI::config()->get('config', 'sitename')), $preamble, $body) + ->forUser($user['uid'] ?? 0) + ->withRecipient($user['email']) + ->build(); return DI::emailer()->send($email); } From 7fb913eb86e9897de3551811ba4adc9d7caf8c14 Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sun, 2 Feb 2020 22:40:30 +0100 Subject: [PATCH 17/22] Add extra email banner (including setting) --- src/Module/Admin/Site.php | 15 +++++++++++++++ src/Util/EMailer/MailBuilder.php | 8 ++++++-- view/templates/admin/site.tpl | 1 + view/templates/email/html.tpl | 4 ++-- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/Module/Admin/Site.php b/src/Module/Admin/Site.php index 7cb3a9b8f7..50a9c9d22e 100644 --- a/src/Module/Admin/Site.php +++ b/src/Module/Admin/Site.php @@ -13,6 +13,7 @@ use Friendica\Module\BaseAdmin; use Friendica\Module\Register; use Friendica\Protocol\PortableContact; use Friendica\Util\BasePath; +use Friendica\Util\EMailer\MailBuilder; use Friendica\Util\Strings; use Friendica\Worker\Delivery; @@ -110,6 +111,7 @@ class Site extends BaseAdmin $sitename = (!empty($_POST['sitename']) ? Strings::escapeTags(trim($_POST['sitename'])) : ''); $sender_email = (!empty($_POST['sender_email']) ? Strings::escapeTags(trim($_POST['sender_email'])) : ''); $banner = (!empty($_POST['banner']) ? trim($_POST['banner']) : false); + $email_banner = (!empty($_POST['email_banner']) ? trim($_POST['email_banner']) : false); $shortcut_icon = (!empty($_POST['shortcut_icon']) ? Strings::escapeTags(trim($_POST['shortcut_icon'])) : ''); $touch_icon = (!empty($_POST['touch_icon']) ? Strings::escapeTags(trim($_POST['touch_icon'])) : ''); $additional_info = (!empty($_POST['additional_info']) ? trim($_POST['additional_info']) : ''); @@ -301,6 +303,12 @@ class Site extends BaseAdmin DI::config()->set('system', 'banner', $banner); } + if (empty($email_banner)) { + DI::config()->delete('system', 'email_banner'); + } else { + DI::config()->set('system', 'email_banner', $email_banner); + } + if (empty($additional_info)) { DI::config()->delete('config', 'info'); } else { @@ -489,6 +497,12 @@ class Site extends BaseAdmin $banner = 'logoFriendica'; } + $email_banner = DI::config()->get('system', 'email_banner'); + + if ($email_banner == false) { + $email_banner = MailBuilder::DEFAULT_EMAIL_BANNER; + } + $additional_info = DI::config()->get('config', 'info'); // Automatically create temporary paths @@ -571,6 +585,7 @@ class Site extends BaseAdmin '$sitename' => ['sitename', DI::l10n()->t('Site name'), DI::config()->get('config', 'sitename'), ''], '$sender_email' => ['sender_email', DI::l10n()->t('Sender Email'), DI::config()->get('config', 'sender_email'), DI::l10n()->t('The email address your server shall use to send notification emails from.'), '', '', 'email'], '$banner' => ['banner', DI::l10n()->t('Banner/Logo'), $banner, ''], + '$email_banner' => ['email_banner', DI::l10n()->t('Email Banner/Logo'), $email_banner, ''], '$shortcut_icon' => ['shortcut_icon', DI::l10n()->t('Shortcut icon'), DI::config()->get('system', 'shortcut_icon'), DI::l10n()->t('Link to an icon that will be used for browsers.')], '$touch_icon' => ['touch_icon', DI::l10n()->t('Touch icon'), DI::config()->get('system', 'touch_icon'), DI::l10n()->t('Link to an icon that will be used for tablets and mobiles.')], '$additional_info' => ['additional_info', DI::l10n()->t('Additional Info'), $additional_info, DI::l10n()->t('For public servers: you can add additional information here that will be listed at %s/servers.', Search::getGlobalDirectory())], diff --git a/src/Util/EMailer/MailBuilder.php b/src/Util/EMailer/MailBuilder.php index 389874efde..2f8c199a50 100644 --- a/src/Util/EMailer/MailBuilder.php +++ b/src/Util/EMailer/MailBuilder.php @@ -17,6 +17,9 @@ use Friendica\Object\EMail\IEmail; */ abstract class MailBuilder { + /** @var string The default email banner in case nothing else is defined */ + const DEFAULT_EMAIL_BANNER = 'images/friendica-32.png'; + /** @var L10n */ protected $l10n; /** @var IConfig */ @@ -163,11 +166,12 @@ abstract class MailBuilder // load the template for private message notifications $tpl = Renderer::getMarkupTemplate('email/html.tpl'); $msgHtml = Renderer::replaceMacros($tpl, [ - '$banner' => $this->l10n->t('Friendica Notification'), + '$title' => $this->l10n->t('Friendica Notification'), '$product' => FRIENDICA_PLATFORM, '$htmlversion' => $msgHtml, '$sitename' => $this->config->get('config', 'sitename'), - '$siteurl' => $this->baseUrl->get(true), + '$banner' => $this->config->get('system', 'email_banner', + $this->baseUrl->get(true) . DIRECTORY_SEPARATOR . self::DEFAULT_EMAIL_BANNER), ]); } diff --git a/view/templates/admin/site.tpl b/view/templates/admin/site.tpl index 19774b4255..9ccda33eeb 100644 --- a/view/templates/admin/site.tpl +++ b/view/templates/admin/site.tpl @@ -15,6 +15,7 @@ {{include file="field_input.tpl" field=$sitename}} {{include file="field_input.tpl" field=$sender_email}} {{include file="field_textarea.tpl" field=$banner}} + {{include file="field_input.tpl" field=$email_banner}} {{include file="field_input.tpl" field=$shortcut_icon}} {{include file="field_input.tpl" field=$touch_icon}} {{include file="field_textarea.tpl" field=$additional_info}} diff --git a/view/templates/email/html.tpl b/view/templates/email/html.tpl index 65af182c55..94e7271b90 100644 --- a/view/templates/email/html.tpl +++ b/view/templates/email/html.tpl @@ -1,7 +1,7 @@ - {{$banner}} + {{$title}} @@ -9,7 +9,7 @@ - +
{{$product}}
From 6e91f1be8399da05586096a0e4704e49bd1e0be1 Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Sun, 2 Feb 2020 22:55:18 +0100 Subject: [PATCH 18/22] Add own table for header --- view/templates/email/html.tpl | 5 ++--- view/templates/email/system/html.tpl | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/view/templates/email/html.tpl b/view/templates/email/html.tpl index 94e7271b90..5813ffc602 100644 --- a/view/templates/email/html.tpl +++ b/view/templates/email/html.tpl @@ -8,15 +8,14 @@ - - - {{$htmlversion nofilter}}
+
{{$product}}
+ {{$htmlversion nofilter}} diff --git a/view/templates/email/system/html.tpl b/view/templates/email/system/html.tpl index 6b1408f7cc..c34ddaba85 100644 --- a/view/templates/email/system/html.tpl +++ b/view/templates/email/system/html.tpl @@ -1,3 +1,5 @@ + - \ No newline at end of file + +
{{$htmlversion nofilter}}
{{$thanks}}
{{$site_admin}}
{{$site_admin}}
\ No newline at end of file From 9f95b975b456d0f8eb2cb03f5d924acecb5181b2 Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Tue, 4 Feb 2020 20:54:26 +0100 Subject: [PATCH 19/22] Improve HTML message --- view/templates/email/html.tpl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/view/templates/email/html.tpl b/view/templates/email/html.tpl index 5813ffc602..103572eaed 100644 --- a/view/templates/email/html.tpl +++ b/view/templates/email/html.tpl @@ -9,13 +9,15 @@ - + Friendica Banner
{{$product}}
+

{{$htmlversion nofilter}} +

From 0b94b84dc7539f28097a15ae030e34c56807365d Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Tue, 4 Feb 2020 21:04:08 +0100 Subject: [PATCH 20/22] simplify mail creation --- mod/lostpass.php | 8 ++++---- mod/removeme.php | 4 ++-- src/Core/Update.php | 8 ++++---- src/Model/User.php | 8 ++++---- src/Module/Admin/Users.php | 4 ++-- src/Util/EMailer/MailBuilder.php | 11 ++++++++--- src/Util/Emailer.php | 12 +++++++----- tests/src/Util/Emailer/MailBuilderTest.php | 2 +- 8 files changed, 32 insertions(+), 25 deletions(-) diff --git a/mod/lostpass.php b/mod/lostpass.php index 34daeffd7d..51aee56df7 100644 --- a/mod/lostpass.php +++ b/mod/lostpass.php @@ -65,9 +65,9 @@ function lostpass_post(App $a) Login Name: %3$s', $resetlink, DI::baseUrl(), $user['nickname'])); $email = DI::emailer() - ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) + ->newSystemMail() ->withMessage(DI::l10n()->t('Password reset requested at %s', $sitename), $preamble, $body) - ->forUser($user['uid'] ?? 0) + ->forUser($user) ->withRecipient($user['email']) ->build(); @@ -157,9 +157,9 @@ function lostpass_generate_password($user) ', DI::baseUrl(), $user['nickname'], $new_password)); $email = DI::emailer() - ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) + ->newSystemMail() ->withMessage(DI::l10n()->t('Your password has been changed at %s', $sitename), $preamble, $body) - ->forUser($user['uid'] ?? 0) + ->forUser($user) ->withRecipient($user['email']) ->build(); DI::emailer()->send($email); diff --git a/mod/removeme.php b/mod/removeme.php index d6b24eb0cc..e8615feb7c 100644 --- a/mod/removeme.php +++ b/mod/removeme.php @@ -42,12 +42,12 @@ function removeme_post(App $a) } $email = DI::emailer() - ->newSystemMail((!empty($admin['language'])) ? DI::l10n()->withLang($admin['language']) : DI::l10n()->withLang('en')) + ->newSystemMail() ->withMessage( DI::l10n()->t('[Friendica System Notify]') . ' ' . DI::l10n()->t('User deleted their account'), DI::l10n()->t('On your Friendica node an user deleted their account. Please ensure that their data is removed from the backups.'), DI::l10n()->t('The user id is %d', local_user())) - ->forUser($admin['uid'] ?? 0) + ->forUser($admin) ->withRecipient($admin['email']) ->build(); DI::emailer()->send($email); diff --git a/src/Core/Update.php b/src/Core/Update.php index 620519a236..4db32ecfbb 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -264,9 +264,9 @@ class Update $body = $l10n->t("The error message is\n[pre]%s[/pre]", $error_message); $email = DI::emailer() - ->newSystemMail($l10n) + ->newSystemMail() ->withMessage($l10n->t('[Friendica Notify] Database update'), $preamble, $body) - ->forUser($admin['uid'] ?? 0) + ->forUser($admin) ->withRecipient($admin['email']) ->build(); DI::emailer()->send($email); @@ -300,9 +300,9 @@ class Update $from_build, $to_build)); $email = DI::emailer() - ->newSystemMail($l10n) + ->newSystemMail() ->withMessage($l10n->t('[Friendica Notify] Database update'), $preamble) - ->forUser($admin['uid'] ?? 0) + ->forUser($admin) ->withRecipient($admin['email']) ->build(); DI::emailer()->send($email); diff --git a/src/Model/User.php b/src/Model/User.php index 6deb1c6aee..7e2d37c408 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -898,9 +898,9 @@ class User )); $email = DI::emailer() - ->newSystemMail(DI::l10n()) + ->newSystemMail() ->withMessage(DI::l10n()->t('Registration at %s', $sitename), $body) - ->forUser($user['uid'] ?? 0) + ->forUser($user) ->withRecipient($user['email']) ->build(); return DI::emailer()->send($email); @@ -966,9 +966,9 @@ class User )); $email = DI::emailer() - ->newSystemMail($l10n) + ->newSystemMail() ->withMessage(DI::l10n()->t('Registration details for %s', $sitename), $preamble, $body) - ->forUser($user['uid'] ?? 0) + ->forUser($user) ->withRecipient($user['email']) ->build(); return DI::emailer()->send($email); diff --git a/src/Module/Admin/Users.php b/src/Module/Admin/Users.php index cbb2fa7ac6..f52d7b36f8 100644 --- a/src/Module/Admin/Users.php +++ b/src/Module/Admin/Users.php @@ -77,9 +77,9 @@ class Users extends BaseAdmin $body = sprintf($body, DI::baseUrl()->get(), $user['nickname'], $result['password'], DI::config()->get('config', 'sitename')); $email = DI::emailer() - ->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n()) + ->newSystemMail() ->withMessage(DI::l10n()->t('Registration details for %s', DI::config()->get('config', 'sitename')), $preamble, $body) - ->forUser($user['uid'] ?? 0) + ->forUser($user) ->withRecipient($user['email']) ->build(); return DI::emailer()->send($email); diff --git a/src/Util/EMailer/MailBuilder.php b/src/Util/EMailer/MailBuilder.php index 2f8c199a50..074e29d3f2 100644 --- a/src/Util/EMailer/MailBuilder.php +++ b/src/Util/EMailer/MailBuilder.php @@ -86,13 +86,18 @@ abstract class MailBuilder /** * Adds the User ID to the email in case the mail sending needs additional properties of this user * - * @param int $uid The User ID + * @todo Once the user array is replaced with a user entity, replace this array parameter as well + * @param array $user The user entity/array, for which the email should be sent * * @return static */ - public function forUser(int $uid) + public function forUser(array $user) { - $this->recipientUid = $uid; + $this->recipientUid = $user['uid'] ?? 0; + try { + $this->l10n = $user['language'] ? $this->l10n->withLang($user['language']) : $this->l10n; + } catch (Exception $e) { + } return $this; } diff --git a/src/Util/Emailer.php b/src/Util/Emailer.php index 485857b9d7..d5d5f2cb41 100644 --- a/src/Util/Emailer.php +++ b/src/Util/Emailer.php @@ -28,18 +28,22 @@ class Emailer private $logger; /** @var App\BaseURL */ private $baseUrl; + /** @var L10n */ + private $l10n; /** @var string */ private $siteEmailAddress; /** @var string */ private $siteEmailName; - public function __construct(IConfig $config, IPConfig $pConfig, App\BaseURL $baseURL, LoggerInterface $logger) + public function __construct(IConfig $config, IPConfig $pConfig, App\BaseURL $baseURL, LoggerInterface $logger, + L10n $defaultLang) { $this->config = $config; $this->pConfig = $pConfig; $this->logger = $logger; $this->baseUrl = $baseURL; + $this->l10n = $defaultLang; $this->siteEmailAddress = $this->config->get('config', 'sender_email'); if (empty($sysEmailAddress)) { @@ -77,13 +81,11 @@ class Emailer /** * Creates a new system email * - * @param L10n $l10n The chosen language for the new email - * * @return SystemMailBuilder */ - public function newSystemMail(L10n $l10n) + public function newSystemMail() { - return new SystemMailBuilder($l10n, $this->baseUrl, $this->config, + return new SystemMailBuilder($this->l10n, $this->baseUrl, $this->config, $this->getSiteEmailAddress(), $this->getSiteEmailName()); } diff --git a/tests/src/Util/Emailer/MailBuilderTest.php b/tests/src/Util/Emailer/MailBuilderTest.php index 564e79f803..37b8f2784c 100644 --- a/tests/src/Util/Emailer/MailBuilderTest.php +++ b/tests/src/Util/Emailer/MailBuilderTest.php @@ -88,7 +88,7 @@ class MailBuilderTest extends MockedTest ->withMessage('Subject', 'Html', 'text') ->withRecipient('recipient@friendica.local') ->withSender('Sender', 'sender@friendica.local', 'no-reply@friendica.local') - ->forUser(100) + ->forUser(['uid' => 100]) ->build(true); $this->assertEmail($testEmail, [ From 11c831945c470ed63c936080ce0c14174061d68e Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Tue, 4 Feb 2020 21:32:18 +0100 Subject: [PATCH 21/22] Add logging --- src/Util/EMailer/MailBuilder.php | 7 ++++++- src/Util/EMailer/SystemMailBuilder.php | 7 ++++--- src/Util/Emailer.php | 2 +- tests/src/Util/Emailer/MailBuilderTest.php | 13 +++++++------ tests/src/Util/Emailer/SystemMailBuilderTest.php | 5 ++--- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/Util/EMailer/MailBuilder.php b/src/Util/EMailer/MailBuilder.php index 074e29d3f2..c640c96b94 100644 --- a/src/Util/EMailer/MailBuilder.php +++ b/src/Util/EMailer/MailBuilder.php @@ -11,6 +11,7 @@ use Friendica\Model\User; use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Object\Email; use Friendica\Object\EMail\IEmail; +use Psr\Log\LoggerInterface; /** * A base class for building new emails @@ -26,6 +27,8 @@ abstract class MailBuilder protected $config; /** @var BaseURL */ protected $baseUrl; + /** @var LoggerInterface */ + protected $logger; /** @var string */ protected $headers; @@ -42,11 +45,12 @@ abstract class MailBuilder /** @var int */ protected $recipientUid = null; - public function __construct(L10n $l10n, BaseURL $baseUrl, IConfig $config) + public function __construct(L10n $l10n, BaseURL $baseUrl, IConfig $config, LoggerInterface $logger) { $this->l10n = $l10n; $this->baseUrl = $baseUrl; $this->config = $config; + $this->logger = $logger; $hostname = $baseUrl->getHostname(); if (strpos($hostname, ':')) { @@ -97,6 +101,7 @@ abstract class MailBuilder try { $this->l10n = $user['language'] ? $this->l10n->withLang($user['language']) : $this->l10n; } catch (Exception $e) { + $this->logger->warning('cannot use language.', ['user' => $user, 'exception' => $e]); } return $this; diff --git a/src/Util/EMailer/SystemMailBuilder.php b/src/Util/EMailer/SystemMailBuilder.php index 07cbca4e27..015597fba5 100644 --- a/src/Util/EMailer/SystemMailBuilder.php +++ b/src/Util/EMailer/SystemMailBuilder.php @@ -3,13 +3,13 @@ namespace Friendica\Util\EMailer; use Exception; -use Friendica\App; use Friendica\App\BaseURL; use Friendica\Content\Text\BBCode; use Friendica\Core\Config\IConfig; use Friendica\Core\L10n; use Friendica\Core\Renderer; use Friendica\Network\HTTPException\InternalServerErrorException; +use Psr\Log\LoggerInterface; /** * Builder for system-wide emails without any dependency to concrete entities (like items, activities, ..) @@ -26,9 +26,10 @@ class SystemMailBuilder extends MailBuilder /** @var string */ protected $siteAdmin; - public function __construct(L10n $l10n, BaseURL $baseUrl, IConfig $config, string $siteEmailAddress, string $siteName) + public function __construct(L10n $l10n, BaseURL $baseUrl, IConfig $config, LoggerInterface $logger, + string$siteEmailAddress, string $siteName) { - parent::__construct($l10n, $baseUrl, $config); + parent::__construct($l10n, $baseUrl, $config, $logger); if ($this->config->get('config', 'admin_name')) { $this->siteAdmin = $l10n->t('%1$s, %2$s Administrator', $this->config->get('config', 'admin_name'), $siteName); diff --git a/src/Util/Emailer.php b/src/Util/Emailer.php index d5d5f2cb41..1e1c6856cf 100644 --- a/src/Util/Emailer.php +++ b/src/Util/Emailer.php @@ -85,7 +85,7 @@ class Emailer */ public function newSystemMail() { - return new SystemMailBuilder($this->l10n, $this->baseUrl, $this->config, + return new SystemMailBuilder($this->l10n, $this->baseUrl, $this->config, $this->logger, $this->getSiteEmailAddress(), $this->getSiteEmailName()); } diff --git a/tests/src/Util/Emailer/MailBuilderTest.php b/tests/src/Util/Emailer/MailBuilderTest.php index 37b8f2784c..1e475c9f70 100644 --- a/tests/src/Util/Emailer/MailBuilderTest.php +++ b/tests/src/Util/Emailer/MailBuilderTest.php @@ -10,6 +10,7 @@ use Friendica\Test\MockedTest; use Friendica\Test\Util\SampleMailBuilder; use Friendica\Test\Util\VFSTrait; use Friendica\Util\EMailer\MailBuilder; +use Psr\Log\NullLogger; /** * This class tests the "MailBuilder" (@see MailBuilder ) @@ -62,7 +63,7 @@ class MailBuilderTest extends MockedTest */ public function testBuilderInstance() { - $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config); + $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config, new NullLogger()); $this->assertInstanceOf(MailBuilder::class, $builder); } @@ -82,7 +83,7 @@ class MailBuilderTest extends MockedTest */ public function testBuilderWithRawEmail() { - $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config); + $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config, new NullLogger()); $testEmail = $builder ->withMessage('Subject', 'Html', 'text') @@ -112,7 +113,7 @@ class MailBuilderTest extends MockedTest */ public function testBuilderWithEmptyMail() { - $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config); + $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config, new NullLogger()); $builder->build(true); } @@ -125,7 +126,7 @@ class MailBuilderTest extends MockedTest */ public function testBuilderWithEmptySender() { - $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config); + $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config, new NullLogger()); $builder ->withRecipient('test@friendica.local') @@ -137,7 +138,7 @@ class MailBuilderTest extends MockedTest */ public function testBuilderWithoutMessage() { - $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config); + $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config, new NullLogger()); $testEmail = $builder ->withRecipient('recipient@friendica.local') @@ -158,7 +159,7 @@ class MailBuilderTest extends MockedTest */ public function testBuilderWithJustPreamble() { - $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config); + $builder = new SampleMailBuilder($this->l10n, $this->baseUrl, $this->config, new NullLogger()); $testEmail = $builder ->withRecipient('recipient@friendica.local') diff --git a/tests/src/Util/Emailer/SystemMailBuilderTest.php b/tests/src/Util/Emailer/SystemMailBuilderTest.php index 5c531bf3cd..e855602766 100644 --- a/tests/src/Util/Emailer/SystemMailBuilderTest.php +++ b/tests/src/Util/Emailer/SystemMailBuilderTest.php @@ -5,12 +5,11 @@ namespace Friendica\Test\src\Util\Emailer; use Friendica\App\BaseURL; use Friendica\Core\Config\IConfig; use Friendica\Core\L10n; -use Friendica\Object\EMail\IEmail; use Friendica\Test\MockedTest; -use Friendica\Test\Util\SampleMailBuilder; use Friendica\Test\Util\VFSTrait; use Friendica\Util\EMailer\MailBuilder; use Friendica\Util\EMailer\SystemMailBuilder; +use Psr\Log\NullLogger; class SystemMailBuilderTest extends MockedTest { @@ -50,7 +49,7 @@ class SystemMailBuilderTest extends MockedTest */ public function testBuilderInstance() { - $builder = new SystemMailBuilder($this->l10n, $this->baseUrl, $this->config, 'moreply@friendica.local', 'FriendicaSite'); + $builder = new SystemMailBuilder($this->l10n, $this->baseUrl, $this->config, new NullLogger(), 'moreply@friendica.local', 'FriendicaSite'); $this->assertInstanceOf(MailBuilder::class, $builder); $this->assertInstanceOf(SystemMailBuilder::class, $builder); From 3e898d04157f323a399515b13e22803e436f247b Mon Sep 17 00:00:00 2001 From: nupplaPhil Date: Tue, 4 Feb 2020 21:33:53 +0100 Subject: [PATCH 22/22] formating --- src/Util/EMailer/MailBuilder.php | 4 ++-- src/Util/EMailer/SystemMailBuilder.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Util/EMailer/MailBuilder.php b/src/Util/EMailer/MailBuilder.php index c640c96b94..c47d22d83f 100644 --- a/src/Util/EMailer/MailBuilder.php +++ b/src/Util/EMailer/MailBuilder.php @@ -50,7 +50,7 @@ abstract class MailBuilder $this->l10n = $l10n; $this->baseUrl = $baseUrl; $this->config = $config; - $this->logger = $logger; + $this->logger = $logger; $hostname = $baseUrl->getHostname(); if (strpos($hostname, ':')) { @@ -90,10 +90,10 @@ abstract class MailBuilder /** * Adds the User ID to the email in case the mail sending needs additional properties of this user * - * @todo Once the user array is replaced with a user entity, replace this array parameter as well * @param array $user The user entity/array, for which the email should be sent * * @return static + * @todo Once the user array is replaced with a user entity, replace this array parameter as well */ public function forUser(array $user) { diff --git a/src/Util/EMailer/SystemMailBuilder.php b/src/Util/EMailer/SystemMailBuilder.php index 015597fba5..24c1593c98 100644 --- a/src/Util/EMailer/SystemMailBuilder.php +++ b/src/Util/EMailer/SystemMailBuilder.php @@ -27,7 +27,7 @@ class SystemMailBuilder extends MailBuilder protected $siteAdmin; public function __construct(L10n $l10n, BaseURL $baseUrl, IConfig $config, LoggerInterface $logger, - string$siteEmailAddress, string $siteName) + string $siteEmailAddress, string $siteName) { parent::__construct($l10n, $baseUrl, $config, $logger);