Skip to content

Commit

Permalink
Merge pull request #2109 from nextcloud/feat/1206/self-test-push
Browse files Browse the repository at this point in the history
feat(push): Add option to send a self-test
  • Loading branch information
nickvergessen authored Dec 2, 2024
2 parents 37aa8ee + 85fe878 commit db651ff
Show file tree
Hide file tree
Showing 11 changed files with 326 additions and 3 deletions.
1 change: 1 addition & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

['name' => 'API#generateNotification', 'url' => '/api/{apiVersion}/admin_notifications/{userId}', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v1|v2)']],
['name' => 'API#generateNotificationV3', 'url' => '/api/{apiVersion3}/admin_notifications/{userId}', 'verb' => 'POST', 'requirements' => ['apiVersion3' => '(v3)']],
['name' => 'API#selfTestPush', 'url' => '/api/{apiVersion3}/test/self', 'verb' => 'POST', 'requirements' => ['apiVersion3' => '(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
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"lint": "find . -name \\*.php -not -path './vendor/*' -not -path './build/*' -print0 | xargs -0 -n1 php -l",
"cs:check": "php-cs-fixer fix --dry-run --diff",
"cs:fix": "php-cs-fixer fix",
"openapi": "generate-spec",
"openapi": "generate-spec --verbose",
"psalm": "psalm --threads=1",
"psalm:dev": "psalm --no-cache --threads=$(nproc)",
"psalm:update-baseline": "psalm --threads=1 --update-baseline",
Expand Down
1 change: 1 addition & 0 deletions lib/Capabilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public function getCapabilities(): array {
'action-web',
'user-status',
'exists',
'test-push',
],
'push' => [
'devices',
Expand Down
76 changes: 76 additions & 0 deletions lib/Controller/APIController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,23 @@
use OCA\Notifications\App;
use OCA\Notifications\ResponseDefinitions;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\OpenAPI;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IL10N;
use OCP\IRequest;
use OCP\IUser;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\Notification\IManager;
use OCP\Notification\IncompleteNotificationException;
use OCP\Notification\InvalidValueException;
use OCP\RichObjectStrings\InvalidObjectExeption;
use OCP\RichObjectStrings\IValidator;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Output\BufferedOutput;

/**
* @psalm-import-type NotificationsRichObjectParameter from ResponseDefinitions
Expand All @@ -36,9 +40,11 @@ public function __construct(
IRequest $request,
protected ITimeFactory $timeFactory,
protected IUserManager $userManager,
protected IUserSession $userSession,
protected IManager $notificationManager,
protected App $notificationApp,
protected IValidator $richValidator,
protected IL10N $l,
protected LoggerInterface $logger,
) {
parent::__construct($appName, $request);
Expand Down Expand Up @@ -153,4 +159,74 @@ public function generateNotificationV3(

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

/**
* Send a test notification to push registered mobile apps
*
* Required capability: `ocs-endpoints > test-push`
*
* @return DataResponse<Http::STATUS_OK|Http::STATUS_BAD_REQUEST, array{message: string}, array{}>
*
* 200: Test notification generated successfully, but the device should still show the message to the user
* 400: Test notification could not be generated, show the message to the user
*/
#[NoAdminRequired]
#[OpenAPI(scope: 'push')]
public function selfTestPush(): DataResponse {
if (!$this->notificationManager->isFairUseOfFreePushService()) {
$message = $this->l->t('We want to keep offering our push notification service for free, but large users overload our infrastructure. For this reason we have to rate-limit the use of push notifications. If you need this feature, consider using Nextcloud Enterprise.');
return new DataResponse(
['message' => $message],
Http::STATUS_BAD_REQUEST,
);
}

$user = $this->userSession->getUser();
if (!$user instanceof IUser) {
return new DataResponse(
['message' => $this->l->t('User not found')],
Http::STATUS_BAD_REQUEST,
);
}

if (!$this->request->isUserAgent([
IRequest::USER_AGENT_TALK_ANDROID,
IRequest::USER_AGENT_TALK_IOS,
IRequest::USER_AGENT_CLIENT_ANDROID,
IRequest::USER_AGENT_CLIENT_IOS,
])) {
return new DataResponse(
['message' => $this->l->t('The device does not seem to be supported')],
Http::STATUS_BAD_REQUEST,
);
}

$notification = $this->notificationManager->createNotification();
$datetime = $this->timeFactory->getDateTime();
$isTalkApp = $this->request->isUserAgent([
IRequest::USER_AGENT_TALK_ANDROID,
IRequest::USER_AGENT_TALK_IOS,
]);
$app = $isTalkApp ? 'admin_notification_talk' : 'admin_notifications';

$output = new BufferedOutput();
try {
$notification->setApp($app)
->setUser($user->getUID())
->setDateTime($datetime)
->setObject('admin_notifications', dechex($datetime->getTimestamp()))
->setSubject('self', ['Testing push notifications']);

$this->notificationApp->setOutput($output);
$this->notificationManager->notify($notification);
} catch (\InvalidArgumentException $e) {
$this->logger->error('Self testing push notification failed: ' . $e->getMessage(), ['exception' => $e]);
return new DataResponse(
['message' => $this->l->t('An unexpected error occurred, ask your administration to check the logs.')],
Http::STATUS_BAD_REQUEST,
);
}

return new DataResponse(['message' => $output->fetch()]);
}
}
1 change: 1 addition & 0 deletions lib/Notifier/AdminNotifications.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ public function prepare(INotification $notification, string $languageCode): INot
// Deal with known subjects
case 'cli':
case 'ocs':
case 'self':
$subjectParams = $notification->getSubjectParameters();
if (isset($subjectParams['subject'])) {
// Nextcloud 30+
Expand Down
3 changes: 2 additions & 1 deletion lib/Push.php
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,9 @@ public function pushToDevice(int $id, INotification $notification, ?OutputInterf
try {
$this->notificationManager->setPreparingPushNotification(true);
$notification = $this->notificationManager->prepare($notification, $language);
} catch (AlreadyProcessedException|IncompleteParsedNotificationException|\InvalidArgumentException) {
} catch (AlreadyProcessedException|IncompleteParsedNotificationException|\InvalidArgumentException $e) {
// FIXME remove \InvalidArgumentException in Nextcloud 39
$this->printInfo('Error when preparing notification for push: ' . get_class($e));
return;
} finally {
$this->notificationManager->setPreparingPushNotification(false);
Expand Down
117 changes: 117 additions & 0 deletions openapi-full.json
Original file line number Diff line number Diff line change
Expand Up @@ -1453,6 +1453,123 @@
}
}
},
"/ocs/v2.php/apps/notifications/api/{apiVersion3}/test/self": {
"post": {
"operationId": "api-self-test-push",
"summary": "Send a test notification to push registered mobile apps",
"description": "Required capability: `ocs-endpoints > test-push`",
"tags": [
"api"
],
"security": [
{
"bearer_auth": []
},
{
"basic_auth": []
}
],
"parameters": [
{
"name": "apiVersion3",
"in": "path",
"required": true,
"schema": {
"type": "string",
"pattern": "^(v3)$"
}
},
{
"name": "OCS-APIRequest",
"in": "header",
"description": "Required to be true for the API request to pass",
"required": true,
"schema": {
"type": "boolean",
"default": true
}
}
],
"responses": {
"200": {
"description": "Test notification generated successfully, but the device should still show the message to the user",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {
"type": "object",
"required": [
"message"
],
"properties": {
"message": {
"type": "string"
}
}
}
}
}
}
}
}
}
},
"400": {
"description": "Test notification could not be generated, show the message to the user",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {
"type": "object",
"required": [
"message"
],
"properties": {
"message": {
"type": "string"
}
}
}
}
}
}
}
}
}
}
}
}
},
"/ocs/v2.php/apps/notifications/api/{apiVersion}/push": {
"post": {
"operationId": "push-register-device",
Expand Down
Loading

0 comments on commit db651ff

Please sign in to comment.