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