You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

315 lines
8.1 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2016, ownCloud, Inc.
  5. *
  6. * @author Joas Schilling <coding@schilljs.com>
  7. * @author Morris Jobke <hey@morrisjobke.de>
  8. * @author Roeland Jago Douma <roeland@famdouma.nl>
  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. namespace OC\Notification;
  26. use OCP\AppFramework\QueryException;
  27. use OCP\ILogger;
  28. use OCP\Notification\AlreadyProcessedException;
  29. use OCP\Notification\IApp;
  30. use OCP\Notification\IDismissableNotifier;
  31. use OCP\Notification\IManager;
  32. use OCP\Notification\INotification;
  33. use OCP\Notification\INotifier;
  34. use OCP\RichObjectStrings\IValidator;
  35. class Manager implements IManager {
  36. /** @var IValidator */
  37. protected $validator;
  38. /** @var ILogger */
  39. protected $logger;
  40. /** @var IApp[] */
  41. protected $apps;
  42. /** @var string[] */
  43. protected $appClasses;
  44. /** @var INotifier[] */
  45. protected $notifiers;
  46. /** @var string[] */
  47. protected $notifierClasses;
  48. /** @var bool */
  49. protected $preparingPushNotification;
  50. public function __construct(IValidator $validator,
  51. ILogger $logger) {
  52. $this->validator = $validator;
  53. $this->logger = $logger;
  54. $this->apps = [];
  55. $this->notifiers = [];
  56. $this->appClasses = [];
  57. $this->notifierClasses = [];
  58. $this->preparingPushNotification = false;
  59. }
  60. /**
  61. * @param string $appClass The service must implement IApp, otherwise a
  62. * \InvalidArgumentException is thrown later
  63. * @since 17.0.0
  64. */
  65. public function registerApp(string $appClass): void {
  66. $this->appClasses[] = $appClass;
  67. }
  68. /**
  69. * @param \Closure $service The service must implement INotifier, otherwise a
  70. * \InvalidArgumentException is thrown later
  71. * @param \Closure $info An array with the keys 'id' and 'name' containing
  72. * the app id and the app name
  73. * @deprecated 17.0.0 use registerNotifierService instead.
  74. * @since 8.2.0 - Parameter $info was added in 9.0.0
  75. */
  76. public function registerNotifier(\Closure $service, \Closure $info) {
  77. $infoData = $info();
  78. $this->logger->logException(new \InvalidArgumentException(
  79. 'Notifier ' . $infoData['name'] . ' (id: ' . $infoData['id'] . ') is not considered because it is using the old way to register.'
  80. ));
  81. }
  82. /**
  83. * @param string $notifierService The service must implement INotifier, otherwise a
  84. * \InvalidArgumentException is thrown later
  85. * @since 17.0.0
  86. */
  87. public function registerNotifierService(string $notifierService): void {
  88. $this->notifierClasses[] = $notifierService;
  89. }
  90. /**
  91. * @return IApp[]
  92. */
  93. protected function getApps(): array {
  94. if (empty($this->appClasses)) {
  95. return $this->apps;
  96. }
  97. foreach ($this->appClasses as $appClass) {
  98. try {
  99. $app = \OC::$server->query($appClass);
  100. } catch (QueryException $e) {
  101. $this->logger->logException($e, [
  102. 'message' => 'Failed to load notification app class: ' . $appClass,
  103. 'app' => 'notifications',
  104. ]);
  105. continue;
  106. }
  107. if (!($app instanceof IApp)) {
  108. $this->logger->error('Notification app class ' . $appClass . ' is not implementing ' . IApp::class, [
  109. 'app' => 'notifications',
  110. ]);
  111. continue;
  112. }
  113. $this->apps[] = $app;
  114. }
  115. $this->appClasses = [];
  116. return $this->apps;
  117. }
  118. /**
  119. * @return INotifier[]
  120. */
  121. public function getNotifiers(): array {
  122. if (empty($this->notifierClasses)) {
  123. return $this->notifiers;
  124. }
  125. foreach ($this->notifierClasses as $notifierClass) {
  126. try {
  127. $notifier = \OC::$server->query($notifierClass);
  128. } catch (QueryException $e) {
  129. $this->logger->logException($e, [
  130. 'message' => 'Failed to load notification notifier class: ' . $notifierClass,
  131. 'app' => 'notifications',
  132. ]);
  133. continue;
  134. }
  135. if (!($notifier instanceof INotifier)) {
  136. $this->logger->error('Notification notifier class ' . $notifierClass . ' is not implementing ' . INotifier::class, [
  137. 'app' => 'notifications',
  138. ]);
  139. continue;
  140. }
  141. $this->notifiers[] = $notifier;
  142. }
  143. $this->notifierClasses = [];
  144. return $this->notifiers;
  145. }
  146. /**
  147. * @return INotification
  148. * @since 8.2.0
  149. */
  150. public function createNotification(): INotification {
  151. return new Notification($this->validator);
  152. }
  153. /**
  154. * @return bool
  155. * @since 8.2.0
  156. */
  157. public function hasNotifiers(): bool {
  158. return !empty($this->notifiers) || !empty($this->notifierClasses);
  159. }
  160. /**
  161. * @param bool $preparingPushNotification
  162. * @since 14.0.0
  163. */
  164. public function setPreparingPushNotification(bool $preparingPushNotification): void {
  165. $this->preparingPushNotification = $preparingPushNotification;
  166. }
  167. /**
  168. * @return bool
  169. * @since 14.0.0
  170. */
  171. public function isPreparingPushNotification(): bool {
  172. return $this->preparingPushNotification;
  173. }
  174. /**
  175. * @param INotification $notification
  176. * @throws \InvalidArgumentException When the notification is not valid
  177. * @since 8.2.0
  178. */
  179. public function notify(INotification $notification): void {
  180. if (!$notification->isValid()) {
  181. throw new \InvalidArgumentException('The given notification is invalid');
  182. }
  183. $apps = $this->getApps();
  184. foreach ($apps as $app) {
  185. try {
  186. $app->notify($notification);
  187. } catch (\InvalidArgumentException $e) {
  188. }
  189. }
  190. }
  191. /**
  192. * Identifier of the notifier, only use [a-z0-9_]
  193. *
  194. * @return string
  195. * @since 17.0.0
  196. */
  197. public function getID(): string {
  198. return 'core';
  199. }
  200. /**
  201. * Human readable name describing the notifier
  202. *
  203. * @return string
  204. * @since 17.0.0
  205. */
  206. public function getName(): string {
  207. return 'core';
  208. }
  209. /**
  210. * @param INotification $notification
  211. * @param string $languageCode The code of the language that should be used to prepare the notification
  212. * @return INotification
  213. * @throws \InvalidArgumentException When the notification was not prepared by a notifier
  214. * @throws AlreadyProcessedException When the notification is not needed anymore and should be deleted
  215. * @since 8.2.0
  216. */
  217. public function prepare(INotification $notification, string $languageCode): INotification {
  218. $notifiers = $this->getNotifiers();
  219. foreach ($notifiers as $notifier) {
  220. try {
  221. $notification = $notifier->prepare($notification, $languageCode);
  222. } catch (\InvalidArgumentException $e) {
  223. continue;
  224. } catch (AlreadyProcessedException $e) {
  225. $this->markProcessed($notification);
  226. throw new \InvalidArgumentException('The given notification has been processed');
  227. }
  228. if (!($notification instanceof INotification) || !$notification->isValidParsed()) {
  229. throw new \InvalidArgumentException('The given notification has not been handled');
  230. }
  231. }
  232. if (!($notification instanceof INotification) || !$notification->isValidParsed()) {
  233. throw new \InvalidArgumentException('The given notification has not been handled');
  234. }
  235. return $notification;
  236. }
  237. /**
  238. * @param INotification $notification
  239. */
  240. public function markProcessed(INotification $notification): void {
  241. $apps = $this->getApps();
  242. foreach ($apps as $app) {
  243. $app->markProcessed($notification);
  244. }
  245. }
  246. /**
  247. * @param INotification $notification
  248. * @return int
  249. */
  250. public function getCount(INotification $notification): int {
  251. $apps = $this->getApps();
  252. $count = 0;
  253. foreach ($apps as $app) {
  254. $count += $app->getCount($notification);
  255. }
  256. return $count;
  257. }
  258. public function dismissNotification(INotification $notification): void {
  259. $notifiers = $this->getNotifiers();
  260. foreach ($notifiers as $notifier) {
  261. if ($notifier instanceof IDismissableNotifier) {
  262. try {
  263. $notifier->dismissNotification($notification);
  264. } catch (\InvalidArgumentException $e) {
  265. continue;
  266. }
  267. }
  268. }
  269. }
  270. }