Merge pull request #44770 from nextcloud/techdebt/noid/improved-notification-exceptions

fix(notifications): Improved notification exceptions
This commit is contained in:
Joas Schilling 2024-04-15 09:26:21 +02:00 committed by GitHub
commit 984f00c581
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 361 additions and 213 deletions

View File

@ -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.

View File

@ -567,6 +567,10 @@ 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\\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',
'OCP\\OCM\\Exceptions\\OCMArgumentException' => $baseDir . '/lib/public/OCM/Exceptions/OCMArgumentException.php',
'OCP\\OCM\\Exceptions\\OCMProviderException' => $baseDir . '/lib/public/OCM/Exceptions/OCMProviderException.php',

View File

@ -600,6 +600,10 @@ 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\\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',
'OCP\\OCM\\Exceptions\\OCMArgumentException' => __DIR__ . '/../../..' . '/lib/public/OCM/Exceptions/OCMArgumentException.php',
'OCP\\OCM\\Exceptions\\OCMProviderException' => __DIR__ . '/../../..' . '/lib/public/OCM/Exceptions/OCMProviderException.php',

View File

@ -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 !== '';

View File

@ -35,8 +35,11 @@ use OCP\Notification\IApp;
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;
use OCP\RichObjectStrings\IValidator;
use OCP\Support\Subscription\IRegistry;
use Psr\Container\ContainerExceptionInterface;
@ -300,13 +303,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 +315,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.');
}
}
}
@ -340,12 +345,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();
@ -353,21 +353,44 @@ 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');
throw $e;
} 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()) {
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();
}
$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;
@ -399,6 +422,9 @@ class Manager implements IManager {
return $count;
}
/**
* {@inheritDoc}
*/
public function dismissNotification(INotification $notification): void {
$notifiers = $this->getNotifiers();
@ -406,7 +432,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;
}
}

View File

@ -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())) {

View File

@ -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;

View File

@ -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;

View File

@ -30,16 +30,19 @@ 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
*/
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;
}

View File

@ -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;

View File

@ -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,15 @@ 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
* @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;
}

View File

@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2024 Joas Schilling <coding@schilljs.com>
*
* @author Joas Schilling <coding@schilljs.com>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/
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 {
}

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2024 Joas Schilling <coding@schilljs.com>
*
* @author Joas Schilling <coding@schilljs.com>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/
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 {
}

View File

@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2024 Joas Schilling <coding@schilljs.com>
*
* @author Joas Schilling <coding@schilljs.com>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/
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;
}
}

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2024 Joas Schilling <coding@schilljs.com>
*
* @author Joas Schilling <coding@schilljs.com>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/
namespace OCP\Notification;
/**
* @since 30.0.0
*/
class UnknownNotificationException extends \InvalidArgumentException {
}