From 834bd13e282516649134269787d98e6d53e9b2d9 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 10 Apr 2024 15:50:17 +0200 Subject: [PATCH 1/6] fix(notifications): Add a dedicated exception when invalid values are set Signed-off-by: Joas Schilling --- lib/composer/composer/LICENSE | 2 + lib/composer/composer/autoload_classmap.php | 1 + lib/composer/composer/autoload_static.php | 1 + lib/private/Notification/Action.php | 72 ++----- lib/private/Notification/Notification.php | 188 ++++++------------ lib/public/Notification/IAction.php | 10 +- .../Notification/IDismissableNotifier.php | 2 +- lib/public/Notification/INotification.php | 42 ++-- .../Notification/InvalidValueException.php | 49 +++++ 9 files changed, 173 insertions(+), 194 deletions(-) create mode 100644 lib/public/Notification/InvalidValueException.php diff --git a/lib/composer/composer/LICENSE b/lib/composer/composer/LICENSE index 62ecfd8d004..f27399a042d 100644 --- a/lib/composer/composer/LICENSE +++ b/lib/composer/composer/LICENSE @@ -1,3 +1,4 @@ + Copyright (c) Nils Adermann, Jordi Boggiano Permission is hereby granted, free of charge, to any person obtaining a copy @@ -17,3 +18,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 526854bea77..54e6d165e83 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -567,6 +567,7 @@ return array( 'OCP\\Notification\\IManager' => $baseDir . '/lib/public/Notification/IManager.php', 'OCP\\Notification\\INotification' => $baseDir . '/lib/public/Notification/INotification.php', 'OCP\\Notification\\INotifier' => $baseDir . '/lib/public/Notification/INotifier.php', + 'OCP\\Notification\\InvalidValueException' => $baseDir . '/lib/public/Notification/InvalidValueException.php', 'OCP\\OCM\\Events\\ResourceTypeRegisterEvent' => $baseDir . '/lib/public/OCM/Events/ResourceTypeRegisterEvent.php', 'OCP\\OCM\\Exceptions\\OCMArgumentException' => $baseDir . '/lib/public/OCM/Exceptions/OCMArgumentException.php', 'OCP\\OCM\\Exceptions\\OCMProviderException' => $baseDir . '/lib/public/OCM/Exceptions/OCMProviderException.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index b05f8eaa395..054d9fa9bc8 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -600,6 +600,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Notification\\IManager' => __DIR__ . '/../../..' . '/lib/public/Notification/IManager.php', 'OCP\\Notification\\INotification' => __DIR__ . '/../../..' . '/lib/public/Notification/INotification.php', 'OCP\\Notification\\INotifier' => __DIR__ . '/../../..' . '/lib/public/Notification/INotifier.php', + 'OCP\\Notification\\InvalidValueException' => __DIR__ . '/../../..' . '/lib/public/Notification/InvalidValueException.php', 'OCP\\OCM\\Events\\ResourceTypeRegisterEvent' => __DIR__ . '/../../..' . '/lib/public/OCM/Events/ResourceTypeRegisterEvent.php', 'OCP\\OCM\\Exceptions\\OCMArgumentException' => __DIR__ . '/../../..' . '/lib/public/OCM/Exceptions/OCMArgumentException.php', 'OCP\\OCM\\Exceptions\\OCMProviderException' => __DIR__ . '/../../..' . '/lib/public/OCM/Exceptions/OCMProviderException.php', diff --git a/lib/private/Notification/Action.php b/lib/private/Notification/Action.php index 9590d28af4a..8307960cf06 100644 --- a/lib/private/Notification/Action.php +++ b/lib/private/Notification/Action.php @@ -25,76 +25,53 @@ declare(strict_types=1); namespace OC\Notification; use OCP\Notification\IAction; +use OCP\Notification\InvalidValueException; class Action implements IAction { - protected string $label; - - protected string $labelParsed; - - protected string $link; - - protected string $requestType; - - protected string $icon; - - protected bool $primary; - - public function __construct() { - $this->label = ''; - $this->labelParsed = ''; - $this->link = ''; - $this->requestType = ''; - $this->primary = false; - } + protected string $label = ''; + protected string $labelParsed = ''; + protected string $link = ''; + protected string $requestType = ''; + protected bool $primary = false; /** - * @param string $label - * @return $this - * @throws \InvalidArgumentException if the label is invalid - * @since 8.2.0 + * {@inheritDoc} */ public function setLabel(string $label): IAction { if ($label === '' || isset($label[32])) { - throw new \InvalidArgumentException('The given label is invalid'); + throw new InvalidValueException('label'); } $this->label = $label; return $this; } /** - * @return string - * @since 8.2.0 + * {@inheritDoc} */ public function getLabel(): string { return $this->label; } /** - * @param string $label - * @return $this - * @throws \InvalidArgumentException if the label is invalid - * @since 8.2.0 + * {@inheritDoc} */ public function setParsedLabel(string $label): IAction { if ($label === '') { - throw new \InvalidArgumentException('The given parsed label is invalid'); + throw new InvalidValueException('parsedLabel'); } $this->labelParsed = $label; return $this; } /** - * @return string - * @since 8.2.0 + * {@inheritDoc} */ public function getParsedLabel(): string { return $this->labelParsed; } /** - * @param $primary bool - * @return $this - * @since 9.0.0 + * {@inheritDoc} */ public function setPrimary(bool $primary): IAction { $this->primary = $primary; @@ -102,23 +79,18 @@ class Action implements IAction { } /** - * @return bool - * @since 9.0.0 + * {@inheritDoc} */ public function isPrimary(): bool { return $this->primary; } /** - * @param string $link - * @param string $requestType - * @return $this - * @throws \InvalidArgumentException if the link is invalid - * @since 8.2.0 + * {@inheritDoc} */ public function setLink(string $link, string $requestType): IAction { if ($link === '' || isset($link[256])) { - throw new \InvalidArgumentException('The given link is invalid'); + throw new InvalidValueException('link'); } if (!in_array($requestType, [ self::TYPE_GET, @@ -127,7 +99,7 @@ class Action implements IAction { self::TYPE_DELETE, self::TYPE_WEB, ], true)) { - throw new \InvalidArgumentException('The given request type is invalid'); + throw new InvalidValueException('requestType'); } $this->link = $link; $this->requestType = $requestType; @@ -135,30 +107,28 @@ class Action implements IAction { } /** - * @return string - * @since 8.2.0 + * {@inheritDoc} */ public function getLink(): string { return $this->link; } /** - * @return string - * @since 8.2.0 + * {@inheritDoc} */ public function getRequestType(): string { return $this->requestType; } /** - * @return bool + * {@inheritDoc} */ public function isValid(): bool { return $this->label !== '' && $this->link !== ''; } /** - * @return bool + * {@inheritDoc} */ public function isValidParsed(): bool { return $this->labelParsed !== '' && $this->link !== ''; diff --git a/lib/private/Notification/Notification.php b/lib/private/Notification/Notification.php index ed2a84b0de2..2398fd55234 100644 --- a/lib/private/Notification/Notification.php +++ b/lib/private/Notification/Notification.php @@ -28,6 +28,7 @@ namespace OC\Notification; use OCP\Notification\IAction; use OCP\Notification\INotification; +use OCP\Notification\InvalidValueException; use OCP\RichObjectStrings\InvalidObjectExeption; use OCP\RichObjectStrings\IValidator; @@ -62,117 +63,95 @@ class Notification implements INotification { } /** - * @param string $app - * @return $this - * @throws \InvalidArgumentException if the app id is invalid - * @since 8.2.0 + * {@inheritDoc} */ public function setApp(string $app): INotification { if ($app === '' || isset($app[32])) { - throw new \InvalidArgumentException('The given app name is invalid'); + throw new InvalidValueException('app'); } $this->app = $app; return $this; } /** - * @return string - * @since 8.2.0 + * {@inheritDoc} */ public function getApp(): string { return $this->app; } /** - * @param string $user - * @return $this - * @throws \InvalidArgumentException if the user id is invalid - * @since 8.2.0 + * {@inheritDoc} */ public function setUser(string $user): INotification { if ($user === '' || isset($user[64])) { - throw new \InvalidArgumentException('The given user id is invalid'); + throw new InvalidValueException('user'); } $this->user = $user; return $this; } /** - * @return string - * @since 8.2.0 + * {@inheritDoc} */ public function getUser(): string { return $this->user; } /** - * @param \DateTime $dateTime - * @return $this - * @throws \InvalidArgumentException if the $dateTime is invalid - * @since 9.0.0 + * {@inheritDoc} */ public function setDateTime(\DateTime $dateTime): INotification { if ($dateTime->getTimestamp() === 0) { - throw new \InvalidArgumentException('The given date time is invalid'); + throw new InvalidValueException('dateTime'); } $this->dateTime = $dateTime; return $this; } /** - * @return \DateTime - * @since 9.0.0 + * {@inheritDoc} */ public function getDateTime(): \DateTime { return $this->dateTime; } /** - * @param string $type - * @param string $id - * @return $this - * @throws \InvalidArgumentException if the object type or id is invalid - * @since 8.2.0 - 9.0.0: Type of $id changed to string + * {@inheritDoc} */ public function setObject(string $type, string $id): INotification { if ($type === '' || isset($type[64])) { - throw new \InvalidArgumentException('The given object type is invalid'); + throw new InvalidValueException('objectType'); } $this->objectType = $type; if ($id === '' || isset($id[64])) { - throw new \InvalidArgumentException('The given object id is invalid'); + throw new InvalidValueException('objectId'); } $this->objectId = $id; return $this; } /** - * @return string - * @since 8.2.0 + * {@inheritDoc} */ public function getObjectType(): string { return $this->objectType; } /** - * @return string - * @since 8.2.0 - 9.0.0: Return type changed to string + * {@inheritDoc} */ public function getObjectId(): string { return $this->objectId; } /** - * @param string $subject - * @param array $parameters - * @return $this - * @throws \InvalidArgumentException if the subject or parameters are invalid - * @since 8.2.0 + * {@inheritDoc} */ public function setSubject(string $subject, array $parameters = []): INotification { if ($subject === '' || isset($subject[64])) { - throw new \InvalidArgumentException('The given subject is invalid'); + throw new InvalidValueException('subject'); } $this->subject = $subject; @@ -182,60 +161,54 @@ class Notification implements INotification { } /** - * @return string - * @since 8.2.0 + * {@inheritDoc} */ public function getSubject(): string { return $this->subject; } /** - * @return array - * @since 8.2.0 + * {@inheritDoc} */ public function getSubjectParameters(): array { return $this->subjectParameters; } /** - * @param string $subject - * @return $this - * @throws \InvalidArgumentException if the subject is invalid - * @since 8.2.0 + * {@inheritDoc} */ public function setParsedSubject(string $subject): INotification { if ($subject === '') { - throw new \InvalidArgumentException('The given parsed subject is invalid'); + throw new InvalidValueException('parsedSubject'); } $this->subjectParsed = $subject; return $this; } /** - * @return string - * @since 8.2.0 + * {@inheritDoc} */ public function getParsedSubject(): string { return $this->subjectParsed; } /** - * @param string $subject - * @param array $parameters - * @return $this - * @throws \InvalidArgumentException if the subject or parameters are invalid - * @since 11.0.0 + * {@inheritDoc} */ public function setRichSubject(string $subject, array $parameters = []): INotification { if ($subject === '') { - throw new \InvalidArgumentException('The given parsed subject is invalid'); + throw new InvalidValueException('richSubject'); } $this->subjectRich = $subject; $this->subjectRichParameters = $parameters; if ($this->subjectParsed === '') { - $this->subjectParsed = $this->richToParsed($subject, $parameters); + try { + $this->subjectParsed = $this->richToParsed($subject, $parameters); + } catch (\InvalidArgumentException $e) { + throw new InvalidValueException('richSubjectParameters', $e); + } } return $this; @@ -266,31 +239,25 @@ class Notification implements INotification { } /** - * @return string - * @since 11.0.0 + * {@inheritDoc} */ public function getRichSubject(): string { return $this->subjectRich; } /** - * @return array[] - * @since 11.0.0 + * {@inheritDoc} */ public function getRichSubjectParameters(): array { return $this->subjectRichParameters; } /** - * @param string $message - * @param array $parameters - * @return $this - * @throws \InvalidArgumentException if the message or parameters are invalid - * @since 8.2.0 + * {@inheritDoc} */ public function setMessage(string $message, array $parameters = []): INotification { if ($message === '' || isset($message[64])) { - throw new \InvalidArgumentException('The given message is invalid'); + throw new InvalidValueException('message'); } $this->message = $message; @@ -300,147 +267,127 @@ class Notification implements INotification { } /** - * @return string - * @since 8.2.0 + * {@inheritDoc} */ public function getMessage(): string { return $this->message; } /** - * @return array - * @since 8.2.0 + * {@inheritDoc} */ public function getMessageParameters(): array { return $this->messageParameters; } /** - * @param string $message - * @return $this - * @throws \InvalidArgumentException if the message is invalid - * @since 8.2.0 + * {@inheritDoc} */ public function setParsedMessage(string $message): INotification { if ($message === '') { - throw new \InvalidArgumentException('The given parsed message is invalid'); + throw new InvalidValueException('parsedMessage'); } $this->messageParsed = $message; return $this; } /** - * @return string - * @since 8.2.0 + * {@inheritDoc} */ public function getParsedMessage(): string { return $this->messageParsed; } /** - * @param string $message - * @param array $parameters - * @return $this - * @throws \InvalidArgumentException if the message or parameters are invalid - * @since 11.0.0 + * {@inheritDoc} */ public function setRichMessage(string $message, array $parameters = []): INotification { if ($message === '') { - throw new \InvalidArgumentException('The given parsed message is invalid'); + throw new InvalidValueException('richMessage'); } $this->messageRich = $message; $this->messageRichParameters = $parameters; if ($this->messageParsed === '') { - $this->messageParsed = $this->richToParsed($message, $parameters); + try { + $this->messageParsed = $this->richToParsed($message, $parameters); + } catch (\InvalidArgumentException $e) { + throw new InvalidValueException('richMessageParameters', $e); + } } return $this; } /** - * @return string - * @since 11.0.0 + * {@inheritDoc} */ public function getRichMessage(): string { return $this->messageRich; } /** - * @return array[] - * @since 11.0.0 + * {@inheritDoc} */ public function getRichMessageParameters(): array { return $this->messageRichParameters; } /** - * @param string $link - * @return $this - * @throws \InvalidArgumentException if the link is invalid - * @since 8.2.0 + * {@inheritDoc} */ public function setLink(string $link): INotification { if ($link === '' || isset($link[4000])) { - throw new \InvalidArgumentException('The given link is invalid'); + throw new InvalidValueException('link'); } $this->link = $link; return $this; } /** - * @return string - * @since 8.2.0 + * {@inheritDoc} */ public function getLink(): string { return $this->link; } /** - * @param string $icon - * @return $this - * @throws \InvalidArgumentException if the icon is invalid - * @since 11.0.0 + * {@inheritDoc} */ public function setIcon(string $icon): INotification { if ($icon === '' || isset($icon[4000])) { - throw new \InvalidArgumentException('The given icon is invalid'); + throw new InvalidValueException('icon'); } $this->icon = $icon; return $this; } /** - * @return string - * @since 11.0.0 + * {@inheritDoc} */ public function getIcon(): string { return $this->icon; } /** - * @return IAction - * @since 8.2.0 + * {@inheritDoc} */ public function createAction(): IAction { return new Action(); } /** - * @param IAction $action - * @return $this - * @throws \InvalidArgumentException if the action is invalid - * @since 8.2.0 + * {@inheritDoc} */ public function addAction(IAction $action): INotification { if (!$action->isValid()) { - throw new \InvalidArgumentException('The given action is invalid'); + throw new InvalidValueException('action'); } if ($action->isPrimary()) { if ($this->hasPrimaryAction) { - throw new \InvalidArgumentException('The notification already has a primary action'); + throw new InvalidValueException('primaryAction'); } $this->hasPrimaryAction = true; @@ -451,27 +398,23 @@ class Notification implements INotification { } /** - * @return IAction[] - * @since 8.2.0 + * {@inheritDoc} */ public function getActions(): array { return $this->actions; } /** - * @param IAction $action - * @return $this - * @throws \InvalidArgumentException if the action is invalid - * @since 8.2.0 + * {@inheritDoc} */ public function addParsedAction(IAction $action): INotification { if (!$action->isValidParsed()) { - throw new \InvalidArgumentException('The given parsed action is invalid'); + throw new InvalidValueException('action'); } if ($action->isPrimary()) { if ($this->hasPrimaryParsedAction) { - throw new \InvalidArgumentException('The notification already has a primary action'); + throw new InvalidValueException('primaryAction'); } $this->hasPrimaryParsedAction = true; @@ -486,16 +429,14 @@ class Notification implements INotification { } /** - * @return IAction[] - * @since 8.2.0 + * {@inheritDoc} */ public function getParsedActions(): array { return $this->actionsParsed; } /** - * @return bool - * @since 8.2.0 + * {@inheritDoc} */ public function isValid(): bool { return @@ -506,8 +447,7 @@ class Notification implements INotification { } /** - * @return bool - * @since 8.2.0 + * {@inheritDoc} */ public function isValidParsed(): bool { if ($this->getRichSubject() !== '' || !empty($this->getRichSubjectParameters())) { diff --git a/lib/public/Notification/IAction.php b/lib/public/Notification/IAction.php index bcd013f08bc..3009101fed0 100644 --- a/lib/public/Notification/IAction.php +++ b/lib/public/Notification/IAction.php @@ -54,8 +54,9 @@ interface IAction { /** * @param string $label * @return $this - * @throws \InvalidArgumentException if the label is invalid + * @throws InvalidValueException if the label is invalid * @since 9.0.0 + * @since 30.0.0 throws {@see InvalidValueException} instead of \InvalidArgumentException */ public function setLabel(string $label): IAction; @@ -68,8 +69,9 @@ interface IAction { /** * @param string $label * @return $this - * @throws \InvalidArgumentException if the label is invalid + * @throws InvalidValueException if the label is invalid * @since 9.0.0 + * @since 30.0.0 throws {@see InvalidValueException} instead of \InvalidArgumentException */ public function setParsedLabel(string $label): IAction; @@ -82,7 +84,6 @@ interface IAction { /** * @param bool $primary * @return $this - * @throws \InvalidArgumentException if $primary is invalid * @since 9.0.0 */ public function setPrimary(bool $primary): IAction; @@ -97,8 +98,9 @@ interface IAction { * @param string $link * @param string $requestType * @return $this - * @throws \InvalidArgumentException if the link is invalid + * @throws InvalidValueException if the link is invalid * @since 9.0.0 + * @since 30.0.0 throws {@see InvalidValueException} instead of \InvalidArgumentException */ public function setLink(string $link, string $requestType): IAction; diff --git a/lib/public/Notification/IDismissableNotifier.php b/lib/public/Notification/IDismissableNotifier.php index c13e880a4a6..3d2d07d3c6b 100644 --- a/lib/public/Notification/IDismissableNotifier.php +++ b/lib/public/Notification/IDismissableNotifier.php @@ -30,7 +30,7 @@ namespace OCP\Notification; * that are dismissed by the user. * * This can be useful if dismissing the notification will leave it in an incomplete - * state. The handler can chose to for example do some default action. + * state. The handler can choose to for example do some default action. * * @since 18.0.0 */ diff --git a/lib/public/Notification/INotification.php b/lib/public/Notification/INotification.php index 0c6625e346d..b7517326581 100644 --- a/lib/public/Notification/INotification.php +++ b/lib/public/Notification/INotification.php @@ -34,8 +34,9 @@ interface INotification { /** * @param string $app * @return $this - * @throws \InvalidArgumentException if the app id is invalid + * @throws InvalidValueException if the app id is invalid * @since 9.0.0 + * @since 30.0.0 throws {@see InvalidValueException} instead of \InvalidArgumentException */ public function setApp(string $app): INotification; @@ -48,8 +49,9 @@ interface INotification { /** * @param string $user * @return $this - * @throws \InvalidArgumentException if the user id is invalid + * @throws InvalidValueException if the user id is invalid * @since 9.0.0 + * @since 30.0.0 throws {@see InvalidValueException} instead of \InvalidArgumentException */ public function setUser(string $user): INotification; @@ -62,8 +64,9 @@ interface INotification { /** * @param \DateTime $dateTime * @return $this - * @throws \InvalidArgumentException if the $dateTime is invalid + * @throws InvalidValueException if the $dateTime is invalid * @since 9.0.0 + * @since 30.0.0 throws {@see InvalidValueException} instead of \InvalidArgumentException */ public function setDateTime(\DateTime $dateTime): INotification; @@ -77,8 +80,9 @@ interface INotification { * @param string $type * @param string $id * @return $this - * @throws \InvalidArgumentException if the object type or id is invalid + * @throws InvalidValueException if the object type or id is invalid * @since 9.0.0 + * @since 30.0.0 throws {@see InvalidValueException} instead of \InvalidArgumentException */ public function setObject(string $type, string $id): INotification; @@ -98,8 +102,9 @@ interface INotification { * @param string $subject * @param array $parameters * @return $this - * @throws \InvalidArgumentException if the subject or parameters are invalid + * @throws InvalidValueException if the subject or parameters are invalid * @since 9.0.0 + * @since 30.0.0 throws {@see InvalidValueException} instead of \InvalidArgumentException */ public function setSubject(string $subject, array $parameters = []): INotification; @@ -127,8 +132,9 @@ interface INotification { * * @param string $subject * @return $this - * @throws \InvalidArgumentException if the subject is invalid + * @throws InvalidValueException if the subject is invalid * @since 9.0.0 + * @since 30.0.0 throws {@see InvalidValueException} instead of \InvalidArgumentException */ public function setParsedSubject(string $subject): INotification; @@ -150,8 +156,9 @@ interface INotification { * @param string $subject * @param array $parameters * @return $this - * @throws \InvalidArgumentException if the subject or parameters are invalid + * @throws InvalidValueException if the subject or parameters are invalid * @since 11.0.0 + * @since 30.0.0 throws {@see InvalidValueException} instead of \InvalidArgumentException */ public function setRichSubject(string $subject, array $parameters = []): INotification; @@ -171,8 +178,9 @@ interface INotification { * @param string $message * @param array $parameters * @return $this - * @throws \InvalidArgumentException if the message or parameters are invalid + * @throws InvalidValueException if the message or parameters are invalid * @since 9.0.0 + * @since 30.0.0 throws {@see InvalidValueException} instead of \InvalidArgumentException */ public function setMessage(string $message, array $parameters = []): INotification; @@ -200,8 +208,9 @@ interface INotification { * * @param string $message * @return $this - * @throws \InvalidArgumentException if the message is invalid + * @throws InvalidValueException if the message is invalid * @since 9.0.0 + * @since 30.0.0 throws {@see InvalidValueException} instead of \InvalidArgumentException */ public function setParsedMessage(string $message): INotification; @@ -223,8 +232,9 @@ interface INotification { * @param string $message * @param array $parameters * @return $this - * @throws \InvalidArgumentException if the message or parameters are invalid + * @throws InvalidValueException if the message or parameters are invalid * @since 11.0.0 + * @since 30.0.0 throws {@see InvalidValueException} instead of \InvalidArgumentException */ public function setRichMessage(string $message, array $parameters = []): INotification; @@ -243,8 +253,9 @@ interface INotification { /** * @param string $link * @return $this - * @throws \InvalidArgumentException if the link is invalid + * @throws InvalidValueException if the link is invalid * @since 9.0.0 + * @since 30.0.0 throws {@see InvalidValueException} instead of \InvalidArgumentException */ public function setLink(string $link): INotification; @@ -257,8 +268,9 @@ interface INotification { /** * @param string $icon * @return $this - * @throws \InvalidArgumentException if the icon is invalid + * @throws InvalidValueException if the icon is invalid * @since 11.0.0 + * @since 30.0.0 throws {@see InvalidValueException} instead of \InvalidArgumentException */ public function setIcon(string $icon): INotification; @@ -277,8 +289,9 @@ interface INotification { /** * @param IAction $action * @return $this - * @throws \InvalidArgumentException if the action is invalid + * @throws InvalidValueException if the action is invalid * @since 9.0.0 + * @since 30.0.0 throws {@see InvalidValueException} instead of \InvalidArgumentException */ public function addAction(IAction $action): INotification; @@ -291,8 +304,9 @@ interface INotification { /** * @param IAction $action * @return $this - * @throws \InvalidArgumentException if the action is invalid + * @throws InvalidValueException if the action is invalid * @since 9.0.0 + * @since 30.0.0 throws {@see InvalidValueException} instead of \InvalidArgumentException */ public function addParsedAction(IAction $action): INotification; diff --git a/lib/public/Notification/InvalidValueException.php b/lib/public/Notification/InvalidValueException.php new file mode 100644 index 00000000000..6c16ea95036 --- /dev/null +++ b/lib/public/Notification/InvalidValueException.php @@ -0,0 +1,49 @@ + + * + * @author Joas Schilling + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCP\Notification; + +/** + * @since 30.0.0 + */ +class InvalidValueException extends \InvalidArgumentException { + /** + * @since 30.0.0 + */ + public function __construct( + protected string $field, + ?\Throwable $previous = null, + ) { + parent::__construct('Value provided for ' . $field . ' is not valid', previous: $previous); + } + + /** + * @since 30.0.0 + */ + public function getFieldIdentifier(): string { + return $this->field; + } +} From 2c6ecef90f3f3a56192dbc8c41905a81ca3b3501 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 10 Apr 2024 16:07:16 +0200 Subject: [PATCH 2/6] fix(notifications): Add a dedicated exception when not all fields are set while saving a notification Signed-off-by: Joas Schilling --- lib/composer/composer/autoload_classmap.php | 1 + lib/composer/composer/autoload_static.php | 1 + lib/private/Notification/Manager.php | 11 +++-- lib/public/Notification/IApp.php | 3 +- .../IncompleteNotificationException.php | 43 +++++++++++++++++++ 5 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 lib/public/Notification/IncompleteNotificationException.php diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 54e6d165e83..0b2d5b3b38f 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -567,6 +567,7 @@ return array( 'OCP\\Notification\\IManager' => $baseDir . '/lib/public/Notification/IManager.php', 'OCP\\Notification\\INotification' => $baseDir . '/lib/public/Notification/INotification.php', 'OCP\\Notification\\INotifier' => $baseDir . '/lib/public/Notification/INotifier.php', + 'OCP\\Notification\\IncompleteNotificationException' => $baseDir . '/lib/public/Notification/IncompleteNotificationException.php', 'OCP\\Notification\\InvalidValueException' => $baseDir . '/lib/public/Notification/InvalidValueException.php', 'OCP\\OCM\\Events\\ResourceTypeRegisterEvent' => $baseDir . '/lib/public/OCM/Events/ResourceTypeRegisterEvent.php', 'OCP\\OCM\\Exceptions\\OCMArgumentException' => $baseDir . '/lib/public/OCM/Exceptions/OCMArgumentException.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 054d9fa9bc8..b22f3a5affa 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -600,6 +600,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Notification\\IManager' => __DIR__ . '/../../..' . '/lib/public/Notification/IManager.php', 'OCP\\Notification\\INotification' => __DIR__ . '/../../..' . '/lib/public/Notification/INotification.php', 'OCP\\Notification\\INotifier' => __DIR__ . '/../../..' . '/lib/public/Notification/INotifier.php', + 'OCP\\Notification\\IncompleteNotificationException' => __DIR__ . '/../../..' . '/lib/public/Notification/IncompleteNotificationException.php', 'OCP\\Notification\\InvalidValueException' => __DIR__ . '/../../..' . '/lib/public/Notification/InvalidValueException.php', 'OCP\\OCM\\Events\\ResourceTypeRegisterEvent' => __DIR__ . '/../../..' . '/lib/public/OCM/Events/ResourceTypeRegisterEvent.php', 'OCP\\OCM\\Exceptions\\OCMArgumentException' => __DIR__ . '/../../..' . '/lib/public/OCM/Exceptions/OCMArgumentException.php', diff --git a/lib/private/Notification/Manager.php b/lib/private/Notification/Manager.php index 348ddb03df9..8bb6e1defe0 100644 --- a/lib/private/Notification/Manager.php +++ b/lib/private/Notification/Manager.php @@ -35,6 +35,7 @@ use OCP\Notification\IApp; use OCP\Notification\IDeferrableApp; use OCP\Notification\IDismissableNotifier; use OCP\Notification\IManager; +use OCP\Notification\IncompleteNotificationException; use OCP\Notification\INotification; use OCP\Notification\INotifier; use OCP\RichObjectStrings\IValidator; @@ -300,13 +301,11 @@ class Manager implements IManager { } /** - * @param INotification $notification - * @throws \InvalidArgumentException When the notification is not valid - * @since 8.2.0 + * {@inheritDoc} */ public function notify(INotification $notification): void { if (!$notification->isValid()) { - throw new \InvalidArgumentException('The given notification is invalid'); + throw new IncompleteNotificationException('The given notification is invalid'); } $apps = $this->getApps(); @@ -314,7 +313,11 @@ class Manager implements IManager { foreach ($apps as $app) { try { $app->notify($notification); + } catch (IncompleteNotificationException) { } catch (\InvalidArgumentException $e) { + // todo 33.0.0 Log as warning + // todo 39.0.0 Log as error + $this->logger->debug(get_class($app) . '::notify() threw \InvalidArgumentException which is deprecated. Throw \OCP\Notification\IncompleteNotificationException when the notification is incomplete for your app and otherwise handle all \InvalidArgumentException yourself.'); } } } diff --git a/lib/public/Notification/IApp.php b/lib/public/Notification/IApp.php index 6abb9a823e5..a3ef2771c8a 100644 --- a/lib/public/Notification/IApp.php +++ b/lib/public/Notification/IApp.php @@ -32,8 +32,9 @@ namespace OCP\Notification; interface IApp { /** * @param INotification $notification - * @throws \InvalidArgumentException When the notification is not valid + * @throws IncompleteNotificationException When the notification does not have all required fields set * @since 9.0.0 + * @since 30.0.0 throws {@see IncompleteNotificationException} instead of \InvalidArgumentException */ public function notify(INotification $notification): void; diff --git a/lib/public/Notification/IncompleteNotificationException.php b/lib/public/Notification/IncompleteNotificationException.php new file mode 100644 index 00000000000..31551389b43 --- /dev/null +++ b/lib/public/Notification/IncompleteNotificationException.php @@ -0,0 +1,43 @@ + + * + * @author Joas Schilling + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCP\Notification; + +/** + * Thrown when {@see \OCP\Notification\IManager::notify()} is called with a notification + * that does not have all required fields set: + * + * - app + * - user + * - dateTime + * - objectType + * - objectId + * - subject + * + * @since 30.0.0 + */ +class IncompleteNotificationException extends \InvalidArgumentException { +} From c8e4a29dfa5665a99077b8eeed645786a946f375 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 10 Apr 2024 16:44:40 +0200 Subject: [PATCH 3/6] fix(notifications): Add a dedicated exception when the notification is unknown to the notifier Signed-off-by: Joas Schilling --- lib/composer/composer/autoload_classmap.php | 1 + lib/composer/composer/autoload_static.php | 1 + lib/private/Notification/Manager.php | 25 +++++++++----- .../Notification/IDismissableNotifier.php | 5 ++- lib/public/Notification/INotifier.php | 7 ++-- .../UnknownNotificationException.php | 33 +++++++++++++++++++ 6 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 lib/public/Notification/UnknownNotificationException.php diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 0b2d5b3b38f..cc9aaa6c1f6 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -569,6 +569,7 @@ return array( 'OCP\\Notification\\INotifier' => $baseDir . '/lib/public/Notification/INotifier.php', 'OCP\\Notification\\IncompleteNotificationException' => $baseDir . '/lib/public/Notification/IncompleteNotificationException.php', 'OCP\\Notification\\InvalidValueException' => $baseDir . '/lib/public/Notification/InvalidValueException.php', + 'OCP\\Notification\\UnknownNotificationException' => $baseDir . '/lib/public/Notification/UnknownNotificationException.php', 'OCP\\OCM\\Events\\ResourceTypeRegisterEvent' => $baseDir . '/lib/public/OCM/Events/ResourceTypeRegisterEvent.php', 'OCP\\OCM\\Exceptions\\OCMArgumentException' => $baseDir . '/lib/public/OCM/Exceptions/OCMArgumentException.php', 'OCP\\OCM\\Exceptions\\OCMProviderException' => $baseDir . '/lib/public/OCM/Exceptions/OCMProviderException.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index b22f3a5affa..d37f75b8496 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -602,6 +602,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Notification\\INotifier' => __DIR__ . '/../../..' . '/lib/public/Notification/INotifier.php', 'OCP\\Notification\\IncompleteNotificationException' => __DIR__ . '/../../..' . '/lib/public/Notification/IncompleteNotificationException.php', 'OCP\\Notification\\InvalidValueException' => __DIR__ . '/../../..' . '/lib/public/Notification/InvalidValueException.php', + 'OCP\\Notification\\UnknownNotificationException' => __DIR__ . '/../../..' . '/lib/public/Notification/UnknownNotificationException.php', 'OCP\\OCM\\Events\\ResourceTypeRegisterEvent' => __DIR__ . '/../../..' . '/lib/public/OCM/Events/ResourceTypeRegisterEvent.php', 'OCP\\OCM\\Exceptions\\OCMArgumentException' => __DIR__ . '/../../..' . '/lib/public/OCM/Exceptions/OCMArgumentException.php', 'OCP\\OCM\\Exceptions\\OCMProviderException' => __DIR__ . '/../../..' . '/lib/public/OCM/Exceptions/OCMProviderException.php', diff --git a/lib/private/Notification/Manager.php b/lib/private/Notification/Manager.php index 8bb6e1defe0..63374cea21f 100644 --- a/lib/private/Notification/Manager.php +++ b/lib/private/Notification/Manager.php @@ -38,6 +38,7 @@ use OCP\Notification\IManager; use OCP\Notification\IncompleteNotificationException; use OCP\Notification\INotification; use OCP\Notification\INotifier; +use OCP\Notification\UnknownNotificationException; use OCP\RichObjectStrings\IValidator; use OCP\Support\Subscription\IRegistry; use Psr\Container\ContainerExceptionInterface; @@ -343,12 +344,7 @@ class Manager implements IManager { } /** - * @param INotification $notification - * @param string $languageCode The code of the language that should be used to prepare the notification - * @return INotification - * @throws \InvalidArgumentException When the notification was not prepared by a notifier - * @throws AlreadyProcessedException When the notification is not needed anymore and should be deleted - * @since 8.2.0 + * {@inheritDoc} */ public function prepare(INotification $notification, string $languageCode): INotification { $notifiers = $this->getNotifiers(); @@ -356,11 +352,16 @@ class Manager implements IManager { foreach ($notifiers as $notifier) { try { $notification = $notifier->prepare($notification, $languageCode); - } catch (\InvalidArgumentException $e) { - continue; } catch (AlreadyProcessedException $e) { $this->markProcessed($notification); throw new \InvalidArgumentException('The given notification has been processed'); + } catch (UnknownNotificationException) { + continue; + } catch (\InvalidArgumentException $e) { + // todo 33.0.0 Log as warning + // todo 39.0.0 Log as error + $this->logger->debug(get_class($notifier) . '::prepare() threw \InvalidArgumentException which is deprecated. Throw \OCP\Notification\UnknownNotificationException when the notification is not known to your notifier and otherwise handle all \InvalidArgumentException yourself.'); + continue; } if (!$notification->isValidParsed()) { @@ -402,6 +403,9 @@ class Manager implements IManager { return $count; } + /** + * {@inheritDoc} + */ public function dismissNotification(INotification $notification): void { $notifiers = $this->getNotifiers(); @@ -409,7 +413,12 @@ class Manager implements IManager { if ($notifier instanceof IDismissableNotifier) { try { $notifier->dismissNotification($notification); + } catch (UnknownNotificationException) { + continue; } catch (\InvalidArgumentException $e) { + // todo 33.0.0 Log as warning + // todo 39.0.0 Log as error + $this->logger->debug(get_class($notifier) . '::dismissNotification() threw \InvalidArgumentException which is deprecated. Throw \OCP\Notification\UnknownNotificationException when the notification is not known to your notifier and otherwise handle all \InvalidArgumentException yourself.'); continue; } } diff --git a/lib/public/Notification/IDismissableNotifier.php b/lib/public/Notification/IDismissableNotifier.php index 3d2d07d3c6b..45f7a2aa9db 100644 --- a/lib/public/Notification/IDismissableNotifier.php +++ b/lib/public/Notification/IDismissableNotifier.php @@ -37,9 +37,12 @@ namespace OCP\Notification; interface IDismissableNotifier extends INotifier { /** * @param INotification $notification - * @throws \InvalidArgumentException In case the handler can't handle the notification + * @throws UnknownNotificationException when the notifier is not in charge of the notification * * @since 18.0.0 + * @since 30.0.0 Notifiers should throw {@see UnknownNotificationException} instead of \InvalidArgumentException + * when they did not handle the notification. Throwing \InvalidArgumentException directly is deprecated and will + * be logged as an error in Nextcloud 39. */ public function dismissNotification(INotification $notification): void; } diff --git a/lib/public/Notification/INotifier.php b/lib/public/Notification/INotifier.php index ba43cc04cf6..8be9ee1bdb0 100644 --- a/lib/public/Notification/INotifier.php +++ b/lib/public/Notification/INotifier.php @@ -39,7 +39,7 @@ interface INotifier { public function getID(): string; /** - * Human readable name describing the notifier + * Human-readable name describing the notifier * * @return string * @since 17.0.0 @@ -50,9 +50,12 @@ interface INotifier { * @param INotification $notification * @param string $languageCode The code of the language that should be used to prepare the notification * @return INotification - * @throws \InvalidArgumentException When the notification was not prepared by a notifier + * @throws UnknownNotificationException When the notification was not prepared by a notifier * @throws AlreadyProcessedException When the notification is not needed anymore and should be deleted * @since 9.0.0 + * @since 30.0.0 Notifiers should throw {@see UnknownNotificationException} instead of \InvalidArgumentException + * when they did not handle the notification. Throwing \InvalidArgumentException directly is deprecated and will + * be logged as an error in Nextcloud 39. */ public function prepare(INotification $notification, string $languageCode): INotification; } diff --git a/lib/public/Notification/UnknownNotificationException.php b/lib/public/Notification/UnknownNotificationException.php new file mode 100644 index 00000000000..bfeeb6a14c5 --- /dev/null +++ b/lib/public/Notification/UnknownNotificationException.php @@ -0,0 +1,33 @@ + + * + * @author Joas Schilling + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCP\Notification; + +/** + * @since 30.0.0 + */ +class UnknownNotificationException extends \InvalidArgumentException { +} From 0d0c2cdaa08f6bc8f547b437a5b046914680b3f5 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 10 Apr 2024 17:12:31 +0200 Subject: [PATCH 4/6] fix(notifications): Add a dedicated exception when a notification was not parsed completely Signed-off-by: Joas Schilling --- lib/composer/composer/autoload_classmap.php | 1 + lib/composer/composer/autoload_static.php | 1 + lib/private/Notification/Manager.php | 6 ++- lib/public/Notification/INotifier.php | 3 ++ .../IncompleteParsedNotificationException.php | 46 +++++++++++++++++++ 5 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 lib/public/Notification/IncompleteParsedNotificationException.php diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index cc9aaa6c1f6..a726e5a54d5 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -568,6 +568,7 @@ return array( 'OCP\\Notification\\INotification' => $baseDir . '/lib/public/Notification/INotification.php', 'OCP\\Notification\\INotifier' => $baseDir . '/lib/public/Notification/INotifier.php', 'OCP\\Notification\\IncompleteNotificationException' => $baseDir . '/lib/public/Notification/IncompleteNotificationException.php', + 'OCP\\Notification\\IncompleteParsedNotificationException' => $baseDir . '/lib/public/Notification/IncompleteParsedNotificationException.php', 'OCP\\Notification\\InvalidValueException' => $baseDir . '/lib/public/Notification/InvalidValueException.php', 'OCP\\Notification\\UnknownNotificationException' => $baseDir . '/lib/public/Notification/UnknownNotificationException.php', 'OCP\\OCM\\Events\\ResourceTypeRegisterEvent' => $baseDir . '/lib/public/OCM/Events/ResourceTypeRegisterEvent.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index d37f75b8496..1f29b6cb3b6 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -601,6 +601,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Notification\\INotification' => __DIR__ . '/../../..' . '/lib/public/Notification/INotification.php', 'OCP\\Notification\\INotifier' => __DIR__ . '/../../..' . '/lib/public/Notification/INotifier.php', 'OCP\\Notification\\IncompleteNotificationException' => __DIR__ . '/../../..' . '/lib/public/Notification/IncompleteNotificationException.php', + 'OCP\\Notification\\IncompleteParsedNotificationException' => __DIR__ . '/../../..' . '/lib/public/Notification/IncompleteParsedNotificationException.php', 'OCP\\Notification\\InvalidValueException' => __DIR__ . '/../../..' . '/lib/public/Notification/InvalidValueException.php', 'OCP\\Notification\\UnknownNotificationException' => __DIR__ . '/../../..' . '/lib/public/Notification/UnknownNotificationException.php', 'OCP\\OCM\\Events\\ResourceTypeRegisterEvent' => __DIR__ . '/../../..' . '/lib/public/OCM/Events/ResourceTypeRegisterEvent.php', diff --git a/lib/private/Notification/Manager.php b/lib/private/Notification/Manager.php index 63374cea21f..df9d338beb0 100644 --- a/lib/private/Notification/Manager.php +++ b/lib/private/Notification/Manager.php @@ -36,6 +36,7 @@ use OCP\Notification\IDeferrableApp; use OCP\Notification\IDismissableNotifier; use OCP\Notification\IManager; use OCP\Notification\IncompleteNotificationException; +use OCP\Notification\IncompleteParsedNotificationException; use OCP\Notification\INotification; use OCP\Notification\INotifier; use OCP\Notification\UnknownNotificationException; @@ -365,13 +366,14 @@ class Manager implements IManager { } if (!$notification->isValidParsed()) { - throw new \InvalidArgumentException('The given notification has not been handled'); + $this->logger->info('Notification was claimed to be parsed, but was not fully parsed by ' . get_class($notifier) . ' [app: ' . $notification->getApp() . ', subject: ' . $notification->getSubject() . ']'); + throw new IncompleteParsedNotificationException(); } } if (!$notification->isValidParsed()) { $this->logger->info('Notification was not parsed by any notifier [app: ' . $notification->getApp() . ', subject: ' . $notification->getSubject() . ']'); - throw new \InvalidArgumentException('The given notification has not been handled'); + throw new IncompleteParsedNotificationException(); } return $notification; diff --git a/lib/public/Notification/INotifier.php b/lib/public/Notification/INotifier.php index 8be9ee1bdb0..2014f73d5aa 100644 --- a/lib/public/Notification/INotifier.php +++ b/lib/public/Notification/INotifier.php @@ -52,10 +52,13 @@ interface INotifier { * @return INotification * @throws UnknownNotificationException When the notification was not prepared by a notifier * @throws AlreadyProcessedException When the notification is not needed anymore and should be deleted + * @throws IncompleteParsedNotificationException Only to be thrown by the {@see IManager} * @since 9.0.0 * @since 30.0.0 Notifiers should throw {@see UnknownNotificationException} instead of \InvalidArgumentException * when they did not handle the notification. Throwing \InvalidArgumentException directly is deprecated and will * be logged as an error in Nextcloud 39. + * @since 30.0.0 Throws {@see IncompleteParsedNotificationException} when not all required fields + * are set at the end of the manager or after a INotifier that claimed to have parsed the notification. */ public function prepare(INotification $notification, string $languageCode): INotification; } diff --git a/lib/public/Notification/IncompleteParsedNotificationException.php b/lib/public/Notification/IncompleteParsedNotificationException.php new file mode 100644 index 00000000000..0a8ca8a61e6 --- /dev/null +++ b/lib/public/Notification/IncompleteParsedNotificationException.php @@ -0,0 +1,46 @@ + + * + * @author Joas Schilling + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCP\Notification; + +/** + * Thrown when {@see \OCP\Notification\IManager::prepare()} is called with a notification + * that does not have all required fields set at the end of the manager or after a INotifier + * that claimed to have parsed the notification. + * + * Required fields are: + * + * - app + * - user + * - dateTime + * - objectType + * - objectId + * - parsedSubject + * + * @since 30.0.0 + */ +class IncompleteParsedNotificationException extends \InvalidArgumentException { +} From 6545fed34ad8061c293f3975801eb4ff9eea10f2 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 10 Apr 2024 17:26:52 +0200 Subject: [PATCH 5/6] fix(notifications): Throw AlreadyProcessedException also from the manager when it's done Signed-off-by: Joas Schilling --- lib/private/Notification/Manager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/private/Notification/Manager.php b/lib/private/Notification/Manager.php index df9d338beb0..d31de6f7950 100644 --- a/lib/private/Notification/Manager.php +++ b/lib/private/Notification/Manager.php @@ -355,7 +355,7 @@ class Manager implements IManager { $notification = $notifier->prepare($notification, $languageCode); } catch (AlreadyProcessedException $e) { $this->markProcessed($notification); - throw new \InvalidArgumentException('The given notification has been processed'); + throw $e; } catch (UnknownNotificationException) { continue; } catch (\InvalidArgumentException $e) { From 874525425c0fd226f210001374b3c5681629436a Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 10 Apr 2024 18:01:50 +0200 Subject: [PATCH 6/6] fix(notifications): Add a warning when using relative links Signed-off-by: Joas Schilling --- lib/private/Notification/Manager.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/private/Notification/Manager.php b/lib/private/Notification/Manager.php index d31de6f7950..5e7c888d4d9 100644 --- a/lib/private/Notification/Manager.php +++ b/lib/private/Notification/Manager.php @@ -376,6 +376,23 @@ class Manager implements IManager { throw new IncompleteParsedNotificationException(); } + $link = $notification->getLink(); + if ($link !== '' && !str_starts_with($link, 'http://') && !str_starts_with($link, 'https://')) { + $this->logger->warning('Link of notification is not an absolute URL and does not work in mobile and desktop clients [app: ' . $notification->getApp() . ', subject: ' . $notification->getSubject() . ']'); + } + + $icon = $notification->getIcon(); + if ($icon !== '' && !str_starts_with($icon, 'http://') && !str_starts_with($icon, 'https://')) { + $this->logger->warning('Icon of notification is not an absolute URL and does not work in mobile and desktop clients [app: ' . $notification->getApp() . ', subject: ' . $notification->getSubject() . ']'); + } + + foreach ($notification->getParsedActions() as $action) { + $link = $action->getLink(); + if ($link !== '' && !str_starts_with($link, 'http://') && !str_starts_with($link, 'https://')) { + $this->logger->warning('Link of action is not an absolute URL and does not work in mobile and desktop clients [app: ' . $notification->getApp() . ', subject: ' . $notification->getSubject() . ']'); + } + } + return $notification; }