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