mirror of
https://github.com/friendica/friendica
synced 2024-12-23 02:40:17 +00:00
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
This commit is contained in:
parent
74490d6594
commit
3291728059
18 changed files with 647 additions and 118 deletions
2
boot.php
2
boot.php
|
@ -152,8 +152,6 @@ define('NOTIFY_TAGSHARE', 256);
|
||||||
define('NOTIFY_POKE', 512);
|
define('NOTIFY_POKE', 512);
|
||||||
define('NOTIFY_SHARE', 1024);
|
define('NOTIFY_SHARE', 1024);
|
||||||
|
|
||||||
define('SYSTEM_EMAIL', 16384);
|
|
||||||
|
|
||||||
define('NOTIFY_SYSTEM', 32768);
|
define('NOTIFY_SYSTEM', 32768);
|
||||||
/* @}*/
|
/* @}*/
|
||||||
|
|
||||||
|
|
|
@ -74,18 +74,14 @@ function notification($params)
|
||||||
|
|
||||||
$sender_email = $a->getSenderEmailAddress();
|
$sender_email = $a->getSenderEmailAddress();
|
||||||
|
|
||||||
if ($params['type'] != SYSTEM_EMAIL) {
|
$user = DBA::selectFirst('user', ['nickname', 'page-flags'],
|
||||||
$user = DBA::selectFirst('user', ['nickname', 'page-flags'],
|
['uid' => $params['uid']]);
|
||||||
['uid' => $params['uid']]);
|
|
||||||
|
|
||||||
// There is no need to create notifications for forum accounts
|
// 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])) {
|
if (!DBA::isResult($user) || in_array($user["page-flags"], [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
$nickname = $user["nickname"];
|
|
||||||
} else {
|
|
||||||
$nickname = '';
|
|
||||||
}
|
}
|
||||||
|
$nickname = $user["nickname"];
|
||||||
|
|
||||||
// with $params['show_in_notification_page'] == false, the notification isn't inserted into
|
// with $params['show_in_notification_page'] == false, the notification isn't inserted into
|
||||||
// the database, and an email is sent if applicable.
|
// 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.")";
|
$subject .= " (".$nickname."@".$hostname.")";
|
||||||
|
|
||||||
$h = [
|
$h = [
|
||||||
|
@ -506,8 +478,7 @@ function notification($params)
|
||||||
|
|
||||||
// send email notification if notification preferences permit
|
// send email notification if notification preferences permit
|
||||||
if ((intval($params['notify_flags']) & intval($params['type']))
|
if ((intval($params['notify_flags']) & intval($params['type']))
|
||||||
|| $params['type'] == NOTIFY_SYSTEM
|
|| $params['type'] == NOTIFY_SYSTEM) {
|
||||||
|| $params['type'] == SYSTEM_EMAIL) {
|
|
||||||
|
|
||||||
Logger::log('sending notification email');
|
Logger::log('sending notification email');
|
||||||
|
|
||||||
|
@ -563,11 +534,10 @@ function notification($params)
|
||||||
Hook::callAll('enotify_mail', $datarray);
|
Hook::callAll('enotify_mail', $datarray);
|
||||||
|
|
||||||
// check whether sending post content in email notifications is allowed
|
// check whether sending post content in email notifications is allowed
|
||||||
// always true for SYSTEM_EMAIL
|
$content_allowed = (!DI::config()->get('system', 'enotify_no_content'));
|
||||||
$content_allowed = ((!DI::config()->get('system', 'enotify_no_content')) || ($params['type'] == SYSTEM_EMAIL));
|
|
||||||
|
|
||||||
// load the template for private message notifications
|
// 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, [
|
$email_html_body = Renderer::replaceMacros($tpl, [
|
||||||
'$banner' => $datarray['banner'],
|
'$banner' => $datarray['banner'],
|
||||||
'$product' => $datarray['product'],
|
'$product' => $datarray['product'],
|
||||||
|
@ -587,7 +557,7 @@ function notification($params)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// load the template for private message notifications
|
// 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, [
|
$email_text_body = Renderer::replaceMacros($tpl, [
|
||||||
'$preamble' => $datarray['preamble'],
|
'$preamble' => $datarray['preamble'],
|
||||||
'$tsitelink' => $datarray['tsitelink'],
|
'$tsitelink' => $datarray['tsitelink'],
|
||||||
|
|
|
@ -64,17 +64,14 @@ function lostpass_post(App $a)
|
||||||
Site Location: %2$s
|
Site Location: %2$s
|
||||||
Login Name: %3$s', $resetlink, DI::baseUrl(), $user['nickname']));
|
Login Name: %3$s', $resetlink, DI::baseUrl(), $user['nickname']));
|
||||||
|
|
||||||
notification([
|
$email = DI::emailer()
|
||||||
'type' => SYSTEM_EMAIL,
|
->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n())
|
||||||
'language' => $user['language'],
|
->withMessage(DI::l10n()->t('Password reset requested at %s', $sitename), $preamble, $body)
|
||||||
'to_name' => $user['username'],
|
->forUser($user['uid'] ?? 0)
|
||||||
'to_email' => $user['email'],
|
->withRecipient($user['to_email'])
|
||||||
'uid' => $user['uid'],
|
->build();
|
||||||
'subject' => DI::l10n()->t('Password reset requested at %s', $sitename),
|
|
||||||
'preamble' => $preamble,
|
|
||||||
'body' => $body
|
|
||||||
]);
|
|
||||||
|
|
||||||
|
DI::emailer()->send($email);
|
||||||
DI::baseUrl()->redirect();
|
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.
|
You may change that password from your account settings page after logging in.
|
||||||
', DI::baseUrl(), $user['nickname'], $new_password));
|
', DI::baseUrl(), $user['nickname'], $new_password));
|
||||||
|
|
||||||
notification([
|
$email = DI::emailer()
|
||||||
'type' => SYSTEM_EMAIL,
|
->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n())
|
||||||
'language' => $user['language'],
|
->withMessage(DI::l10n()->t('Your password has been changed at %s', $sitename), $preamble, $body)
|
||||||
'to_name' => $user['username'],
|
->forUser($user['uid'] ?? 0)
|
||||||
'to_email' => $user['email'],
|
->withRecipient($user['to_email'])
|
||||||
'uid' => $user['uid'],
|
->build();
|
||||||
'subject' => DI::l10n()->t('Your password has been changed at %s', $sitename),
|
DI::emailer()->send($email);
|
||||||
'preamble' => $preamble,
|
|
||||||
'body' => $body
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $o;
|
return $o;
|
||||||
|
|
|
@ -40,17 +40,16 @@ function removeme_post(App $a)
|
||||||
if (!DBA::isResult($admin)) {
|
if (!DBA::isResult($admin)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
notification([
|
|
||||||
'type' => SYSTEM_EMAIL,
|
$email = DI::emailer()
|
||||||
'subject' => DI::l10n()->t('[Friendica System Notify]') . ' ' . DI::l10n()->t('User deleted their account'),
|
->newSystemMail((!empty($admin['language'])) ? DI::l10n()->withLang($admin['language']) : DI::l10n()->withLang('en'))
|
||||||
'preamble' => DI::l10n()->t('On your Friendica node an user deleted their account. Please ensure that their data is removed from the backups.'),
|
->withMessage(DI::l10n()->t('[Friendica System Notify]') . ' ' . DI::l10n()->t('User deleted their account'),
|
||||||
'body' => DI::l10n()->t('The user id is %d', local_user()),
|
DI::l10n()->t('On your Friendica node an user deleted their account. Please ensure that their data is removed from the backups.'),
|
||||||
'to_email' => $admin['email'],
|
DI::l10n()->t('The user id is %d', local_user()))
|
||||||
'to_name' => $admin['username'],
|
->forUser($admin['uid'] ?? 0)
|
||||||
'uid' => $admin['uid'],
|
->withRecipient($admin['email'])
|
||||||
'language' => $admin['language'] ? $admin['language'] : 'en',
|
->build();
|
||||||
'show_in_notification_page' => false
|
DI::emailer()->send($email);
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (User::getIdFromPasswordAuthentication($a->user, trim($_POST['qxz_password']))) {
|
if (User::getIdFromPasswordAuthentication($a->user, trim($_POST['qxz_password']))) {
|
||||||
|
|
|
@ -252,7 +252,7 @@ class Update
|
||||||
}
|
}
|
||||||
$sent[] = $admin['email'];
|
$sent[] = $admin['email'];
|
||||||
|
|
||||||
$lang = (($admin['language'])?$admin['language']:'en');
|
$lang = (($admin['language']) ? $admin['language'] : 'en');
|
||||||
$l10n = DI::l10n()->withLang($lang);
|
$l10n = DI::l10n()->withLang($lang);
|
||||||
|
|
||||||
$preamble = Strings::deindent($l10n->t("
|
$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
|
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.",
|
friendica developer if you can not help me on your own. My database might be invalid.",
|
||||||
$update_id));
|
$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([
|
$email = DI::emailer()
|
||||||
'uid' => $admin['uid'],
|
->newSystemMail($l10n)
|
||||||
'type' => SYSTEM_EMAIL,
|
->withMessage($l10n->t('[Friendica Notify] Database update'), $preamble, $body)
|
||||||
'to_email' => $admin['email'],
|
->forUser($admin['uid'] ?? 0)
|
||||||
'subject' => $l10n->t('[Friendica Notify] Database update'),
|
->withRecipient($admin['email'])
|
||||||
'preamble' => $preamble,
|
->build();
|
||||||
'body' => $body,
|
DI::emailer()->send($email);
|
||||||
'language' => $lang]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//try the logger
|
//try the logger
|
||||||
|
@ -301,15 +299,13 @@ class Update
|
||||||
The friendica database was successfully updated from %s to %s.",
|
The friendica database was successfully updated from %s to %s.",
|
||||||
$from_build, $to_build));
|
$from_build, $to_build));
|
||||||
|
|
||||||
notification([
|
$email = DI::emailer()
|
||||||
'uid' => $admin['uid'],
|
->newSystemMail($l10n)
|
||||||
'type' => SYSTEM_EMAIL,
|
->withMessage($l10n->t('[Friendica Notify] Database update'), $preamble)
|
||||||
'to_email' => $admin['email'],
|
->forUser($admin['uid'] ?? 0)
|
||||||
'subject' => DI::l10n()->t('[Friendica Notify] Database update'),
|
->withRecipient($admin['email'])
|
||||||
'preamble' => $preamble,
|
->build();
|
||||||
'body' => $preamble,
|
DI::emailer()->send($email);
|
||||||
'language' => $lang]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -897,13 +897,13 @@ class User
|
||||||
$password
|
$password
|
||||||
));
|
));
|
||||||
|
|
||||||
return notification([
|
$email = DI::emailer()
|
||||||
'type' => SYSTEM_EMAIL,
|
->newSystemMail(DI::l10n())
|
||||||
'uid' => $user['uid'],
|
->withMessage(DI::l10n()->t('Registration at %s', $sitename), $body)
|
||||||
'to_email' => $user['email'],
|
->forUser($user['uid'] ?? 0)
|
||||||
'subject' => DI::l10n()->t('Registration at %s', $sitename),
|
->withRecipient($user['email'])
|
||||||
'body' => $body
|
->build();
|
||||||
]);
|
return DI::emailer()->send($email);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -965,15 +965,13 @@ class User
|
||||||
$password
|
$password
|
||||||
));
|
));
|
||||||
|
|
||||||
return notification([
|
$email = DI::emailer()
|
||||||
'uid' => $user['uid'],
|
->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n())
|
||||||
'language' => $user['language'],
|
->withMessage(DI::l10n()->t('Registration details for %s', $sitename), $preamble, $body)
|
||||||
'type' => SYSTEM_EMAIL,
|
->forUser($user['uid'] ?? 0)
|
||||||
'to_email' => $user['email'],
|
->withRecipient($user['email'])
|
||||||
'subject' => DI::l10n()->t('Registration details for %s', $sitename),
|
->build();
|
||||||
'preamble' => $preamble,
|
return DI::emailer()->send($email);
|
||||||
'body' => $body
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -76,15 +76,13 @@ class Users extends BaseAdmin
|
||||||
$preamble = sprintf($preamble, $user['username'], DI::config()->get('config', 'sitename'));
|
$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'));
|
$body = sprintf($body, DI::baseUrl()->get(), $user['nickname'], $result['password'], DI::config()->get('config', 'sitename'));
|
||||||
|
|
||||||
notification([
|
$email = DI::emailer()
|
||||||
'type' => SYSTEM_EMAIL,
|
->newSystemMail((!empty($user['language'])) ? DI::l10n()->withLang($user['language']) : DI::l10n())
|
||||||
'language' => $user['language'],
|
->withMessage(DI::l10n()->t('Registration details for %s', DI::config()->get('config', 'sitename')), $preamble, $body)
|
||||||
'to_name' => $user['username'],
|
->forUser($user['uid'] ?? 0)
|
||||||
'to_email' => $user['email'],
|
->withRecipient($user['email'])
|
||||||
'uid' => $user['uid'],
|
->build();
|
||||||
'subject' => DI::l10n()->t('Registration details for %s', DI::config()->get('config', 'sitename')),
|
return DI::emailer()->send($email);
|
||||||
'preamble' => $preamble,
|
|
||||||
'body' => $body]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($_POST['page_users_block'])) {
|
if (!empty($_POST['page_users_block'])) {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace Friendica\Object\EMail;
|
namespace Friendica\Object\EMail;
|
||||||
|
|
||||||
|
use Friendica\Core\L10n;
|
||||||
use Friendica\Util\Emailer;
|
use Friendica\Util\Emailer;
|
||||||
use JsonSerializable;
|
use JsonSerializable;
|
||||||
|
|
||||||
|
|
186
src/Util/EMailer/MailBuilder.php
Normal file
186
src/Util/EMailer/MailBuilder.php
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Util\EMailer;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Friendica\App\BaseURL;
|
||||||
|
use Friendica\Core\Config\IConfig;
|
||||||
|
use Friendica\Core\L10n;
|
||||||
|
use Friendica\Core\Renderer;
|
||||||
|
use Friendica\Model\User;
|
||||||
|
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||||
|
use Friendica\Object\Email;
|
||||||
|
use Friendica\Object\EMail\IEmail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A base class for building new emails
|
||||||
|
*/
|
||||||
|
abstract class MailBuilder
|
||||||
|
{
|
||||||
|
/** @var L10n */
|
||||||
|
protected $l10n;
|
||||||
|
/** @var IConfig */
|
||||||
|
protected $config;
|
||||||
|
/** @var BaseURL */
|
||||||
|
protected $baseUrl;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $headers;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $senderName = null;
|
||||||
|
/** @var string */
|
||||||
|
protected $senderAddress = null;
|
||||||
|
/** @var string */
|
||||||
|
protected $senderNoReply = null;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $recipientAddress = null;
|
||||||
|
/** @var int */
|
||||||
|
protected $recipientUid = null;
|
||||||
|
|
||||||
|
public function __construct(L10n $l10n, BaseURL $baseUrl, IConfig $config)
|
||||||
|
{
|
||||||
|
$this->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: <notification." . $hostname . ">\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);
|
||||||
|
}
|
||||||
|
}
|
110
src/Util/EMailer/SystemMailBuilder.php
Normal file
110
src/Util/EMailer/SystemMailBuilder.php
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Util\EMailer;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
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, ..)
|
||||||
|
*/
|
||||||
|
class SystemMailBuilder extends MailBuilder
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
protected $subject;
|
||||||
|
/** @var string */
|
||||||
|
protected $preamble;
|
||||||
|
/** @var string */
|
||||||
|
protected $body;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $siteAdmin;
|
||||||
|
|
||||||
|
public function __construct(L10n $l10n, BaseURL $baseUrl, IConfig $config)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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", "<br>\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,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,10 +7,12 @@ namespace Friendica\Util;
|
||||||
use Friendica\App;
|
use Friendica\App;
|
||||||
use Friendica\Core\Config\IConfig;
|
use Friendica\Core\Config\IConfig;
|
||||||
use Friendica\Core\Hook;
|
use Friendica\Core\Hook;
|
||||||
|
use Friendica\Core\L10n;
|
||||||
use Friendica\Core\PConfig\IPConfig;
|
use Friendica\Core\PConfig\IPConfig;
|
||||||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||||
use Friendica\Object\EMail\IEmail;
|
use Friendica\Object\EMail\IEmail;
|
||||||
use Friendica\Protocol\Email;
|
use Friendica\Protocol\Email;
|
||||||
|
use Friendica\Util\EMailer\SystemMailBuilder;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,6 +37,18 @@ class Emailer
|
||||||
$this->baseUrl = $baseURL;
|
$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
|
* Send a multipart/alternative message with Text and HTML versions
|
||||||
*
|
*
|
||||||
|
|
57
tests/Util/SampleMailBuilder.php
Normal file
57
tests/Util/SampleMailBuilder.php
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Test\Util;
|
||||||
|
|
||||||
|
use Friendica\Util\EMailer\MailBuilder;
|
||||||
|
|
||||||
|
class SampleMailBuilder extends MailBuilder
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
protected $subject;
|
||||||
|
/** @var string */
|
||||||
|
protected $html;
|
||||||
|
/** @var string */
|
||||||
|
protected $text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a test message
|
||||||
|
*
|
||||||
|
* @param string $subject The subject of the email
|
||||||
|
* @param string $html The preamble of the email
|
||||||
|
* @param string $text The body of the email (if not set, the preamble will get used as body)
|
||||||
|
*
|
||||||
|
* @return static
|
||||||
|
*/
|
||||||
|
public function withMessage(string $subject, string $html, string $text)
|
||||||
|
{
|
||||||
|
$this->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;
|
||||||
|
}
|
||||||
|
}
|
176
tests/src/Util/Emailer/MailBuilderTest.php
Normal file
176
tests/src/Util/Emailer/MailBuilderTest.php
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class tests the "MailBuilder" (@see MailBuilder )
|
||||||
|
* Since it's an abstract class and every extended class of it has dependencies, we use a "SampleMailBuilder" (@see SampleMailBuilder ) to make this class work
|
||||||
|
*/
|
||||||
|
class MailBuilderTest extends MockedTest
|
||||||
|
{
|
||||||
|
use VFSTrait;
|
||||||
|
|
||||||
|
/** @var IConfig */
|
||||||
|
private $config;
|
||||||
|
/** @var L10n */
|
||||||
|
private $l10n;
|
||||||
|
/** @var BaseURL */
|
||||||
|
private $baseUrl;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $defaultHeaders;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->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,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
22
view/templates/email/html.tpl
Normal file
22
view/templates/email/html.tpl
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional //EN">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>{{$banner}}</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table style="border:1px solid #ccc">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" style="background:#084769; color:#FFFFFF; font-weight:bold; font-family:'lucida grande', tahoma, verdana,arial, sans-serif; padding: 4px 8px; vertical-align: middle; font-size:16px; letter-spacing: -0.03em; text-align: left;">
|
||||||
|
<img style="width:32px;height:32px; float:left;" src='{{$siteurl}}/images/friendica-32.png'>
|
||||||
|
<div style="padding:7px; margin-left: 5px; float:left; font-size:18px;letter-spacing:1px;">{{$product}}</div>
|
||||||
|
<div style="clear: both;"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{{$htmlversion nofilter}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
3
view/templates/email/system/html.tpl
Normal file
3
view/templates/email/system/html.tpl
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<tr><td style="padding-right:22px;">{{$htmlversion nofilter}}</td></tr>
|
||||||
|
<tr><td></td><td>{{$thanks}}</td></tr>
|
||||||
|
<tr><td></td><td>{{$site_admin}}</td></tr>
|
7
view/templates/email/system/text.tpl
Normal file
7
view/templates/email/system/text.tpl
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
{{$preamble nofilter}}
|
||||||
|
|
||||||
|
{{$textversion nofilter}}
|
||||||
|
|
||||||
|
{{$thanks nofilter}}
|
||||||
|
{{$site_admin nofilter}}
|
Loading…
Reference in a new issue