Passed
Push — master ( 782554...5b604e )
by Morris
10:22
created

Manager::listNotifiers()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

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