Notification.php 9.7 KB

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