Merge pull request #8232 from nupplaphil/task/notify_email_builder
[friendica.git/.git] / src / Util / EMailer / MailBuilder.php
1 <?php
2
3 namespace Friendica\Util\EMailer;
4
5 use Exception;
6 use Friendica\App\BaseURL;
7 use Friendica\Core\Config\IConfig;
8 use Friendica\Core\L10n;
9 use Friendica\Core\Renderer;
10 use Friendica\Model\User;
11 use Friendica\Network\HTTPException\InternalServerErrorException;
12 use Friendica\Object\Email;
13 use Friendica\Object\EMail\IEmail;
14 use Psr\Log\LoggerInterface;
15
16 /**
17  * A base class for building new emails
18  */
19 abstract class MailBuilder
20 {
21         /** @var string The default email banner in case nothing else is defined */
22         const DEFAULT_EMAIL_BANNER = 'images/friendica-32.png';
23
24         /** @var L10n */
25         protected $l10n;
26         /** @var IConfig */
27         protected $config;
28         /** @var BaseURL */
29         protected $baseUrl;
30         /** @var LoggerInterface */
31         protected $logger;
32
33         /** @var string */
34         protected $headers;
35
36         /** @var string */
37         protected $senderName = null;
38         /** @var string */
39         protected $senderAddress = null;
40         /** @var string */
41         protected $senderNoReply = null;
42
43         /** @var string */
44         protected $recipientAddress = null;
45         /** @var int */
46         protected $recipientUid = null;
47
48         public function __construct(L10n $l10n, BaseURL $baseUrl, IConfig $config, LoggerInterface $logger)
49         {
50                 $this->l10n    = $l10n;
51                 $this->baseUrl = $baseUrl;
52                 $this->config  = $config;
53                 $this->logger  = $logger;
54
55                 $hostname = $baseUrl->getHostname();
56                 if (strpos($hostname, ':')) {
57                         $hostname = substr($hostname, 0, strpos($hostname, ':'));
58                 }
59
60                 $this->headers = "";
61                 $this->headers .= "Precedence: list\n";
62                 $this->headers .= "X-Friendica-Host: " . $hostname . "\n";
63                 $this->headers .= "X-Friendica-Platform: " . FRIENDICA_PLATFORM . "\n";
64                 $this->headers .= "X-Friendica-Version: " . FRIENDICA_VERSION . "\n";
65                 $this->headers .= "List-ID: <notification." . $hostname . ">\n";
66                 $this->headers .= "List-Archive: <" . $baseUrl->get() . "/notifications/system>\n";
67         }
68
69         /**
70          * Gets the subject of the concrete builder, which inherits this base class
71          *
72          * @return string
73          */
74         abstract protected function getSubject();
75
76         /**
77          * Gets the HTML version of the body of the concrete builder, which inherits this base class
78          *
79          * @return string
80          */
81         abstract protected function getHtmlMessage();
82
83         /**
84          * Gets the Plaintext version of the body of the concrete builder, which inherits this base class
85          *
86          * @return string
87          */
88         abstract protected function getPlaintextMessage();
89
90         /**
91          * Adds the User ID to the email in case the mail sending needs additional properties of this user
92          *
93          * @param array $user The user entity/array, for which the email should be sent
94          *
95          * @return static
96          * @todo Once the user array is replaced with a user entity, replace this array parameter as well
97          */
98         public function forUser(array $user)
99         {
100                 $this->recipientUid = $user['uid'] ?? 0;
101                 try {
102                         $this->l10n = $user['language'] ? $this->l10n->withLang($user['language']) : $this->l10n;
103                 } catch (Exception $e) {
104                         $this->logger->warning('cannot use language.', ['user' => $user, 'exception' => $e]);
105                 }
106
107                 return $this;
108         }
109
110         /**
111          * Adds the sender to the email (if not called/set, the sender will get loaded with the help of the user id)
112          *
113          * @param string      $name    The name of the sender
114          * @param string      $address The (email) address of the sender
115          * @param string|null $noReply Optional "no-reply" (email) address (if not set, it's the same as the address)
116          *
117          * @return static
118          */
119         public function withSender(string $name, string $address, string $noReply = null)
120         {
121                 $this->senderName    = $name;
122                 $this->senderAddress = $address;
123                 $this->senderNoReply = $noReply ?? $this->senderNoReply;
124
125                 return $this;
126         }
127
128         /**
129          * Adds a recipient to the email
130          *
131          * @param string $address The (email) address of the recipient
132          *
133          * @return static
134          */
135         public function withRecipient(string $address)
136         {
137                 $this->recipientAddress = $address;
138
139                 return $this;
140         }
141
142         /**
143          * Adds new headers to the default headers
144          *
145          * @param string $headers New headers
146          *
147          * @return static
148          */
149         public function addHeaders(string $headers)
150         {
151                 $this->headers .= $headers;
152
153                 return $this;
154         }
155
156         /**
157          * Build a email based on the given attributes
158          *
159          * @param bool $raw True, if the email shouldn't get extended by the default email-template
160          *
161          * @return IEmail A new generated email
162          *
163          * @throws InternalServerErrorException
164          * @throws Exception
165          */
166         public function build(bool $raw = false)
167         {
168                 if ((empty($this->recipientAddress)) &&
169                     !empty($this->recipientUid)) {
170                         $user = User::getById($this->recipientUid, ['email']);
171
172                         if (!empty($user['email'])) {
173                                 $this->recipientAddress = $user['email'];
174                         }
175                 }
176
177                 if (empty($this->recipientAddress)) {
178                         throw new InternalServerErrorException('Recipient address is missing.');
179                 }
180
181                 if (empty($this->senderAddress) || empty($this->senderName)) {
182                         throw new InternalServerErrorException('Sender address or name is missing.');
183                 }
184
185                 $this->senderNoReply = $this->senderNoReply ?? $this->senderAddress;
186
187                 $msgHtml = $this->getHtmlMessage() ?? '';
188
189                 if (!$raw) {
190                         // load the template for private message notifications
191                         $tpl     = Renderer::getMarkupTemplate('email/html.tpl');
192                         $msgHtml = Renderer::replaceMacros($tpl, [
193                                 '$title'       => $this->l10n->t('Friendica Notification'),
194                                 '$product'     => FRIENDICA_PLATFORM,
195                                 '$htmlversion' => $msgHtml,
196                                 '$sitename'    => $this->config->get('config', 'sitename'),
197                                 '$banner'      => $this->config->get('system', 'email_banner',
198                                         $this->baseUrl->get(true) . DIRECTORY_SEPARATOR . self::DEFAULT_EMAIL_BANNER),
199                         ]);
200                 }
201
202                 return new Email(
203                         $this->senderName,
204                         $this->senderAddress,
205                         $this->senderNoReply,
206                         $this->recipientAddress,
207                         $this->getSubject() ?? '',
208                         $msgHtml,
209                         $this->getPlaintextMessage() ?? '',
210                         $this->headers,
211                         $this->recipientUid ?? null);
212         }
213 }