]> git.mxchange.org Git - friendica.git/blob - src/Navigation/Notifications/Factory/FormattedNotify.php
Fix link to post in notification
[friendica.git] / src / Navigation / Notifications / Factory / FormattedNotify.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2022, 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 namespace Friendica\Navigation\Notifications\Factory;
23
24 use Exception;
25 use Friendica\App\BaseURL;
26 use Friendica\BaseFactory;
27 use Friendica\Content\Text\BBCode;
28 use Friendica\Core\L10n;
29 use Friendica\Core\Protocol;
30 use Friendica\Database\Database;
31 use Friendica\Model\Contact;
32 use Friendica\Model\Post;
33 use Friendica\Module\BaseNotifications;
34 use Friendica\Navigation\Notifications\Collection\FormattedNotifies;
35 use Friendica\Navigation\Notifications\Repository;
36 use Friendica\Navigation\Notifications\ValueObject;
37 use Friendica\Network\HTTPException\InternalServerErrorException;
38 use Friendica\Protocol\Activity;
39 use Friendica\Util\DateTimeFormat;
40 use Friendica\Util\Proxy;
41 use Friendica\Util\Temporal;
42 use Friendica\Util\XML;
43 use Psr\Log\LoggerInterface;
44
45 /**
46  * Factory for creating notification objects based on items
47  * Currently, there are the following types of item based notifications:
48  * - network
49  * - system
50  * - home
51  * - personal
52  *
53  * @deprecated since 2022.05 Use \Friendica\Navigation\Notifications\Factory\FormattedNotification instead
54  */
55 class FormattedNotify extends BaseFactory
56 {
57         /** @var Database */
58         private $dba;
59         /** @var Repository\Notify */
60         private $notify;
61         /** @var BaseURL */
62         private $baseUrl;
63         /** @var L10n */
64         private $l10n;
65
66         public function __construct(LoggerInterface $logger, Database $dba, Repository\Notify $notification, BaseURL $baseUrl, L10n $l10n)
67         {
68                 parent::__construct($logger);
69
70                 $this->dba     = $dba;
71                 $this->notify  = $notification;
72                 $this->baseUrl = $baseUrl;
73                 $this->l10n    = $l10n;
74         }
75
76         /**
77          * @param array $formattedItem The return of $this->formatItem
78          *
79          * @return ValueObject\FormattedNotify
80          */
81         private function createFromFormattedItem(array $formattedItem): ValueObject\FormattedNotify
82         {
83                 // Transform the different types of notification in a usable array
84                 switch ($formattedItem['verb'] ?? '') {
85                         case Activity::LIKE:
86                                 return new ValueObject\FormattedNotify(
87                                         'like',
88                                         $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'],
89                                         $formattedItem['author-avatar'],
90                                         $formattedItem['author-link'],
91                                         $this->l10n->t("%s liked %s's post", $formattedItem['author-name'], $formattedItem['parent-author-name']),
92                                         $formattedItem['when'],
93                                         $formattedItem['ago'],
94                                         $formattedItem['seen']
95                                 );
96
97                         case Activity::DISLIKE:
98                                 return new ValueObject\FormattedNotify(
99                                         'dislike',
100                                         $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'],
101                                         $formattedItem['author-avatar'],
102                                         $formattedItem['author-link'],
103                                         $this->l10n->t("%s disliked %s's post", $formattedItem['author-name'], $formattedItem['parent-author-name']),
104                                         $formattedItem['when'],
105                                         $formattedItem['ago'],
106                                         $formattedItem['seen']
107                                 );
108
109                         case Activity::ATTEND:
110                                 return new ValueObject\FormattedNotify(
111                                         'attend',
112                                         $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'],
113                                         $formattedItem['author-avatar'],
114                                         $formattedItem['author-link'],
115                                         $this->l10n->t("%s is attending %s's event", $formattedItem['author-name'], $formattedItem['parent-author-name']),
116                                         $formattedItem['when'],
117                                         $formattedItem['ago'],
118                                         $formattedItem['seen']
119                                 );
120
121                         case Activity::ATTENDNO:
122                                 return new ValueObject\FormattedNotify(
123                                         'attendno',
124                                         $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'],
125                                         $formattedItem['author-avatar'],
126                                         $formattedItem['author-link'],
127                                         $this->l10n->t("%s is not attending %s's event", $formattedItem['author-name'], $formattedItem['parent-author-name']),
128                                         $formattedItem['when'],
129                                         $formattedItem['ago'],
130                                         $formattedItem['seen']
131                                 );
132
133                         case Activity::ATTENDMAYBE:
134                                 return new ValueObject\FormattedNotify(
135                                         'attendmaybe',
136                                         $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'],
137                                         $formattedItem['author-avatar'],
138                                         $formattedItem['author-link'],
139                                         $this->l10n->t("%s may attending %s's event", $formattedItem['author-name'], $formattedItem['parent-author-name']),
140                                         $formattedItem['when'],
141                                         $formattedItem['ago'],
142                                         $formattedItem['seen']
143                                 );
144
145                         case Activity::FRIEND:
146                                 if (!isset($formattedItem['object'])) {
147                                         return new ValueObject\FormattedNotify(
148                                                 'friend',
149                                                 $formattedItem['link'],
150                                                 $formattedItem['image'],
151                                                 $formattedItem['url'],
152                                                 $formattedItem['text'],
153                                                 $formattedItem['when'],
154                                                 $formattedItem['ago'],
155                                                 $formattedItem['seen']
156                                         );
157                                 }
158
159                                 $xmlHead = "<" . "?xml version='1.0' encoding='UTF-8' ?" . ">";
160                                 $obj     = XML::parseString($xmlHead . $formattedItem['object']);
161
162                                 $formattedItem['fname'] = $obj->title;
163
164                                 return new ValueObject\FormattedNotify(
165                                         'friend',
166                                         $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'],
167                                         $formattedItem['author-avatar'],
168                                         $formattedItem['author-link'],
169                                         $this->l10n->t("%s is now friends with %s", $formattedItem['author-name'], $formattedItem['fname']),
170                                         $formattedItem['when'],
171                                         $formattedItem['ago'],
172                                         $formattedItem['seen']
173                                 );
174
175                         default:
176                                 return new ValueObject\FormattedNotify(
177                                         $formattedItem['label'] ?? '',
178                                         $formattedItem['link'] ?? '',
179                                         $formattedItem['image'] ?? '',
180                                         $formattedItem['url'] ?? '',
181                                         $formattedItem['text'] ?? '',
182                                         $formattedItem['when'] ?? '',
183                                         $formattedItem['ago'] ?? '',
184                                         $formattedItem['seen'] ?? false
185                                 );
186                 }
187         }
188
189         /**
190          * Get system notifications
191          *
192          * @param bool $seen          False => only include notifications into the query
193          *                            which aren't marked as "seen"
194          * @param int  $start         Start the query at this point
195          * @param int  $limit         Maximum number of query results
196          *
197          * @return FormattedNotifies
198          */
199         public function getSystemList(bool $seen = false, int $start = 0, int $limit = BaseNotifications::DEFAULT_PAGE_LIMIT): FormattedNotifies
200         {
201                 $conditions = [];
202                 if (!$seen) {
203                         $conditions['seen'] = false;
204                 }
205
206                 $params          = [];
207                 $params['order'] = ['date' => 'DESC'];
208                 $params['limit'] = [$start, $limit];
209
210                 $formattedNotifications = new FormattedNotifies();
211                 try {
212                         $Notifies = $this->notify->selectForUser(local_user(), $conditions, $params);
213
214                         foreach ($Notifies as $Notify) {
215                                 $formattedNotifications[] = new ValueObject\FormattedNotify(
216                                         'notification',
217                                         $this->baseUrl->get(true) . '/notify/' . $Notify->id,
218                                         Contact::getAvatarUrlForUrl($Notify->url, $Notify->uid, Proxy::SIZE_MICRO),
219                                         $Notify->url,
220                                         strip_tags(BBCode::toPlaintext($Notify->msg)),
221                                         DateTimeFormat::local($Notify->date->format(DateTimeFormat::MYSQL), 'r'),
222                                         Temporal::getRelativeDate($Notify->date->format(DateTimeFormat::MYSQL)),
223                                         $Notify->seen
224                                 );
225                         }
226                 } catch (Exception $e) {
227                         $this->logger->warning('Select failed.', ['conditions' => $conditions, 'exception' => $e]);
228                 }
229
230                 return $formattedNotifications;
231         }
232
233         /**
234          * Get network notifications
235          *
236          * @param bool $seen          False => only include notifications into the query
237          *                            which aren't marked as "seen"
238          * @param int  $start         Start the query at this point
239          * @param int  $limit         Maximum number of query results
240          *
241          * @return FormattedNotifies
242          */
243         public function getNetworkList(bool $seen = false, int $start = 0, int $limit = BaseNotifications::DEFAULT_PAGE_LIMIT): FormattedNotifies
244         {
245                 $condition = ['wall' => false, 'uid' => local_user()];
246
247                 if (!$seen) {
248                         $condition['unseen'] = true;
249                 }
250
251                 $fields = ['id', 'parent', 'verb', 'author-name', 'unseen', 'author-link', 'author-avatar', 'contact-avatar',
252                         'network', 'created', 'object', 'parent-author-name', 'parent-author-link', 'parent-guid', 'gravity'];
253                 $params = ['order' => ['received' => true], 'limit' => [$start, $limit]];
254
255                 $formattedNotifications = new FormattedNotifies();
256
257                 try {
258                         $userPosts = Post::selectForUser(local_user(), $fields, $condition, $params);
259                         while ($userPost = $this->dba->fetch($userPosts)) {
260                                 $formattedNotifications[] = $this->createFromFormattedItem($this->formatItem($userPost));
261                         }
262                 } catch (Exception $e) {
263                         $this->logger->warning('Select failed.', ['condition' => $condition, 'exception' => $e]);
264                 }
265
266                 return $formattedNotifications;
267         }
268
269         /**
270          * Get personal notifications
271          *
272          * @param bool $seen          False => only include notifications into the query
273          *                            which aren't marked as "seen"
274          * @param int  $start         Start the query at this point
275          * @param int  $limit         Maximum number of query results
276          *
277          * @return FormattedNotifies
278          */
279         public function getPersonalList(bool $seen = false, int $start = 0, int $limit = BaseNotifications::DEFAULT_PAGE_LIMIT): FormattedNotifies
280         {
281                 $condition = ['wall' => false, 'uid' => local_user(), 'author-id' => public_contact()];
282
283                 if (!$seen) {
284                         $condition['unseen'] = true;
285                 }
286
287                 $fields = ['id', 'parent', 'verb', 'author-name', 'unseen', 'author-link', 'author-avatar', 'contact-avatar',
288                         'network', 'created', 'object', 'parent-author-name', 'parent-author-link', 'parent-guid', 'gravity'];
289                 $params = ['order' => ['received' => true], 'limit' => [$start, $limit]];
290
291                 $formattedNotifications = new FormattedNotifies();
292
293                 try {
294                         $userPosts = Post::selectForUser(local_user(), $fields, $condition, $params);
295                         while ($userPost = $this->dba->fetch($userPosts)) {
296                                 $formattedNotifications[] = $this->createFromFormattedItem($this->formatItem($userPost));
297                         }
298                 } catch (Exception $e) {
299                         $this->logger->warning('Select failed.', ['conditions' => $condition, 'exception' => $e]);
300                 }
301
302                 return $formattedNotifications;
303         }
304
305         /**
306          * Get home notifications
307          *
308          * @param bool $seen          False => only include notifications into the query
309          *                            which aren't marked as "seen"
310          * @param int  $start         Start the query at this point
311          * @param int  $limit         Maximum number of query results
312          *
313          * @return FormattedNotifies
314          */
315         public function getHomeList(bool $seen = false, int $start = 0, int $limit = BaseNotifications::DEFAULT_PAGE_LIMIT): FormattedNotifies
316         {
317                 $condition = ['wall' => true, 'uid' => local_user()];
318
319                 if (!$seen) {
320                         $condition['unseen'] = true;
321                 }
322
323                 $fields = ['id', 'parent', 'verb', 'author-name', 'unseen', 'author-link', 'author-avatar', 'contact-avatar',
324                         'network', 'created', 'object', 'parent-author-name', 'parent-author-link', 'parent-guid', 'gravity'];
325                 $params = ['order' => ['received' => true], 'limit' => [$start, $limit]];
326
327                 $formattedNotifications = new FormattedNotifies();
328
329                 try {
330                         $userPosts = Post::selectForUser(local_user(), $fields, $condition, $params);
331                         while ($userPost = $this->dba->fetch($userPosts)) {
332                                 $formattedItem = $this->formatItem($userPost);
333
334                                 // Overwrite specific fields, not default item format
335                                 $formattedItem['label'] = 'comment';
336                                 $formattedItem['text']  = $this->l10n->t("%s commented on %s's post", $formattedItem['author-name'], $formattedItem['parent-author-name']);
337
338                                 $formattedNotifications[] = $this->createFromFormattedItem($formattedItem);
339                         }
340                 } catch (Exception $e) {
341                         $this->logger->warning('Select failed.', ['conditions' => $condition, 'exception' => $e]);
342                 }
343
344                 return $formattedNotifications;
345         }
346
347         /**
348          * Format the item query in a usable array
349          *
350          * @param array $item The item from the db query
351          *
352          * @return array The item, extended with the notification-specific information
353          *
354          * @throws InternalServerErrorException
355          * @throws Exception
356          */
357         private function formatItem(array $item): array
358         {
359                 $item['seen'] = !($item['unseen'] > 0);
360
361                 // For feed items we use the user's contact, since the avatar is mostly self choosen.
362                 if (!empty($item['network']) && $item['network'] == Protocol::FEED) {
363                         $item['author-avatar'] = $item['contact-avatar'];
364                 }
365
366                 $item['label'] = (($item['gravity'] == GRAVITY_PARENT) ? 'post' : 'comment');
367                 $item['link']  = $this->baseUrl->get(true) . '/display/' . $item['parent-guid'];
368                 $item['image'] = $item['author-avatar'];
369                 $item['url']   = $item['author-link'];
370                 $item['when']  = DateTimeFormat::local($item['created'], 'r');
371                 $item['ago']   = Temporal::getRelativeDate($item['created']);
372                 $item['text']  = (($item['gravity'] == GRAVITY_PARENT)
373                         ? $this->l10n->t("%s created a new post", $item['author-name'])
374                         : $this->l10n->t("%s commented on %s's post", $item['author-name'], $item['parent-author-name']));
375
376                 return $item;
377         }
378 }