Skip to content

Commit

Permalink
feat(api): Add a V3 of the API allowing to give parameters
Browse files Browse the repository at this point in the history
Signed-off-by: Joas Schilling <coding@schilljs.com>
  • Loading branch information
nickvergessen committed Jul 23, 2024
1 parent 87d7ff4 commit e056862
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 34 deletions.
1 change: 1 addition & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
['name' => 'Endpoint#deleteAllNotifications', 'url' => '/api/{apiVersion}/notifications', 'verb' => 'DELETE', 'requirements' => ['apiVersion' => '(v1|v2)']],

['name' => 'API#generateNotification', 'url' => '/api/{apiVersion}/admin_notifications/{userId}', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v1|v2)']],
['name' => 'API#generateNotificationV3', 'url' => '/api/{apiVersion}/admin_notifications/{userId}', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v3)']],

['name' => 'Settings#personal', 'url' => '/api/{apiVersion}/settings', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']],
['name' => 'Settings#admin', 'url' => '/api/{apiVersion}/settings/admin', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']],
Expand Down
96 changes: 62 additions & 34 deletions lib/Controller/APIController.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

namespace OCA\Notifications\Controller;

use OCA\Notifications\App;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\OpenAPI;
use OCP\AppFramework\Http\DataResponse;
Expand All @@ -19,8 +20,9 @@
use OCP\IUserManager;
use OCP\Notification\IManager;
use OCP\Notification\InvalidValueException;
use OCP\RichObjectStrings\IValidator;
use OCP\RichObjectStrings\InvalidObjectExeption;
use OCP\RichObjectStrings\IValidator;
use Psr\Log\LoggerInterface;

class APIController extends OCSController {
public function __construct(
Expand All @@ -29,60 +31,88 @@ public function __construct(
protected ITimeFactory $timeFactory,
protected IUserManager $userManager,
protected IManager $notificationManager,
protected App $notificationApp,
protected IValidator $richValidator,
protected LoggerInterface $logger,
) {
parent::__construct($appName, $request);
}

/**
* Generate a notification for a user
* Generate a notification for a user (deprecated, use v3 instead)
*
* @param string $userId ID of the user
* @param string $shortMessage Subject of the notification
* @param string $longMessage Message of the notification
* @param string $richSubject Subject of the notification with placeholders
* @param string $richSubjectParameters Rich objects to fill the subject placeholders, {@see \OCP\RichObjectStrings\Definitions}
* @param string $richMessage Message of the notification with placeholders
* @param string $richMessageParameters Rich objects to fill the message placeholders, {@see \OCP\RichObjectStrings\Definitions}
* @return DataResponse<Http::STATUS_OK, array<empty>, array{}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_NOT_FOUND|Http::STATUS_INTERNAL_SERVER_ERROR, null, array{}>
* @deprecated 30.0.0
*
* 200: Notification generated successfully
* 400: Generating notification is not possible
* 404: User not found
*/
#[OpenAPI(scope: OpenAPI::SCOPE_ADMINISTRATION)]
public function generateNotification(
public function generateNotification(string $userId, string $shortMessage, string $longMessage = ''): DataResponse {
$response = $this->generateNotificationV3($userId, $shortMessage, $longMessage);
if ($response->getStatus() === Http::STATUS_OK) {
return new DataResponse();
}

// Translate to old status code
$error = $response->getData()['error'] ?? null;
$code = match($error) {
'user' => Http::STATUS_NOT_FOUND,
'subject',
'message' => Http::STATUS_BAD_REQUEST,
default => Http::STATUS_INTERNAL_SERVER_ERROR,
};
return new DataResponse(null, $code);
}

/**
* Generate a notification with rich object parameters for a user
*
* @param string $userId ID of the user
* @param string $subject Subject of the notification
* @param string $message Message of the notification
* @param array $subjectParameters Rich objects to fill the subject placeholders, {@see \OCP\RichObjectStrings\Definitions}
* @param array $messageParameters Rich objects to fill the message placeholders, {@see \OCP\RichObjectStrings\Definitions}
* @return DataResponse<Http::STATUS_OK, array{id: int}, array<string, mixed>>|DataResponse<Http::STATUS_BAD_REQUEST, array{error: string}, array<string, mixed>>
*
* 200: Notification generated successfully, returned id is the notification ID for future delete requests
* 400: Provided data was invalid, check error field of the response of log file for details
*/
#[OpenAPI(scope: OpenAPI::SCOPE_ADMINISTRATION)]
public function generateNotificationV3(
string $userId,
string $shortMessage = '',
string $longMessage = '',
string $richSubject = '',
array $richSubjectParameters = [],
string $richMessage = '',
array $richMessageParameters = [],
string $subject = '',
string $message = '',
array $subjectParameters = [],
array $messageParameters = [],
): DataResponse {
$user = $this->userManager->get($userId);

if (!$user instanceof IUser) {
return new DataResponse(null, Http::STATUS_NOT_FOUND);
return new DataResponse(['error' => 'user'], Http::STATUS_BAD_REQUEST);
}

if (($shortMessage === '' && $richSubject === '') || strlen($shortMessage) > 255) {
return new DataResponse(null, Http::STATUS_BAD_REQUEST);
if ($subject === '' || strlen($subject) > 255) {
return new DataResponse(['error' => 'subject'], Http::STATUS_BAD_REQUEST);
}

if ($longMessage !== '' && strlen($longMessage) > 4000) {
return new DataResponse(null, Http::STATUS_BAD_REQUEST);
if ($message !== '' && strlen($message) > 4000) {
return new DataResponse(['error' => 'message'], Http::STATUS_BAD_REQUEST);
}

$notification = $this->notificationManager->createNotification();
$datetime = $this->timeFactory->getDateTime();

try {
if ($richSubject !== '') {
$this->richValidator->validate($richSubject, $richSubjectParameters);
if (!empty($subjectParameters)) {
$this->richValidator->validate($subject, $subjectParameters);
}
if ($richMessage !== '') {
$this->richValidator->validate($richMessage, $richMessageParameters);
if ($message !== '' && !empty($messageParameters)) {
$this->richValidator->validate($message, $messageParameters);
}
$notification->setApp('admin_notifications')
->setUser($user->getUID())
Expand All @@ -91,32 +121,30 @@ public function generateNotification(
->setSubject(
'ocs',
[
'parsed' => $shortMessage,
'rich' => $richSubject,
'parameters' => $richSubjectParameters,
'subject' => $subject,
'parameters' => $subjectParameters,
]
);

if ($longMessage !== '' || $richMessage !== '') {
if ($message !== '') {
$notification->setMessage(
'ocs',
[
'parsed' => $longMessage,
'rich' => $richMessage,
'parameters' => $richMessageParameters,
'message' => $message,
'parameters' => $messageParameters,
]
);
}

$this->notificationManager->notify($notification);
} catch (InvalidObjectExeption $e) {
return new DataResponse('Invalid rich object: '.$e->getMessage(), Http::STATUS_BAD_REQUEST);
$this->logger->error('Invalid rich object parameter provided: ' . $e->getMessage(), ['exception' => $e]);
return new DataResponse(['error' => 'parameters'], Http::STATUS_BAD_REQUEST);
} catch (InvalidValueException $e) {
return new DataResponse($e->getMessage(), Http::STATUS_BAD_REQUEST);
} catch (\InvalidArgumentException) {
return new DataResponse(null, Http::STATUS_INTERNAL_SERVER_ERROR);
$this->logger->error('Invalid value for notification provided: ' . $e->getMessage(), ['exception' => $e]);
return new DataResponse(['error' => $e->getMessage()], Http::STATUS_BAD_REQUEST);
}

return new DataResponse();
return new DataResponse(['id' => (int) $this->notificationApp->getLastInsertedId()]);
}
}

0 comments on commit e056862

Please sign in to comment.