Passed
Push — master ( 5aacb4...da571c )
by Christoph
11:08 queued 10s
created

Manager::setPreparingPushNotification()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @copyright Copyright (c) 2016, ownCloud, Inc.
7
 *
8
 * @author Joas Schilling <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 *
11
 * @license AGPL-3.0
12
 *
13
 * This code is free software: you can redistribute it and/or modify
14
 * it under the terms of the GNU Affero General Public License, version 3,
15
 * as published by the Free Software Foundation.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License, version 3,
23
 * along with this program. If not, see <http://www.gnu.org/licenses/>
24
 *
25
 */
26
27
namespace OC\Notification;
28
29
30
use OCP\AppFramework\QueryException;
31
use OCP\ILogger;
32
use OCP\Notification\AlreadyProcessedException;
33
use OCP\Notification\IApp;
34
use OCP\Notification\IDismissableNotifier;
35
use OCP\Notification\IManager;
36
use OCP\Notification\INotification;
37
use OCP\Notification\INotifier;
38
use OCP\RichObjectStrings\IValidator;
39
40
class Manager implements IManager {
41
	/** @var IValidator */
42
	protected $validator;
43
	/** @var ILogger */
44
	protected $logger;
45
46
	/** @var IApp[] */
47
	protected $apps;
48
	/** @var string[] */
49
	protected $appClasses;
50
51
	/** @var INotifier[] */
52
	protected $notifiers;
53
	/** @var string[] */
54
	protected $notifierClasses;
55
56
	/** @var bool */
57
	protected $preparingPushNotification;
58
59
	public function __construct(IValidator $validator,
60
								ILogger $logger) {
61
		$this->validator = $validator;
62
		$this->logger = $logger;
63
		$this->apps = [];
64
		$this->notifiers = [];
65
		$this->appClasses = [];
66
		$this->notifierClasses = [];
67
		$this->preparingPushNotification = false;
68
	}
69
	/**
70
	 * @param string $appClass The service must implement IApp, otherwise a
71
	 *                          \InvalidArgumentException is thrown later
72
	 * @since 17.0.0
73
	 */
74
	public function registerApp(string $appClass): void {
75
		$this->appClasses[] = $appClass;
76
	}
77
78
	/**
79
	 * @param \Closure $service The service must implement INotifier, otherwise a
80
	 *                          \InvalidArgumentException is thrown later
81
	 * @param \Closure $info    An array with the keys 'id' and 'name' containing
82
	 *                          the app id and the app name
83
	 * @deprecated 17.0.0 use registerNotifierService instead.
84
	 * @since 8.2.0 - Parameter $info was added in 9.0.0
85
	 */
86
	public function registerNotifier(\Closure $service, \Closure $info) {
87
		$infoData = $info();
88
		$this->logger->logException(new \InvalidArgumentException(
89
			'Notifier ' . $infoData['name'] . ' (id: ' . $infoData['id'] . ') is not considered because it is using the old way to register.'
90
		));
91
	}
92
93
	/**
94
	 * @param string $notifierService The service must implement INotifier, otherwise a
95
	 *                          \InvalidArgumentException is thrown later
96
	 * @since 17.0.0
97
	 */
98
	public function registerNotifierService(string $notifierService): void {
99
		$this->notifierClasses[] = $notifierService;
100
	}
101
102
	/**
103
	 * @return IApp[]
104
	 */
105
	protected function getApps(): array {
106
		if (empty($this->appClasses)) {
107
			return $this->apps;
108
		}
109
110
		foreach ($this->appClasses as $appClass) {
111
			try {
112
				$app = \OC::$server->query($appClass);
113
			} catch (QueryException $e) {
114
				$this->logger->logException($e, [
115
					'message' => 'Failed to load notification app class: ' . $appClass,
116
					'app' => 'notifications',
117
				]);
118
				continue;
119
			}
120
121
			if (!($app instanceof IApp)) {
122
				$this->logger->error('Notification app class ' . $appClass . ' is not implementing ' . IApp::class, [
123
					'app' => 'notifications',
124
				]);
125
				continue;
126
			}
127
128
			$this->apps[] = $app;
129
		}
130
131
		$this->appClasses = [];
132
133
		return $this->apps;
134
	}
135
136
	/**
137
	 * @return INotifier[]
138
	 */
139
	public function getNotifiers(): array {
140
		if (empty($this->notifierClasses)) {
141
			return $this->notifiers;
142
		}
143
144
		foreach ($this->notifierClasses as $notifierClass) {
145
			try {
146
				$notifier = \OC::$server->query($notifierClass);
147
			} catch (QueryException $e) {
148
				$this->logger->logException($e, [
149
					'message' => 'Failed to load notification notifier class: ' . $notifierClass,
150
					'app' => 'notifications',
151
				]);
152
				continue;
153
			}
154
155
			if (!($notifier instanceof INotifier)) {
156
				$this->logger->error('Notification notifier class ' . $notifierClass . ' is not implementing ' . INotifier::class, [
157
					'app' => 'notifications',
158
				]);
159
				continue;
160
			}
161
162
			$this->notifiers[] = $notifier;
163
		}
164
165
		$this->notifierClasses = [];
166
167
		return $this->notifiers;
168
	}
169
170
	/**
171
	 * @return INotification
172
	 * @since 8.2.0
173
	 */
174
	public function createNotification(): INotification {
175
		return new Notification($this->validator);
176
	}
177
178
	/**
179
	 * @return bool
180
	 * @since 8.2.0
181
	 */
182
	public function hasNotifiers(): bool {
183
		return !empty($this->notifiers) || !empty($this->notifierClasses);
184
	}
185
186
	/**
187
	 * @param bool $preparingPushNotification
188
	 * @since 14.0.0
189
	 */
190
	public function setPreparingPushNotification(bool $preparingPushNotification): void {
191
		$this->preparingPushNotification = $preparingPushNotification;
192
	}
193
194
	/**
195
	 * @return bool
196
	 * @since 14.0.0
197
	 */
198
	public function isPreparingPushNotification(): bool {
199
		return $this->preparingPushNotification;
200
	}
201
202
	/**
203
	 * @param INotification $notification
204
	 * @throws \InvalidArgumentException When the notification is not valid
205
	 * @since 8.2.0
206
	 */
207
	public function notify(INotification $notification): void {
208
		if (!$notification->isValid()) {
209
			throw new \InvalidArgumentException('The given notification is invalid');
210
		}
211
212
		$apps = $this->getApps();
213
214
		foreach ($apps as $app) {
215
			try {
216
				$app->notify($notification);
217
			} catch (\InvalidArgumentException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
218
			}
219
		}
220
	}
221
222
	/**
223
	 * Identifier of the notifier, only use [a-z0-9_]
224
	 *
225
	 * @return string
226
	 * @since 17.0.0
227
	 */
228
	public function getID(): string {
229
		return 'core';
230
	}
231
232
	/**
233
	 * Human readable name describing the notifier
234
	 *
235
	 * @return string
236
	 * @since 17.0.0
237
	 */
238
	public function getName(): string {
239
		return 'core';
240
	}
241
242
	/**
243
	 * @param INotification $notification
244
	 * @param string $languageCode The code of the language that should be used to prepare the notification
245
	 * @return INotification
246
	 * @throws \InvalidArgumentException When the notification was not prepared by a notifier
247
	 * @throws AlreadyProcessedException When the notification is not needed anymore and should be deleted
248
	 * @since 8.2.0
249
	 */
250
	public function prepare(INotification $notification, string $languageCode): INotification {
251
		$notifiers = $this->getNotifiers();
252
253
		foreach ($notifiers as $notifier) {
254
			try {
255
				$notification = $notifier->prepare($notification, $languageCode);
256
			} catch (\InvalidArgumentException $e) {
257
				continue;
258
			} catch (AlreadyProcessedException $e) {
259
				$this->markProcessed($notification);
260
				throw new \InvalidArgumentException('The given notification has been processed');
261
			}
262
263
			if (!($notification instanceof INotification) || !$notification->isValidParsed()) {
264
				throw new \InvalidArgumentException('The given notification has not been handled');
265
			}
266
		}
267
268
		if (!($notification instanceof INotification) || !$notification->isValidParsed()) {
0 ignored issues
show
introduced by
$notification is always a sub-type of OCP\Notification\INotification.
Loading history...
269
			throw new \InvalidArgumentException('The given notification has not been handled');
270
		}
271
272
		return $notification;
273
	}
274
275
	/**
276
	 * @param INotification $notification
277
	 */
278
	public function markProcessed(INotification $notification): void {
279
		$apps = $this->getApps();
280
281
		foreach ($apps as $app) {
282
			$app->markProcessed($notification);
283
		}
284
	}
285
286
	/**
287
	 * @param INotification $notification
288
	 * @return int
289
	 */
290
	public function getCount(INotification $notification): int {
291
		$apps = $this->getApps();
292
293
		$count = 0;
294
		foreach ($apps as $app) {
295
			$count += $app->getCount($notification);
296
		}
297
298
		return $count;
299
	}
300
301
	public function dismissNotification(INotification $notification): void {
302
		$notifiers = $this->getNotifiers();
303
304
		foreach ($notifiers as $notifier) {
305
			if ($notifier instanceof IDismissableNotifier) {
306
				try {
307
					$notifier->dismissNotification($notification);
308
				} catch (\InvalidArgumentException $e) {
309
					continue;
310
				}
311
			}
312
		}
313
	}
314
}
315