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