]> git.mxchange.org Git - friendica.git/blob - include/enotify.php
Move notify to the new paradigm
[friendica.git] / include / enotify.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2021, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 use Friendica\Content\Text\Plaintext;
23 use Friendica\Core\Hook;
24 use Friendica\Core\Logger;
25 use Friendica\Core\System;
26 use Friendica\Database\DBA;
27 use Friendica\DI;
28 use Friendica\Model\Contact;
29 use Friendica\Model\Item;
30 use Friendica\Model\Notification;
31 use Friendica\Model\Post;
32 use Friendica\Model\User;
33 use Friendica\Model\Verb;
34 use Friendica\Navigation\Notifications;
35 use Friendica\Protocol\Activity;
36
37 /**
38  * Creates a notification entry and possibly sends a mail
39  *
40  * @param array $params Array with the elements:
41  *                      type, event, otype, activity, verb, uid, cid, item, link,
42  *                      source_name, source_mail, source_nick, source_link, source_photo,
43  *                      show_in_notification_page
44  *
45  * @return bool
46  * @throws \Friendica\Network\HTTPException\InternalServerErrorException
47  */
48 function notification($params)
49 {
50         /** @var string the common prefix of a notification subject */
51         $subjectPrefix = DI::l10n()->t('[Friendica:Notify]');
52
53         // Temporary logging for finding the origin
54         if (!isset($params['uid'])) {
55                 Logger::notice('Missing parameters "uid".', ['params' => $params, 'callstack' => System::callstack()]);
56         }
57
58         // Ensure that the important fields are set at any time
59         $fields = ['nickname', 'page-flags', 'notify-flags', 'language', 'username', 'email'];
60         $user = DBA::selectFirst('user', $fields, ['uid' => $params['uid']]);
61
62         if (!DBA::isResult($user)) {
63                 Logger::error('Unknown user', ['uid' =>  $params['uid']]);
64                 return false;
65         }
66
67         // There is no need to create notifications for forum accounts
68         if (in_array($user['page-flags'], [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP])) {
69                 return false;
70         }
71
72         $params['notify_flags'] = $user['notify-flags'];
73         $params['language']     = $user['language'];
74         $params['to_name']      = $user['username'];
75         $params['to_email']     = $user['email'];
76
77         // from here on everything is in the recipients language
78         $l10n = DI::l10n()->withLang($params['language']);
79
80         if (!empty($params['cid'])) {
81                 $contact = Contact::getById($params['cid'], ['url', 'name', 'photo']);
82                 if (DBA::isResult($contact)) {
83                         $params['source_link'] = $contact['url'];
84                         $params['source_name'] = $contact['name'];
85                         $params['source_photo'] = $contact['photo'];
86                 }
87         }
88
89         $siteurl = DI::baseUrl()->get(true);
90         $sitename = DI::config()->get('config', 'sitename');
91
92         // with $params['show_in_notification_page'] == false, the notification isn't inserted into
93         // the database, and an email is sent if applicable.
94         // default, if not specified: true
95         $show_in_notification_page = isset($params['show_in_notification_page']) ? $params['show_in_notification_page'] : true;
96
97         $title = $params['item']['title'] ?? '';
98         $body = $params['item']['body'] ?? '';
99
100         $parent_id = $params['item']['parent'] ?? 0;
101         $parent_uri_id = $params['item']['parent-uri-id'] ?? 0;
102
103         $epreamble = '';
104         $preamble  = '';
105         $subject   = '';
106         $sitelink  = '';
107         $tsitelink = '';
108         $hsitelink = '';
109         $itemlink  = '';
110
111         switch ($params['type']) {
112                 case Notification\Type::MAIL:
113                         $itemlink = $params['link'];
114
115                         $subject = $l10n->t('%s New mail received at %s', $subjectPrefix, $sitename);
116
117                         $preamble = $l10n->t('%1$s sent you a new private message at %2$s.', $params['source_name'], $sitename);
118                         $epreamble = $l10n->t('%1$s sent you %2$s.', '[url='.$params['source_link'].']'.$params['source_name'].'[/url]', '[url=' . $itemlink . ']' . $l10n->t('a private message').'[/url]');
119
120                         $sitelink = $l10n->t('Please visit %s to view and/or reply to your private messages.');
121                         $tsitelink = sprintf($sitelink, $itemlink);
122                         $hsitelink = sprintf($sitelink, '<a href="' . $itemlink . '">' . $sitename . '</a>');
123
124                         // Mail notifications aren't using the "notify" table entry
125                         $show_in_notification_page = false;
126                         break;
127
128                 case Notification\Type::COMMENT:
129                         if (Post\ThreadUser::getIgnored($parent_uri_id, $params['uid'])) {
130                                 Logger::info('Thread is ignored', ['parent' => $parent_id, 'parent-uri-id' => $parent_uri_id]);
131                                 return false;
132                         }
133
134                         $item = Post::selectFirstForUser($params['uid'], Item::ITEM_FIELDLIST, ['id' => $parent_id, 'deleted' => false]);
135                         if (empty($item)) {
136                                 return false;
137                         }
138
139                         $item_post_type = Item::postType($item, $l10n);
140
141                         $content = Plaintext::getPost($item, 70);
142                         if (!empty($content['text'])) {
143                                 $title = '"' . trim(str_replace("\n", " ", $content['text'])) . '"';
144                         } else {
145                                 $title = '';
146                         }
147
148                         // First go for the general message
149
150                         // "George Bull's post"
151                         $message = $l10n->t('%1$s commented on %2$s\'s %3$s %4$s');
152                         $dest_str = sprintf($message, $params['source_name'], $item['author-name'], $item_post_type, $title);
153
154                         // "your post"
155                         if ($item['wall']) {
156                                 $message = $l10n->t('%1$s commented on your %2$s %3$s');
157                                 $dest_str = sprintf($message, $params['source_name'], $item_post_type, $title);
158                         // "their post"
159                         } elseif ($item['author-link'] == $params['source_link']) {
160                                 $message = $l10n->t('%1$s commented on their %2$s %3$s');
161                                 $dest_str = sprintf($message, $params['source_name'], $item_post_type, $title);
162                         }
163
164                         $subject = $l10n->t('%1$s Comment to conversation #%2$d by %3$s', $subjectPrefix, $parent_id, $params['source_name']);
165
166                         $preamble = $l10n->t('%s commented on an item/conversation you have been following.', $params['source_name']);
167
168                         $epreamble = $dest_str;
169
170                         $sitelink = $l10n->t('Please visit %s to view and/or reply to the conversation.');
171                         $tsitelink = sprintf($sitelink, $siteurl);
172                         $hsitelink = sprintf($sitelink, '<a href="' . $siteurl . '">' . $sitename . '</a>');
173                         $itemlink =  $params['link'];
174                         break;
175
176                 case Notification\Type::WALL:
177                         $subject = $l10n->t('%s %s posted to your profile wall', $subjectPrefix, $params['source_name']);
178
179                         $preamble = $l10n->t('%1$s posted to your profile wall at %2$s', $params['source_name'], $sitename);
180                         $epreamble = $l10n->t('%1$s posted to [url=%2$s]your wall[/url]',
181                                 '[url='.$params['source_link'].']'.$params['source_name'].'[/url]',
182                                 $params['link']
183                         );
184
185                         $sitelink = $l10n->t('Please visit %s to view and/or reply to the conversation.');
186                         $tsitelink = sprintf($sitelink, $siteurl);
187                         $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
188                         $itemlink =  $params['link'];
189                         break;
190
191                 case Notification\Type::POKE:
192                         $subject = $l10n->t('%1$s %2$s poked you', $subjectPrefix, $params['source_name']);
193
194                         $preamble = $l10n->t('%1$s poked you at %2$s', $params['source_name'], $sitename);
195                         $epreamble = $l10n->t('%1$s [url=%2$s]poked you[/url].',
196                                 '[url='.$params['source_link'].']'.$params['source_name'].'[/url]',
197                                 $params['link']
198                         );
199
200                         $subject = str_replace('poked', $l10n->t($params['activity']), $subject);
201                         $preamble = str_replace('poked', $l10n->t($params['activity']), $preamble);
202                         $epreamble = str_replace('poked', $l10n->t($params['activity']), $epreamble);
203
204                         $sitelink = $l10n->t('Please visit %s to view and/or reply to the conversation.');
205                         $tsitelink = sprintf($sitelink, $siteurl);
206                         $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
207                         $itemlink =  $params['link'];
208                         break;
209
210                 case Notification\Type::INTRO:
211                         $itemlink = $params['link'];
212                         $subject = $l10n->t('%s Introduction received', $subjectPrefix);
213
214                         $preamble = $l10n->t('You\'ve received an introduction from \'%1$s\' at %2$s', $params['source_name'], $sitename);
215                         $epreamble = $l10n->t('You\'ve received [url=%1$s]an introduction[/url] from %2$s.',
216                                 $itemlink,
217                                 '[url='.$params['source_link'].']'.$params['source_name'].'[/url]'
218                         );
219
220                         $body = $l10n->t('You may visit their profile at %s', $params['source_link']);
221
222                         $sitelink = $l10n->t('Please visit %s to approve or reject the introduction.');
223                         $tsitelink = sprintf($sitelink, $siteurl);
224                         $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
225
226                         switch ($params['verb']) {
227                                 case Activity::FRIEND:
228                                         // someone started to share with user (mostly OStatus)
229                                         $subject = $l10n->t('%s A new person is sharing with you', $subjectPrefix);
230
231                                         $preamble = $l10n->t('%1$s is sharing with you at %2$s', $params['source_name'], $sitename);
232                                         $epreamble = $l10n->t('%1$s is sharing with you at %2$s',
233                                                 '[url='.$params['source_link'].']'.$params['source_name'].'[/url]',
234                                                 $sitename
235                                         );
236                                         break;
237                                 case Activity::FOLLOW:
238                                         // someone started to follow the user (mostly OStatus)
239                                         $subject = $l10n->t('%s You have a new follower', $subjectPrefix);
240
241                                         $preamble = $l10n->t('You have a new follower at %2$s : %1$s', $params['source_name'], $sitename);
242                                         $epreamble = $l10n->t('You have a new follower at %2$s : %1$s',
243                                                 '[url='.$params['source_link'].']'.$params['source_name'].'[/url]',
244                                                 $sitename
245                                         );
246                                         break;
247                                 default:
248                                         // ACTIVITY_REQ_FRIEND is default activity for notifications
249                                         break;
250                         }
251                         break;
252
253                 case Notification\Type::SUGGEST:
254                         $itemlink =  $params['link'];
255                         $subject = $l10n->t('%s Friend suggestion received', $subjectPrefix);
256
257                         $preamble = $l10n->t('You\'ve received a friend suggestion from \'%1$s\' at %2$s', $params['source_name'], $sitename);
258                         $epreamble = $l10n->t('You\'ve received [url=%1$s]a friend suggestion[/url] for %2$s from %3$s.',
259                                 $itemlink,
260                                 '[url='.$params['item']['url'].']'.$params['item']['name'].'[/url]',
261                                 '[url='.$params['source_link'].']'.$params['source_name'].'[/url]'
262                         );
263
264                         $body = $l10n->t('Name:').' '.$params['item']['name']."\n";
265                         $body .= $l10n->t('Photo:').' '.$params['item']['photo']."\n";
266                         $body .= $l10n->t('You may visit their profile at %s', $params['item']['url']);
267
268                         $sitelink = $l10n->t('Please visit %s to approve or reject the suggestion.');
269                         $tsitelink = sprintf($sitelink, $siteurl);
270                         $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
271                         break;
272
273                 case Notification\Type::CONFIRM:
274                         if ($params['verb'] == Activity::FRIEND) { // mutual connection
275                                 $itemlink =  $params['link'];
276                                 $subject = $l10n->t('%s Connection accepted', $subjectPrefix);
277
278                                 $preamble = $l10n->t('\'%1$s\' has accepted your connection request at %2$s', $params['source_name'], $sitename);
279                                 $epreamble = $l10n->t('%2$s has accepted your [url=%1$s]connection request[/url].',
280                                         $itemlink,
281                                         '[url='.$params['source_link'].']'.$params['source_name'].'[/url]'
282                                 );
283
284                                 $body =  $l10n->t('You are now mutual friends and may exchange status updates, photos, and email without restriction.');
285
286                                 $sitelink = $l10n->t('Please visit %s if you wish to make any changes to this relationship.');
287                                 $tsitelink = sprintf($sitelink, $siteurl);
288                                 $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
289                         } else { // ACTIVITY_FOLLOW
290                                 $itemlink =  $params['link'];
291                                 $subject = $l10n->t('%s Connection accepted', $subjectPrefix);
292
293                                 $preamble = $l10n->t('\'%1$s\' has accepted your connection request at %2$s', $params['source_name'], $sitename);
294                                 $epreamble = $l10n->t('%2$s has accepted your [url=%1$s]connection request[/url].',
295                                         $itemlink,
296                                         '[url='.$params['source_link'].']'.$params['source_name'].'[/url]'
297                                 );
298
299                                 $body =  $l10n->t('\'%1$s\' has chosen to accept you a fan, which restricts some forms of communication - such as private messaging and some profile interactions. If this is a celebrity or community page, these settings were applied automatically.', $params['source_name']);
300                                 $body .= "\n\n";
301                                 $body .= $l10n->t('\'%1$s\' may choose to extend this into a two-way or more permissive relationship in the future.', $params['source_name']);
302
303                                 $sitelink = $l10n->t('Please visit %s  if you wish to make any changes to this relationship.');
304                                 $tsitelink = sprintf($sitelink, $siteurl);
305                                 $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
306                         }
307                         break;
308
309                 case Notification\Type::SYSTEM:
310                         switch($params['event']) {
311                                 case "SYSTEM_REGISTER_REQUEST":
312                                         $itemlink =  $params['link'];
313                                         $subject = $l10n->t('[Friendica System Notify]') . ' ' . $l10n->t('registration request');
314
315                                         $preamble = $l10n->t('You\'ve received a registration request from \'%1$s\' at %2$s', $params['source_name'], $sitename);
316                                         $epreamble = $l10n->t('You\'ve received a [url=%1$s]registration request[/url] from %2$s.',
317                                                 $itemlink,
318                                                 '[url='.$params['source_link'].']'.$params['source_name'].'[/url]'
319                                         );
320
321                                         $body = $l10n->t("Full Name:    %s\nSite Location:      %s\nLogin Name: %s (%s)",
322                                                 $params['source_name'],
323                                                 $siteurl, $params['source_mail'],
324                                                 $params['source_nick']
325                                         );
326
327                                         $sitelink = $l10n->t('Please visit %s to approve or reject the request.');
328                                         $tsitelink = sprintf($sitelink, $params['link']);
329                                         $hsitelink = sprintf($sitelink, '<a href="'.$params['link'].'">'.$sitename.'</a><br><br>');
330                                         break;
331                                 case "SYSTEM_DB_UPDATE_FAIL":
332                                         break;
333                         }
334                         break;
335
336                 default:
337                         Logger::notice('Unhandled type', ['type' => $params['type']]);
338                         return false;
339         }
340
341         return notification_store_and_send($params, $sitelink, $tsitelink, $hsitelink, $title, $subject, $preamble, $epreamble, $body, $itemlink, $show_in_notification_page);
342 }
343
344 function notification_store_and_send($params, $sitelink, $tsitelink, $hsitelink, $title, $subject, $preamble, $epreamble, $body, $itemlink, $show_in_notification_page)
345 {
346         $item_id = $params['item']['id'] ?? 0;
347         $uri_id = $params['item']['uri-id'] ?? 0;
348         $parent_id = $params['item']['parent'] ?? 0;
349         $parent_uri_id = $params['item']['parent-uri-id'] ?? 0;
350
351         // Ensure that the important fields are set at any time
352         $fields = ['nickname'];
353         $user = User::getById($params['uid'], $fields);
354
355         $sitename = DI::config()->get('config', 'sitename');
356
357         $nickname = $user['nickname'];
358
359         $hostname = DI::baseUrl()->getHostname();
360         if (strpos($hostname, ':')) {
361                 $hostname = substr($hostname, 0, strpos($hostname, ':'));
362         }
363
364         // Creates a new email builder for the notification email
365         $emailBuilder = DI::emailer()->newNotifyMail();
366
367         $emailBuilder->setHeader('X-Friendica-Account', '<' . $nickname . '@' . $hostname . '>');
368
369         $subject .= " (".$nickname."@".$hostname.")";
370
371         $h = [
372                 'params'    => $params,
373                 'subject'   => $subject,
374                 'preamble'  => $preamble,
375                 'epreamble' => $epreamble,
376                 'body'      => $body,
377                 'sitelink'  => $sitelink,
378                 'tsitelink' => $tsitelink,
379                 'hsitelink' => $hsitelink,
380                 'itemlink'  => $itemlink
381         ];
382
383         Hook::callAll('enotify', $h);
384
385         $subject   = $h['subject'];
386
387         $preamble  = $h['preamble'];
388         $epreamble = $h['epreamble'];
389
390         $body      = $h['body'];
391
392         $tsitelink = $h['tsitelink'];
393         $hsitelink = $h['hsitelink'];
394         $itemlink  = $h['itemlink'];
395
396         $notify_id = 0;
397
398         if ($show_in_notification_page) {
399                 /** @var $factory Notifications\Factory\Notify */
400                 $factory = DI::getDice()->create(Notifications\Factory\Notify::class);
401
402                 $Notify = $factory->createFromParams($params, $itemlink, $item_id, $uri_id, $parent_id, $parent_uri_id);
403                 try {
404                         $Notify = DI::notify()->save($Notify);
405                 } catch (Notifications\Exception\NotificationCreationInterceptedException $e) {
406                         // Notification insertion can be intercepted by an addon registering the 'enotify_store' hook
407                         return false;
408                 }
409
410                 $Notify->updateMsgFromPreamble($epreamble);
411                 $Notify = DI::notify()->save($Notify);
412
413                 $itemlink  = DI::baseUrl() . '/notification/' . $Notify->id;
414                 $notify_id = $Notify->id;
415         }
416
417         // send email notification if notification preferences permit
418         if ((intval($params['notify_flags']) & intval($params['type']))
419                 || $params['type'] == Notification\Type::SYSTEM) {
420
421                 Logger::log('sending notification email');
422
423                 if (isset($params['parent']) && (intval($params['parent']) != 0)) {
424                         $parent = Post::selectFirst(['guid'], ['id' => $params['parent']]);
425                         $message_id = "<" . $parent['guid'] . "@" . gethostname() . ">";
426
427                         // Is this the first email notification for this parent item and user?
428                         if (!DBA::exists('notify-threads', ['master-parent-uri-id' => $parent_uri_id, 'receiver-uid' => $params['uid']])) {
429                                 Logger::log("notify_id:" . intval($notify_id) . ", parent: " . intval($params['parent']) . "uid: " . intval($params['uid']), Logger::DEBUG);
430
431                                 $fields = ['notify-id' => $notify_id, 'master-parent-uri-id' => $parent_uri_id,
432                                         'receiver-uid' => $params['uid'], 'parent-item' => 0];
433                                 DBA::insert('notify-threads', $fields);
434
435                                 $emailBuilder->setHeader('Message-ID', $message_id);
436                                 $log_msg = "include/enotify: No previous notification found for this parent:\n" .
437                                         "  parent: ${params['parent']}\n" . "  uid   : ${params['uid']}\n";
438                                 Logger::log($log_msg, Logger::DEBUG);
439                         } else {
440                                 // If not, just "follow" the thread.
441                                 $emailBuilder->setHeader('References', $message_id);
442                                 $emailBuilder->setHeader('In-Reply-To', $message_id);
443                                 Logger::log("There's already a notification for this parent.", Logger::DEBUG);
444                         }
445                 }
446
447                 $datarray = [
448                         'preamble'     => $preamble,
449                         'type'         => $params['type'],
450                         'parent'       => $parent_id,
451                         'source_name'  => $params['source_name'] ?? null,
452                         'source_link'  => $params['source_link'] ?? null,
453                         'source_photo' => $params['source_photo'] ?? null,
454                         'uid'          => $params['uid'],
455                         'hsitelink'    => $hsitelink,
456                         'tsitelink'    => $tsitelink,
457                         'itemlink'     => $itemlink,
458                         'title'        => $title,
459                         'body'         => $body,
460                         'subject'      => $subject,
461                         'headers'      => $emailBuilder->getHeaders(),
462                 ];
463
464                 Hook::callAll('enotify_mail', $datarray);
465
466                 $emailBuilder
467                         ->withHeaders($datarray['headers'])
468                         ->withRecipient($params['to_email'])
469                         ->forUser([
470                                 'uid' => $datarray['uid'],
471                                 'language' => $params['language'],
472                         ])
473                         ->withNotification($datarray['subject'], $datarray['preamble'], $datarray['title'], $datarray['body'])
474                         ->withSiteLink($datarray['tsitelink'], $datarray['hsitelink'])
475                         ->withItemLink($datarray['itemlink']);
476
477                 // If a photo is present, add it to the email
478                 if (!empty($datarray['source_photo'])) {
479                         $emailBuilder->withPhoto(
480                                 $datarray['source_photo'],
481                                 $datarray['source_link'] ?? $sitelink,
482                                 $datarray['source_name'] ?? $sitename);
483                 }
484
485                 $email = $emailBuilder->build();
486
487                 // use the Emailer class to send the message
488                 return DI::emailer()->send($email);
489         }
490
491         return false;
492 }
493
494 function notification_from_array(array $notification)
495 {
496         Logger::info('Start', ['uid' => $notification['uid'], 'id' => $notification['id'], 'type' => $notification['type']]);
497
498         if ($notification['type'] == Post\UserNotification::NOTIF_NONE) {
499                 Logger::info('Not an item based notification, quitting', ['uid' => $notification['uid'], 'id' => $notification['id'], 'type' => $notification['type']]);
500                 return false;
501         }
502
503         $params = [];
504         $params['verb'] = Verb::getByID($notification['vid']);
505
506         $params['uid']   = $notification['uid'];
507         $params['otype'] = Notification\ObjectType::ITEM;
508
509         $user = User::getById($notification['uid']);
510
511         $params['notify_flags'] = $user['notify-flags'];
512         $params['language']     = $user['language'];
513         $params['to_name']      = $user['username'];
514         $params['to_email']     = $user['email'];
515
516         // from here on everything is in the recipients language
517         $l10n = DI::l10n()->withLang($user['language']);
518
519         $contact = Contact::getById($notification['actor-id'], ['url', 'name', 'photo']);
520         if (DBA::isResult($contact)) {
521                 $params['source_link']  = $contact['url'];
522                 $params['source_name']  = $contact['name'];
523                 $params['source_photo'] = $contact['photo'];
524         }
525
526         $item = Post::selectFirstForUser($notification['uid'], Item::ITEM_FIELDLIST,
527                 ['uid' => [0, $notification['uid']], 'uri-id' => $notification['target-uri-id'], 'deleted' => false],
528                 ['order' => ['uid' => true]]);
529         if (empty($item)) {
530                 Logger::info('Item not found', ['uri-id' => $notification['target-uri-id'], 'type' => $notification['type']]);
531                 return false;
532         }
533
534         $params['item']   = $item;
535         $params['parent'] = $item['parent'];
536         $params['link']   = DI::baseUrl() . '/display/' . urlencode($item['guid']);
537
538         $subjectPrefix = $l10n->t('[Friendica:Notify]');
539
540         if (Post\ThreadUser::getIgnored($notification['parent-uri-id'], $notification['uid'])) {
541                 Logger::info('Thread is ignored', ['parent-uri-id' => $notification['parent-uri-id'], 'type' => $notification['type']]);
542                 return false;
543         }
544
545         // Check to see if there was already a tag notify or comment notify for this post.
546         // If so don't create a second notification
547         $condition = ['type' => [Notification\Type::TAG_SELF, Notification\Type::COMMENT, Notification\Type::SHARE],
548                 'link' => $params['link'], 'verb' => Activity::POST];
549         if (DI::notify()->existsForUser($notification['uid'], $condition)) {
550                 Logger::info('Duplicate found, quitting', $condition + ['uid' => $notification['uid']]);
551                 return false;
552         }
553
554         $content = Plaintext::getPost($item, 70);
555         if (!empty($content['text'])) {
556                 $title = '"' . trim(str_replace("\n", " ", $content['text'])) . '"';
557         } else {
558                 $title = $item['title'];
559         }
560
561         // Some mail software relies on subject field for threading.
562         // So, we cannot have different subjects for notifications of the same thread.
563         // Before this we have the name of the replier on the subject rendering
564         // different subjects for messages on the same thread.
565         if ($notification['type'] == Post\UserNotification::NOTIF_EXPLICIT_TAGGED) {
566                 $params['type'] = Notification\Type::TAG_SELF;
567                 $subject        = $l10n->t('%s %s tagged you', $subjectPrefix, $contact['name']);
568         } elseif ($notification['type'] == Post\UserNotification::NOTIF_SHARED) {
569                 $params['type'] = Notification\Type::SHARE;
570                 $subject        = $l10n->t('%s %s shared a new post', $subjectPrefix, $contact['name']);
571         } else {
572                 $params['type'] = Notification\Type::COMMENT;
573                 $subject        = $l10n->t('%1$s Comment to conversation #%2$d by %3$s', $subjectPrefix, $item['parent'], $contact['name']);
574         }
575
576         $msg = Notification::getMessage($notification);
577         if (empty($msg)) {
578                 Logger::info('No notification message, quitting', ['uid' => $notification['uid'], 'id' => $notification['id'], 'type' => $notification['type']]);
579                 return false;
580         }
581
582         $preamble  = $msg['plain'];
583         $epreamble = $msg['rich'];
584
585         $sitename = DI::config()->get('config', 'sitename');
586         $siteurl  = DI::baseUrl()->get(true);
587
588         $sitelink  = $l10n->t('Please visit %s to view and/or reply to the conversation.');
589         $tsitelink = sprintf($sitelink, $siteurl);
590         $hsitelink = sprintf($sitelink, '<a href="' . $siteurl . '">' . $sitename . '</a>');
591         $itemlink  = $params['link'];
592
593         Logger::info('Perform notification', ['uid' => $notification['uid'], 'id' => $notification['id'], 'type' => $notification['type']]);
594
595         return notification_store_and_send($params, $sitelink, $tsitelink, $hsitelink, $title, $subject, $preamble, $epreamble, $item['body'], $itemlink, true);
596 }