Completed
Push — master ( aef905...545552 )
by Joas
30:35 queued 01:00
created
lib/private/Notification/Manager.php 1 patch
Indentation   +408 added lines, -408 removed lines patch added patch discarded remove patch
@@ -29,412 +29,412 @@
 block discarded – undo
29 29
 use Psr\Log\LoggerInterface;
30 30
 
31 31
 class Manager implements IManager {
32
-	/** @var ICache */
33
-	protected ICache $cache;
34
-
35
-	/** @var IApp[] */
36
-	protected array $apps;
37
-	/** @var string[] */
38
-	protected array $appClasses;
39
-
40
-	/** @var INotifier[] */
41
-	protected array $notifiers;
42
-	/** @var string[] */
43
-	protected array $notifierClasses;
44
-
45
-	/** @var bool */
46
-	protected bool $preparingPushNotification;
47
-	/** @var bool */
48
-	protected bool $deferPushing;
49
-	/** @var bool */
50
-	private bool $parsedRegistrationContext;
51
-
52
-	public function __construct(
53
-		protected IValidator $validator,
54
-		private IUserManager $userManager,
55
-		ICacheFactory $cacheFactory,
56
-		protected IRegistry $subscription,
57
-		protected LoggerInterface $logger,
58
-		private Coordinator $coordinator,
59
-		private IRichTextFormatter $richTextFormatter,
60
-	) {
61
-		$this->cache = $cacheFactory->createDistributed('notifications');
62
-
63
-		$this->apps = [];
64
-		$this->notifiers = [];
65
-		$this->appClasses = [];
66
-		$this->notifierClasses = [];
67
-		$this->preparingPushNotification = false;
68
-		$this->deferPushing = false;
69
-		$this->parsedRegistrationContext = false;
70
-	}
71
-	/**
72
-	 * @param string $appClass The service must implement IApp, otherwise a
73
-	 *                         \InvalidArgumentException is thrown later
74
-	 * @since 17.0.0
75
-	 */
76
-	public function registerApp(string $appClass): void {
77
-		// other apps may want to rely on the 'main' notification app so make it deterministic that
78
-		// the 'main' notification app adds it's notifications first and removes it's notifications last
79
-		if ($appClass === \OCA\Notifications\App::class) {
80
-			// add 'main' notifications app to start of internal list of apps
81
-			array_unshift($this->appClasses, $appClass);
82
-		} else {
83
-			// add app to end of internal list of apps
84
-			$this->appClasses[] = $appClass;
85
-		}
86
-	}
87
-
88
-	/**
89
-	 * @param \Closure $service The service must implement INotifier, otherwise a
90
-	 *                          \InvalidArgumentException is thrown later
91
-	 * @param \Closure $info An array with the keys 'id' and 'name' containing
92
-	 *                       the app id and the app name
93
-	 * @deprecated 17.0.0 use registerNotifierService instead.
94
-	 * @since 8.2.0 - Parameter $info was added in 9.0.0
95
-	 */
96
-	public function registerNotifier(\Closure $service, \Closure $info): void {
97
-		$infoData = $info();
98
-		$exception = new \InvalidArgumentException(
99
-			'Notifier ' . $infoData['name'] . ' (id: ' . $infoData['id'] . ') is not considered because it is using the old way to register.'
100
-		);
101
-		$this->logger->error($exception->getMessage(), ['exception' => $exception]);
102
-	}
103
-
104
-	/**
105
-	 * @param string $notifierService The service must implement INotifier, otherwise a
106
-	 *                                \InvalidArgumentException is thrown later
107
-	 * @since 17.0.0
108
-	 */
109
-	public function registerNotifierService(string $notifierService): void {
110
-		$this->notifierClasses[] = $notifierService;
111
-	}
112
-
113
-	/**
114
-	 * @return IApp[]
115
-	 */
116
-	protected function getApps(): array {
117
-		if (empty($this->appClasses)) {
118
-			return $this->apps;
119
-		}
120
-
121
-		foreach ($this->appClasses as $appClass) {
122
-			try {
123
-				$app = \OC::$server->get($appClass);
124
-			} catch (ContainerExceptionInterface $e) {
125
-				$this->logger->error('Failed to load notification app class: ' . $appClass, [
126
-					'exception' => $e,
127
-					'app' => 'notifications',
128
-				]);
129
-				continue;
130
-			}
131
-
132
-			if (!($app instanceof IApp)) {
133
-				$this->logger->error('Notification app class ' . $appClass . ' is not implementing ' . IApp::class, [
134
-					'app' => 'notifications',
135
-				]);
136
-				continue;
137
-			}
138
-
139
-			$this->apps[] = $app;
140
-		}
141
-
142
-		$this->appClasses = [];
143
-
144
-		return $this->apps;
145
-	}
146
-
147
-	/**
148
-	 * @return INotifier[]
149
-	 */
150
-	public function getNotifiers(): array {
151
-		if (!$this->parsedRegistrationContext) {
152
-			$notifierServices = $this->coordinator->getRegistrationContext()->getNotifierServices();
153
-			foreach ($notifierServices as $notifierService) {
154
-				try {
155
-					$notifier = \OC::$server->get($notifierService->getService());
156
-				} catch (ContainerExceptionInterface $e) {
157
-					$this->logger->error('Failed to load notification notifier class: ' . $notifierService->getService(), [
158
-						'exception' => $e,
159
-						'app' => 'notifications',
160
-					]);
161
-					continue;
162
-				}
163
-
164
-				if (!($notifier instanceof INotifier)) {
165
-					$this->logger->error('Notification notifier class ' . $notifierService->getService() . ' is not implementing ' . INotifier::class, [
166
-						'app' => 'notifications',
167
-					]);
168
-					continue;
169
-				}
170
-
171
-				$this->notifiers[] = $notifier;
172
-			}
173
-
174
-			$this->parsedRegistrationContext = true;
175
-		}
176
-
177
-		if (empty($this->notifierClasses)) {
178
-			return $this->notifiers;
179
-		}
180
-
181
-		foreach ($this->notifierClasses as $notifierClass) {
182
-			try {
183
-				$notifier = \OC::$server->get($notifierClass);
184
-			} catch (ContainerExceptionInterface $e) {
185
-				$this->logger->error('Failed to load notification notifier class: ' . $notifierClass, [
186
-					'exception' => $e,
187
-					'app' => 'notifications',
188
-				]);
189
-				continue;
190
-			}
191
-
192
-			if (!($notifier instanceof INotifier)) {
193
-				$this->logger->error('Notification notifier class ' . $notifierClass . ' is not implementing ' . INotifier::class, [
194
-					'app' => 'notifications',
195
-				]);
196
-				continue;
197
-			}
198
-
199
-			$this->notifiers[] = $notifier;
200
-		}
201
-
202
-		$this->notifierClasses = [];
203
-
204
-		return $this->notifiers;
205
-	}
206
-
207
-	/**
208
-	 * @return INotification
209
-	 * @since 8.2.0
210
-	 */
211
-	public function createNotification(): INotification {
212
-		return new Notification($this->validator, $this->richTextFormatter);
213
-	}
214
-
215
-	/**
216
-	 * @return bool
217
-	 * @since 8.2.0
218
-	 */
219
-	public function hasNotifiers(): bool {
220
-		return !empty($this->notifiers)
221
-			|| !empty($this->notifierClasses)
222
-			|| (!$this->parsedRegistrationContext && !empty($this->coordinator->getRegistrationContext()->getNotifierServices()));
223
-	}
224
-
225
-	/**
226
-	 * @param bool $preparingPushNotification
227
-	 * @since 14.0.0
228
-	 */
229
-	public function setPreparingPushNotification(bool $preparingPushNotification): void {
230
-		$this->preparingPushNotification = $preparingPushNotification;
231
-	}
232
-
233
-	/**
234
-	 * @return bool
235
-	 * @since 14.0.0
236
-	 */
237
-	public function isPreparingPushNotification(): bool {
238
-		return $this->preparingPushNotification;
239
-	}
240
-
241
-	/**
242
-	 * The calling app should only "flush" when it got returned true on the defer call
243
-	 * @return bool
244
-	 * @since 20.0.0
245
-	 */
246
-	public function defer(): bool {
247
-		$alreadyDeferring = $this->deferPushing;
248
-		$this->deferPushing = true;
249
-
250
-		$apps = array_reverse($this->getApps());
251
-
252
-		foreach ($apps as $app) {
253
-			if ($app instanceof IDeferrableApp) {
254
-				$app->defer();
255
-			}
256
-		}
257
-
258
-		return !$alreadyDeferring;
259
-	}
260
-
261
-	/**
262
-	 * @since 20.0.0
263
-	 */
264
-	public function flush(): void {
265
-		$apps = array_reverse($this->getApps());
266
-
267
-		foreach ($apps as $app) {
268
-			if (!$app instanceof IDeferrableApp) {
269
-				continue;
270
-			}
271
-
272
-			try {
273
-				$app->flush();
274
-			} catch (\InvalidArgumentException $e) {
275
-			}
276
-		}
277
-
278
-		$this->deferPushing = false;
279
-	}
280
-
281
-	/**
282
-	 * {@inheritDoc}
283
-	 */
284
-	public function isFairUseOfFreePushService(): bool {
285
-		$pushAllowed = $this->cache->get('push_fair_use');
286
-		if ($pushAllowed === null) {
287
-			/**
288
-			 * We want to keep offering our push notification service for free, but large
289
-			 * users overload our infrastructure. For this reason we have to rate-limit the
290
-			 * use of push notifications. If you need this feature, consider using Nextcloud Enterprise.
291
-			 */
292
-			$isFairUse = $this->subscription->delegateHasValidSubscription() || $this->userManager->countSeenUsers() < 1000;
293
-			$pushAllowed = $isFairUse ? 'yes' : 'no';
294
-			$this->cache->set('push_fair_use', $pushAllowed, 3600);
295
-		}
296
-		return $pushAllowed === 'yes';
297
-	}
298
-
299
-	/**
300
-	 * {@inheritDoc}
301
-	 */
302
-	public function notify(INotification $notification): void {
303
-		if (!$notification->isValid()) {
304
-			throw new IncompleteNotificationException('The given notification is invalid');
305
-		}
306
-
307
-		$apps = $this->getApps();
308
-
309
-		foreach ($apps as $app) {
310
-			try {
311
-				$app->notify($notification);
312
-			} catch (IncompleteNotificationException) {
313
-			} catch (\InvalidArgumentException $e) {
314
-				// todo 33.0.0 Log as warning
315
-				// todo 39.0.0 Log as error
316
-				$this->logger->debug(get_class($app) . '::notify() threw \InvalidArgumentException which is deprecated. Throw \OCP\Notification\IncompleteNotificationException when the notification is incomplete for your app and otherwise handle all \InvalidArgumentException yourself.');
317
-			}
318
-		}
319
-	}
320
-
321
-	/**
322
-	 * Identifier of the notifier, only use [a-z0-9_]
323
-	 *
324
-	 * @return string
325
-	 * @since 17.0.0
326
-	 */
327
-	public function getID(): string {
328
-		return 'core';
329
-	}
330
-
331
-	/**
332
-	 * Human readable name describing the notifier
333
-	 *
334
-	 * @return string
335
-	 * @since 17.0.0
336
-	 */
337
-	public function getName(): string {
338
-		return 'core';
339
-	}
340
-
341
-	/**
342
-	 * {@inheritDoc}
343
-	 */
344
-	public function prepare(INotification $notification, string $languageCode): INotification {
345
-		$notifiers = $this->getNotifiers();
346
-
347
-		foreach ($notifiers as $notifier) {
348
-			try {
349
-				$notification = $notifier->prepare($notification, $languageCode);
350
-			} catch (AlreadyProcessedException $e) {
351
-				$this->markProcessed($notification);
352
-				throw $e;
353
-			} catch (UnknownNotificationException) {
354
-				continue;
355
-			} catch (\InvalidArgumentException $e) {
356
-				// todo 33.0.0 Log as warning
357
-				// todo 39.0.0 Log as error
358
-				$this->logger->debug(get_class($notifier) . '::prepare() threw \InvalidArgumentException which is deprecated. Throw \OCP\Notification\UnknownNotificationException when the notification is not known to your notifier and otherwise handle all \InvalidArgumentException yourself.');
359
-				continue;
360
-			}
361
-
362
-			if (!$notification->isValidParsed()) {
363
-				$this->logger->info('Notification was claimed to be parsed, but was not fully parsed by ' . get_class($notifier) . ' [app: ' . $notification->getApp() . ', subject: ' . $notification->getSubject() . ']');
364
-				throw new IncompleteParsedNotificationException();
365
-			}
366
-		}
367
-
368
-		if (!$notification->isValidParsed()) {
369
-			$this->logger->info('Notification was not parsed by any notifier [app: ' . $notification->getApp() . ', subject: ' . $notification->getSubject() . ']');
370
-			throw new IncompleteParsedNotificationException();
371
-		}
372
-
373
-		$link = $notification->getLink();
374
-		if ($link !== '' && !str_starts_with($link, 'http://') && !str_starts_with($link, 'https://')) {
375
-			$this->logger->warning('Link of notification is not an absolute URL and does not work in mobile and desktop clients [app: ' . $notification->getApp() . ', subject: ' . $notification->getSubject() . ']');
376
-		}
377
-
378
-		$icon = $notification->getIcon();
379
-		if ($icon !== '' && !str_starts_with($icon, 'http://') && !str_starts_with($icon, 'https://')) {
380
-			$this->logger->warning('Icon of notification is not an absolute URL and does not work in mobile and desktop clients [app: ' . $notification->getApp() . ', subject: ' . $notification->getSubject() . ']');
381
-		}
382
-
383
-		foreach ($notification->getParsedActions() as $action) {
384
-			$link = $action->getLink();
385
-			if ($link !== '' && !str_starts_with($link, 'http://') && !str_starts_with($link, 'https://')) {
386
-				$this->logger->warning('Link of action is not an absolute URL and does not work in mobile and desktop clients [app: ' . $notification->getApp() . ', subject: ' . $notification->getSubject() . ']');
387
-			}
388
-		}
389
-
390
-		return $notification;
391
-	}
392
-
393
-	/**
394
-	 * @param INotification $notification
395
-	 */
396
-	public function markProcessed(INotification $notification): void {
397
-		$apps = array_reverse($this->getApps());
398
-
399
-		foreach ($apps as $app) {
400
-			$app->markProcessed($notification);
401
-		}
402
-	}
403
-
404
-	/**
405
-	 * @param INotification $notification
406
-	 * @return int
407
-	 */
408
-	public function getCount(INotification $notification): int {
409
-		$apps = array_reverse($this->getApps());
410
-
411
-		$count = 0;
412
-		foreach ($apps as $app) {
413
-			$count += $app->getCount($notification);
414
-		}
415
-
416
-		return $count;
417
-	}
418
-
419
-	/**
420
-	 * {@inheritDoc}
421
-	 */
422
-	public function dismissNotification(INotification $notification): void {
423
-		$notifiers = $this->getNotifiers();
424
-
425
-		foreach ($notifiers as $notifier) {
426
-			if ($notifier instanceof IDismissableNotifier) {
427
-				try {
428
-					$notifier->dismissNotification($notification);
429
-				} catch (UnknownNotificationException) {
430
-					continue;
431
-				} catch (\InvalidArgumentException $e) {
432
-					// todo 33.0.0 Log as warning
433
-					// todo 39.0.0 Log as error
434
-					$this->logger->debug(get_class($notifier) . '::dismissNotification() threw \InvalidArgumentException which is deprecated. Throw \OCP\Notification\UnknownNotificationException when the notification is not known to your notifier and otherwise handle all \InvalidArgumentException yourself.');
435
-					continue;
436
-				}
437
-			}
438
-		}
439
-	}
32
+    /** @var ICache */
33
+    protected ICache $cache;
34
+
35
+    /** @var IApp[] */
36
+    protected array $apps;
37
+    /** @var string[] */
38
+    protected array $appClasses;
39
+
40
+    /** @var INotifier[] */
41
+    protected array $notifiers;
42
+    /** @var string[] */
43
+    protected array $notifierClasses;
44
+
45
+    /** @var bool */
46
+    protected bool $preparingPushNotification;
47
+    /** @var bool */
48
+    protected bool $deferPushing;
49
+    /** @var bool */
50
+    private bool $parsedRegistrationContext;
51
+
52
+    public function __construct(
53
+        protected IValidator $validator,
54
+        private IUserManager $userManager,
55
+        ICacheFactory $cacheFactory,
56
+        protected IRegistry $subscription,
57
+        protected LoggerInterface $logger,
58
+        private Coordinator $coordinator,
59
+        private IRichTextFormatter $richTextFormatter,
60
+    ) {
61
+        $this->cache = $cacheFactory->createDistributed('notifications');
62
+
63
+        $this->apps = [];
64
+        $this->notifiers = [];
65
+        $this->appClasses = [];
66
+        $this->notifierClasses = [];
67
+        $this->preparingPushNotification = false;
68
+        $this->deferPushing = false;
69
+        $this->parsedRegistrationContext = false;
70
+    }
71
+    /**
72
+     * @param string $appClass The service must implement IApp, otherwise a
73
+     *                         \InvalidArgumentException is thrown later
74
+     * @since 17.0.0
75
+     */
76
+    public function registerApp(string $appClass): void {
77
+        // other apps may want to rely on the 'main' notification app so make it deterministic that
78
+        // the 'main' notification app adds it's notifications first and removes it's notifications last
79
+        if ($appClass === \OCA\Notifications\App::class) {
80
+            // add 'main' notifications app to start of internal list of apps
81
+            array_unshift($this->appClasses, $appClass);
82
+        } else {
83
+            // add app to end of internal list of apps
84
+            $this->appClasses[] = $appClass;
85
+        }
86
+    }
87
+
88
+    /**
89
+     * @param \Closure $service The service must implement INotifier, otherwise a
90
+     *                          \InvalidArgumentException is thrown later
91
+     * @param \Closure $info An array with the keys 'id' and 'name' containing
92
+     *                       the app id and the app name
93
+     * @deprecated 17.0.0 use registerNotifierService instead.
94
+     * @since 8.2.0 - Parameter $info was added in 9.0.0
95
+     */
96
+    public function registerNotifier(\Closure $service, \Closure $info): void {
97
+        $infoData = $info();
98
+        $exception = new \InvalidArgumentException(
99
+            'Notifier ' . $infoData['name'] . ' (id: ' . $infoData['id'] . ') is not considered because it is using the old way to register.'
100
+        );
101
+        $this->logger->error($exception->getMessage(), ['exception' => $exception]);
102
+    }
103
+
104
+    /**
105
+     * @param string $notifierService The service must implement INotifier, otherwise a
106
+     *                                \InvalidArgumentException is thrown later
107
+     * @since 17.0.0
108
+     */
109
+    public function registerNotifierService(string $notifierService): void {
110
+        $this->notifierClasses[] = $notifierService;
111
+    }
112
+
113
+    /**
114
+     * @return IApp[]
115
+     */
116
+    protected function getApps(): array {
117
+        if (empty($this->appClasses)) {
118
+            return $this->apps;
119
+        }
120
+
121
+        foreach ($this->appClasses as $appClass) {
122
+            try {
123
+                $app = \OC::$server->get($appClass);
124
+            } catch (ContainerExceptionInterface $e) {
125
+                $this->logger->error('Failed to load notification app class: ' . $appClass, [
126
+                    'exception' => $e,
127
+                    'app' => 'notifications',
128
+                ]);
129
+                continue;
130
+            }
131
+
132
+            if (!($app instanceof IApp)) {
133
+                $this->logger->error('Notification app class ' . $appClass . ' is not implementing ' . IApp::class, [
134
+                    'app' => 'notifications',
135
+                ]);
136
+                continue;
137
+            }
138
+
139
+            $this->apps[] = $app;
140
+        }
141
+
142
+        $this->appClasses = [];
143
+
144
+        return $this->apps;
145
+    }
146
+
147
+    /**
148
+     * @return INotifier[]
149
+     */
150
+    public function getNotifiers(): array {
151
+        if (!$this->parsedRegistrationContext) {
152
+            $notifierServices = $this->coordinator->getRegistrationContext()->getNotifierServices();
153
+            foreach ($notifierServices as $notifierService) {
154
+                try {
155
+                    $notifier = \OC::$server->get($notifierService->getService());
156
+                } catch (ContainerExceptionInterface $e) {
157
+                    $this->logger->error('Failed to load notification notifier class: ' . $notifierService->getService(), [
158
+                        'exception' => $e,
159
+                        'app' => 'notifications',
160
+                    ]);
161
+                    continue;
162
+                }
163
+
164
+                if (!($notifier instanceof INotifier)) {
165
+                    $this->logger->error('Notification notifier class ' . $notifierService->getService() . ' is not implementing ' . INotifier::class, [
166
+                        'app' => 'notifications',
167
+                    ]);
168
+                    continue;
169
+                }
170
+
171
+                $this->notifiers[] = $notifier;
172
+            }
173
+
174
+            $this->parsedRegistrationContext = true;
175
+        }
176
+
177
+        if (empty($this->notifierClasses)) {
178
+            return $this->notifiers;
179
+        }
180
+
181
+        foreach ($this->notifierClasses as $notifierClass) {
182
+            try {
183
+                $notifier = \OC::$server->get($notifierClass);
184
+            } catch (ContainerExceptionInterface $e) {
185
+                $this->logger->error('Failed to load notification notifier class: ' . $notifierClass, [
186
+                    'exception' => $e,
187
+                    'app' => 'notifications',
188
+                ]);
189
+                continue;
190
+            }
191
+
192
+            if (!($notifier instanceof INotifier)) {
193
+                $this->logger->error('Notification notifier class ' . $notifierClass . ' is not implementing ' . INotifier::class, [
194
+                    'app' => 'notifications',
195
+                ]);
196
+                continue;
197
+            }
198
+
199
+            $this->notifiers[] = $notifier;
200
+        }
201
+
202
+        $this->notifierClasses = [];
203
+
204
+        return $this->notifiers;
205
+    }
206
+
207
+    /**
208
+     * @return INotification
209
+     * @since 8.2.0
210
+     */
211
+    public function createNotification(): INotification {
212
+        return new Notification($this->validator, $this->richTextFormatter);
213
+    }
214
+
215
+    /**
216
+     * @return bool
217
+     * @since 8.2.0
218
+     */
219
+    public function hasNotifiers(): bool {
220
+        return !empty($this->notifiers)
221
+            || !empty($this->notifierClasses)
222
+            || (!$this->parsedRegistrationContext && !empty($this->coordinator->getRegistrationContext()->getNotifierServices()));
223
+    }
224
+
225
+    /**
226
+     * @param bool $preparingPushNotification
227
+     * @since 14.0.0
228
+     */
229
+    public function setPreparingPushNotification(bool $preparingPushNotification): void {
230
+        $this->preparingPushNotification = $preparingPushNotification;
231
+    }
232
+
233
+    /**
234
+     * @return bool
235
+     * @since 14.0.0
236
+     */
237
+    public function isPreparingPushNotification(): bool {
238
+        return $this->preparingPushNotification;
239
+    }
240
+
241
+    /**
242
+     * The calling app should only "flush" when it got returned true on the defer call
243
+     * @return bool
244
+     * @since 20.0.0
245
+     */
246
+    public function defer(): bool {
247
+        $alreadyDeferring = $this->deferPushing;
248
+        $this->deferPushing = true;
249
+
250
+        $apps = array_reverse($this->getApps());
251
+
252
+        foreach ($apps as $app) {
253
+            if ($app instanceof IDeferrableApp) {
254
+                $app->defer();
255
+            }
256
+        }
257
+
258
+        return !$alreadyDeferring;
259
+    }
260
+
261
+    /**
262
+     * @since 20.0.0
263
+     */
264
+    public function flush(): void {
265
+        $apps = array_reverse($this->getApps());
266
+
267
+        foreach ($apps as $app) {
268
+            if (!$app instanceof IDeferrableApp) {
269
+                continue;
270
+            }
271
+
272
+            try {
273
+                $app->flush();
274
+            } catch (\InvalidArgumentException $e) {
275
+            }
276
+        }
277
+
278
+        $this->deferPushing = false;
279
+    }
280
+
281
+    /**
282
+     * {@inheritDoc}
283
+     */
284
+    public function isFairUseOfFreePushService(): bool {
285
+        $pushAllowed = $this->cache->get('push_fair_use');
286
+        if ($pushAllowed === null) {
287
+            /**
288
+             * We want to keep offering our push notification service for free, but large
289
+             * users overload our infrastructure. For this reason we have to rate-limit the
290
+             * use of push notifications. If you need this feature, consider using Nextcloud Enterprise.
291
+             */
292
+            $isFairUse = $this->subscription->delegateHasValidSubscription() || $this->userManager->countSeenUsers() < 1000;
293
+            $pushAllowed = $isFairUse ? 'yes' : 'no';
294
+            $this->cache->set('push_fair_use', $pushAllowed, 3600);
295
+        }
296
+        return $pushAllowed === 'yes';
297
+    }
298
+
299
+    /**
300
+     * {@inheritDoc}
301
+     */
302
+    public function notify(INotification $notification): void {
303
+        if (!$notification->isValid()) {
304
+            throw new IncompleteNotificationException('The given notification is invalid');
305
+        }
306
+
307
+        $apps = $this->getApps();
308
+
309
+        foreach ($apps as $app) {
310
+            try {
311
+                $app->notify($notification);
312
+            } catch (IncompleteNotificationException) {
313
+            } catch (\InvalidArgumentException $e) {
314
+                // todo 33.0.0 Log as warning
315
+                // todo 39.0.0 Log as error
316
+                $this->logger->debug(get_class($app) . '::notify() threw \InvalidArgumentException which is deprecated. Throw \OCP\Notification\IncompleteNotificationException when the notification is incomplete for your app and otherwise handle all \InvalidArgumentException yourself.');
317
+            }
318
+        }
319
+    }
320
+
321
+    /**
322
+     * Identifier of the notifier, only use [a-z0-9_]
323
+     *
324
+     * @return string
325
+     * @since 17.0.0
326
+     */
327
+    public function getID(): string {
328
+        return 'core';
329
+    }
330
+
331
+    /**
332
+     * Human readable name describing the notifier
333
+     *
334
+     * @return string
335
+     * @since 17.0.0
336
+     */
337
+    public function getName(): string {
338
+        return 'core';
339
+    }
340
+
341
+    /**
342
+     * {@inheritDoc}
343
+     */
344
+    public function prepare(INotification $notification, string $languageCode): INotification {
345
+        $notifiers = $this->getNotifiers();
346
+
347
+        foreach ($notifiers as $notifier) {
348
+            try {
349
+                $notification = $notifier->prepare($notification, $languageCode);
350
+            } catch (AlreadyProcessedException $e) {
351
+                $this->markProcessed($notification);
352
+                throw $e;
353
+            } catch (UnknownNotificationException) {
354
+                continue;
355
+            } catch (\InvalidArgumentException $e) {
356
+                // todo 33.0.0 Log as warning
357
+                // todo 39.0.0 Log as error
358
+                $this->logger->debug(get_class($notifier) . '::prepare() threw \InvalidArgumentException which is deprecated. Throw \OCP\Notification\UnknownNotificationException when the notification is not known to your notifier and otherwise handle all \InvalidArgumentException yourself.');
359
+                continue;
360
+            }
361
+
362
+            if (!$notification->isValidParsed()) {
363
+                $this->logger->info('Notification was claimed to be parsed, but was not fully parsed by ' . get_class($notifier) . ' [app: ' . $notification->getApp() . ', subject: ' . $notification->getSubject() . ']');
364
+                throw new IncompleteParsedNotificationException();
365
+            }
366
+        }
367
+
368
+        if (!$notification->isValidParsed()) {
369
+            $this->logger->info('Notification was not parsed by any notifier [app: ' . $notification->getApp() . ', subject: ' . $notification->getSubject() . ']');
370
+            throw new IncompleteParsedNotificationException();
371
+        }
372
+
373
+        $link = $notification->getLink();
374
+        if ($link !== '' && !str_starts_with($link, 'http://') && !str_starts_with($link, 'https://')) {
375
+            $this->logger->warning('Link of notification is not an absolute URL and does not work in mobile and desktop clients [app: ' . $notification->getApp() . ', subject: ' . $notification->getSubject() . ']');
376
+        }
377
+
378
+        $icon = $notification->getIcon();
379
+        if ($icon !== '' && !str_starts_with($icon, 'http://') && !str_starts_with($icon, 'https://')) {
380
+            $this->logger->warning('Icon of notification is not an absolute URL and does not work in mobile and desktop clients [app: ' . $notification->getApp() . ', subject: ' . $notification->getSubject() . ']');
381
+        }
382
+
383
+        foreach ($notification->getParsedActions() as $action) {
384
+            $link = $action->getLink();
385
+            if ($link !== '' && !str_starts_with($link, 'http://') && !str_starts_with($link, 'https://')) {
386
+                $this->logger->warning('Link of action is not an absolute URL and does not work in mobile and desktop clients [app: ' . $notification->getApp() . ', subject: ' . $notification->getSubject() . ']');
387
+            }
388
+        }
389
+
390
+        return $notification;
391
+    }
392
+
393
+    /**
394
+     * @param INotification $notification
395
+     */
396
+    public function markProcessed(INotification $notification): void {
397
+        $apps = array_reverse($this->getApps());
398
+
399
+        foreach ($apps as $app) {
400
+            $app->markProcessed($notification);
401
+        }
402
+    }
403
+
404
+    /**
405
+     * @param INotification $notification
406
+     * @return int
407
+     */
408
+    public function getCount(INotification $notification): int {
409
+        $apps = array_reverse($this->getApps());
410
+
411
+        $count = 0;
412
+        foreach ($apps as $app) {
413
+            $count += $app->getCount($notification);
414
+        }
415
+
416
+        return $count;
417
+    }
418
+
419
+    /**
420
+     * {@inheritDoc}
421
+     */
422
+    public function dismissNotification(INotification $notification): void {
423
+        $notifiers = $this->getNotifiers();
424
+
425
+        foreach ($notifiers as $notifier) {
426
+            if ($notifier instanceof IDismissableNotifier) {
427
+                try {
428
+                    $notifier->dismissNotification($notification);
429
+                } catch (UnknownNotificationException) {
430
+                    continue;
431
+                } catch (\InvalidArgumentException $e) {
432
+                    // todo 33.0.0 Log as warning
433
+                    // todo 39.0.0 Log as error
434
+                    $this->logger->debug(get_class($notifier) . '::dismissNotification() threw \InvalidArgumentException which is deprecated. Throw \OCP\Notification\UnknownNotificationException when the notification is not known to your notifier and otherwise handle all \InvalidArgumentException yourself.');
435
+                    continue;
436
+                }
437
+            }
438
+        }
439
+    }
440 440
 }
Please login to merge, or discard this patch.