Notification.php 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  6. * SPDX-License-Identifier: AGPL-3.0-only
  7. */
  8. namespace OC\Notification;
  9. use OCP\Notification\IAction;
  10. use OCP\Notification\INotification;
  11. use OCP\Notification\InvalidValueException;
  12. use OCP\RichObjectStrings\InvalidObjectExeption;
  13. use OCP\RichObjectStrings\IRichTextFormatter;
  14. use OCP\RichObjectStrings\IValidator;
  15. class Notification implements INotification {
  16. /**
  17. * A very small and privileged list of apps that are allowed to push during DND.
  18. */
  19. public const PRIORITY_NOTIFICATION_APPS = [
  20. 'spreed',
  21. 'twofactor_nextcloud_notification',
  22. ];
  23. protected string $app = '';
  24. protected string $user = '';
  25. protected \DateTime $dateTime;
  26. protected string $objectType = '';
  27. protected string $objectId = '';
  28. protected string $subject = '';
  29. protected array $subjectParameters = [];
  30. protected string $subjectParsed = '';
  31. protected string $subjectRich = '';
  32. protected array $subjectRichParameters = [];
  33. protected string $message = '';
  34. protected array $messageParameters = [];
  35. protected string $messageParsed = '';
  36. protected string $messageRich = '';
  37. protected array $messageRichParameters = [];
  38. protected string $link = '';
  39. protected string $icon = '';
  40. protected bool $priorityNotification = false;
  41. protected array $actions = [];
  42. protected array $actionsParsed = [];
  43. protected bool $hasPrimaryAction = false;
  44. protected bool $hasPrimaryParsedAction = false;
  45. public function __construct(
  46. protected IValidator $richValidator,
  47. protected IRichTextFormatter $richTextFormatter,
  48. ) {
  49. $this->dateTime = new \DateTime();
  50. $this->dateTime->setTimestamp(0);
  51. }
  52. /**
  53. * {@inheritDoc}
  54. */
  55. public function setApp(string $app): INotification {
  56. if ($app === '' || isset($app[32])) {
  57. throw new InvalidValueException('app');
  58. }
  59. $this->app = $app;
  60. return $this;
  61. }
  62. /**
  63. * {@inheritDoc}
  64. */
  65. public function getApp(): string {
  66. return $this->app;
  67. }
  68. /**
  69. * {@inheritDoc}
  70. */
  71. public function setUser(string $user): INotification {
  72. if ($user === '' || isset($user[64])) {
  73. throw new InvalidValueException('user');
  74. }
  75. $this->user = $user;
  76. return $this;
  77. }
  78. /**
  79. * {@inheritDoc}
  80. */
  81. public function getUser(): string {
  82. return $this->user;
  83. }
  84. /**
  85. * {@inheritDoc}
  86. */
  87. public function setDateTime(\DateTime $dateTime): INotification {
  88. if ($dateTime->getTimestamp() === 0) {
  89. throw new InvalidValueException('dateTime');
  90. }
  91. $this->dateTime = $dateTime;
  92. return $this;
  93. }
  94. /**
  95. * {@inheritDoc}
  96. */
  97. public function getDateTime(): \DateTime {
  98. return $this->dateTime;
  99. }
  100. /**
  101. * {@inheritDoc}
  102. */
  103. public function setObject(string $type, string $id): INotification {
  104. if ($type === '' || isset($type[64])) {
  105. throw new InvalidValueException('objectType');
  106. }
  107. $this->objectType = $type;
  108. if ($id === '' || isset($id[64])) {
  109. throw new InvalidValueException('objectId');
  110. }
  111. $this->objectId = $id;
  112. return $this;
  113. }
  114. /**
  115. * {@inheritDoc}
  116. */
  117. public function getObjectType(): string {
  118. return $this->objectType;
  119. }
  120. /**
  121. * {@inheritDoc}
  122. */
  123. public function getObjectId(): string {
  124. return $this->objectId;
  125. }
  126. /**
  127. * {@inheritDoc}
  128. */
  129. public function setSubject(string $subject, array $parameters = []): INotification {
  130. if ($subject === '' || isset($subject[64])) {
  131. throw new InvalidValueException('subject');
  132. }
  133. $this->subject = $subject;
  134. $this->subjectParameters = $parameters;
  135. return $this;
  136. }
  137. /**
  138. * {@inheritDoc}
  139. */
  140. public function getSubject(): string {
  141. return $this->subject;
  142. }
  143. /**
  144. * {@inheritDoc}
  145. */
  146. public function getSubjectParameters(): array {
  147. return $this->subjectParameters;
  148. }
  149. /**
  150. * {@inheritDoc}
  151. */
  152. public function setParsedSubject(string $subject): INotification {
  153. if ($subject === '') {
  154. throw new InvalidValueException('parsedSubject');
  155. }
  156. $this->subjectParsed = $subject;
  157. return $this;
  158. }
  159. /**
  160. * {@inheritDoc}
  161. */
  162. public function getParsedSubject(): string {
  163. return $this->subjectParsed;
  164. }
  165. /**
  166. * {@inheritDoc}
  167. */
  168. public function setRichSubject(string $subject, array $parameters = []): INotification {
  169. if ($subject === '') {
  170. throw new InvalidValueException('richSubject');
  171. }
  172. $this->subjectRich = $subject;
  173. $this->subjectRichParameters = $parameters;
  174. if ($this->subjectParsed === '') {
  175. try {
  176. $this->subjectParsed = $this->richTextFormatter->richToParsed($subject, $parameters);
  177. } catch (\InvalidArgumentException $e) {
  178. throw new InvalidValueException('richSubjectParameters', $e);
  179. }
  180. }
  181. return $this;
  182. }
  183. /**
  184. * {@inheritDoc}
  185. */
  186. public function getRichSubject(): string {
  187. return $this->subjectRich;
  188. }
  189. /**
  190. * {@inheritDoc}
  191. */
  192. public function getRichSubjectParameters(): array {
  193. return $this->subjectRichParameters;
  194. }
  195. /**
  196. * {@inheritDoc}
  197. */
  198. public function setMessage(string $message, array $parameters = []): INotification {
  199. if ($message === '' || isset($message[64])) {
  200. throw new InvalidValueException('message');
  201. }
  202. $this->message = $message;
  203. $this->messageParameters = $parameters;
  204. return $this;
  205. }
  206. /**
  207. * {@inheritDoc}
  208. */
  209. public function getMessage(): string {
  210. return $this->message;
  211. }
  212. /**
  213. * {@inheritDoc}
  214. */
  215. public function getMessageParameters(): array {
  216. return $this->messageParameters;
  217. }
  218. /**
  219. * {@inheritDoc}
  220. */
  221. public function setParsedMessage(string $message): INotification {
  222. if ($message === '') {
  223. throw new InvalidValueException('parsedMessage');
  224. }
  225. $this->messageParsed = $message;
  226. return $this;
  227. }
  228. /**
  229. * {@inheritDoc}
  230. */
  231. public function getParsedMessage(): string {
  232. return $this->messageParsed;
  233. }
  234. /**
  235. * {@inheritDoc}
  236. */
  237. public function setRichMessage(string $message, array $parameters = []): INotification {
  238. if ($message === '') {
  239. throw new InvalidValueException('richMessage');
  240. }
  241. $this->messageRich = $message;
  242. $this->messageRichParameters = $parameters;
  243. if ($this->messageParsed === '') {
  244. try {
  245. $this->messageParsed = $this->richTextFormatter->richToParsed($message, $parameters);
  246. } catch (\InvalidArgumentException $e) {
  247. throw new InvalidValueException('richMessageParameters', $e);
  248. }
  249. }
  250. return $this;
  251. }
  252. /**
  253. * {@inheritDoc}
  254. */
  255. public function getRichMessage(): string {
  256. return $this->messageRich;
  257. }
  258. /**
  259. * {@inheritDoc}
  260. */
  261. public function getRichMessageParameters(): array {
  262. return $this->messageRichParameters;
  263. }
  264. /**
  265. * {@inheritDoc}
  266. */
  267. public function setLink(string $link): INotification {
  268. if ($link === '' || isset($link[4000])) {
  269. throw new InvalidValueException('link');
  270. }
  271. $this->link = $link;
  272. return $this;
  273. }
  274. /**
  275. * {@inheritDoc}
  276. */
  277. public function getLink(): string {
  278. return $this->link;
  279. }
  280. /**
  281. * {@inheritDoc}
  282. */
  283. public function setIcon(string $icon): INotification {
  284. if ($icon === '' || isset($icon[4000])) {
  285. throw new InvalidValueException('icon');
  286. }
  287. $this->icon = $icon;
  288. return $this;
  289. }
  290. /**
  291. * {@inheritDoc}
  292. */
  293. public function getIcon(): string {
  294. return $this->icon;
  295. }
  296. /**
  297. * {@inheritDoc}
  298. */
  299. public function setPriorityNotification(bool $priorityNotification): INotification {
  300. if ($priorityNotification && !in_array($this->getApp(), self::PRIORITY_NOTIFICATION_APPS, true)) {
  301. throw new InvalidValueException('priorityNotification');
  302. }
  303. $this->priorityNotification = $priorityNotification;
  304. return $this;
  305. }
  306. /**
  307. * {@inheritDoc}
  308. */
  309. public function isPriorityNotification(): bool {
  310. return $this->priorityNotification;
  311. }
  312. /**
  313. * {@inheritDoc}
  314. */
  315. public function createAction(): IAction {
  316. return new Action();
  317. }
  318. /**
  319. * {@inheritDoc}
  320. */
  321. public function addAction(IAction $action): INotification {
  322. if (!$action->isValid()) {
  323. throw new InvalidValueException('action');
  324. }
  325. if ($action->isPrimary()) {
  326. if ($this->hasPrimaryAction) {
  327. throw new InvalidValueException('primaryAction');
  328. }
  329. $this->hasPrimaryAction = true;
  330. }
  331. $this->actions[] = $action;
  332. return $this;
  333. }
  334. /**
  335. * {@inheritDoc}
  336. */
  337. public function getActions(): array {
  338. return $this->actions;
  339. }
  340. /**
  341. * {@inheritDoc}
  342. */
  343. public function addParsedAction(IAction $action): INotification {
  344. if (!$action->isValidParsed()) {
  345. throw new InvalidValueException('action');
  346. }
  347. if ($action->isPrimary()) {
  348. if ($this->hasPrimaryParsedAction) {
  349. throw new InvalidValueException('primaryAction');
  350. }
  351. $this->hasPrimaryParsedAction = true;
  352. // Make sure the primary action is always the first one
  353. array_unshift($this->actionsParsed, $action);
  354. } else {
  355. $this->actionsParsed[] = $action;
  356. }
  357. return $this;
  358. }
  359. /**
  360. * {@inheritDoc}
  361. */
  362. public function getParsedActions(): array {
  363. return $this->actionsParsed;
  364. }
  365. /**
  366. * {@inheritDoc}
  367. */
  368. public function isValid(): bool {
  369. return
  370. $this->isValidCommon()
  371. &&
  372. $this->getSubject() !== ''
  373. ;
  374. }
  375. /**
  376. * {@inheritDoc}
  377. */
  378. public function isValidParsed(): bool {
  379. if ($this->getRichSubject() !== '' || !empty($this->getRichSubjectParameters())) {
  380. try {
  381. $this->richValidator->validate($this->getRichSubject(), $this->getRichSubjectParameters());
  382. } catch (InvalidObjectExeption $e) {
  383. return false;
  384. }
  385. }
  386. if ($this->getRichMessage() !== '' || !empty($this->getRichMessageParameters())) {
  387. try {
  388. $this->richValidator->validate($this->getRichMessage(), $this->getRichMessageParameters());
  389. } catch (InvalidObjectExeption $e) {
  390. return false;
  391. }
  392. }
  393. return
  394. $this->isValidCommon()
  395. &&
  396. $this->getParsedSubject() !== ''
  397. ;
  398. }
  399. protected function isValidCommon(): bool {
  400. if ($this->isPriorityNotification() && !in_array($this->getApp(), self::PRIORITY_NOTIFICATION_APPS, true)) {
  401. return false;
  402. }
  403. return
  404. $this->getApp() !== ''
  405. &&
  406. $this->getUser() !== ''
  407. &&
  408. $this->getDateTime()->getTimestamp() !== 0
  409. &&
  410. $this->getObjectType() !== ''
  411. &&
  412. $this->getObjectId() !== ''
  413. ;
  414. }
  415. }