From a8693bf9f24b334bb016a0ca379f6a87adce2764 Mon Sep 17 00:00:00 2001 From: "v.scharf" Date: Mon, 10 Aug 2026 18:44:47 +0200 Subject: [PATCH 1/2] api-test: notification settings and getting email notifications --- tests/acceptance/bootstrap/CliContext.php | 14 + .../bootstrap/NotificationContext.php | 103 ++ .../acceptance/bootstrap/SettingsContext.php | 192 ++++ tests/acceptance/config/behat.yml | 4 + .../expected-failures-decomposed-storage.md | 5 + .../expected-failures-posix-storage.md | 5 + .../apiNotification/emailNotification.feature | 105 ++ .../apiNotification/notification.feature | 31 + .../apiNotification/spaceNotification.feature | 17 + .../apiSettings/notificationSetting.feature | 929 ++++++++++++++++++ 10 files changed, 1405 insertions(+) create mode 100644 tests/acceptance/features/apiSettings/notificationSetting.feature diff --git a/tests/acceptance/bootstrap/CliContext.php b/tests/acceptance/bootstrap/CliContext.php index be6091f807..2ec3c37694 100644 --- a/tests/acceptance/bootstrap/CliContext.php +++ b/tests/acceptance/bootstrap/CliContext.php @@ -1304,4 +1304,18 @@ public function theCommandShouldNotBeSuccessful(): void { "Expected command to fail with a non-zero exit code, but got 0. Message: " . $jsonResponse["message"] ); } + + /** + * @param string $interval + * + * @return void + */ + #[When('the administrator sends the grouped :interval email notifications using the CLI')] + public function theAdministratorSendsTheGroupedEmailNotifications(string $interval): void { + $body = [ + "command" => "notifications send-email --$interval" + ]; + $this->featureContext->setResponse(CliHelper::runCommand($body)); + $this->theCommandShouldBeSuccessful(); + } } diff --git a/tests/acceptance/bootstrap/NotificationContext.php b/tests/acceptance/bootstrap/NotificationContext.php index 56bc57134a..96925d7563 100644 --- a/tests/acceptance/bootstrap/NotificationContext.php +++ b/tests/acceptance/bootstrap/NotificationContext.php @@ -488,6 +488,71 @@ public function userShouldNotHaveANotificationRelatedToResourceWithSubject( ); } + /** + * filter notification according to subject and space + * + * @param string $subject + * @param string $space + * @param ResponseInterface|null $response + * + * @return array + */ + public function filterNotificationsBySubjectAndSpace( + string $subject, + string $space, + ?ResponseInterface $response = null + ): array { + $filteredNotifications = []; + $response = $response ?? $this->featureContext->getResponse(); + $responseObject = $this->featureContext->getJsonDecodedResponseBodyContent($response); + + if (!isset($responseObject->ocs->data)) { + Assert::fail("Response doesn't contain notification: " . print_r($responseObject, true)); + } + + $notifications = $responseObject->ocs->data; + foreach ($notifications as $notification) { + if (isset($notification->subject) && $notification->subject === $subject + && isset($notification->messageRichParameters->space->name) + && $notification->messageRichParameters->space->name === $space + ) { + $this->notificationIds[] = $notification->notification_id; + $filteredNotifications[] = $notification; + } + } + return $filteredNotifications; + } + + /** + * + * @param string $user + * @param string $resourceOrSpace + * @param string $resource + * @param string $subject + * + * @return void + */ + #[Then('/^user "([^"]*)" should not have a notification related to (resource|space) "([^"]*)" with subject "([^"]*)"$/')] + public function userShouldNotHaveANotificationRelatedToResourceOrSpaceWithSubject( + string $user, + string $resourceOrSpace, + string $resource, + string $subject + ): void { + $response = $this->listAllNotifications($user); + if ($resourceOrSpace === "space") { + $filteredResponse = $this->filterNotificationsBySubjectAndSpace($subject, $resource, $response); + } else { + $filteredResponse = $this->filterNotificationsBySubjectAndResource($subject, $resource, $response); + } + Assert::assertCount( + 0, + $filteredResponse, + "Response should not contain notification related to $resourceOrSpace '$resource'" + . " with subject '$subject' but found" . print_r($filteredResponse, true) + ); + } + /** * * @param string $user @@ -763,4 +828,42 @@ public function userDeletesDeprovisioningNotification(?string $user = null): voi ); $this->featureContext->setResponse($response); } + + /** + * + * @param string $user + * @param string $count + * + * @return void + * + * @throws GuzzleException + */ + #[Then('user :user should have :count emails')] + public function userShouldHaveEmails(string $user, string $count): void { + $expectedCount = (int)$count; + $address = $this->featureContext->getEmailAddressForUser($user); + $this->featureContext->pushEmailRecipientAsMailBox($address); + $mailBox = EmailHelper::getMailBoxFromEmail($address); + + // assert with retries as email delivery might be delayed + $retried = 0; + do { + $mailBoxInfo = EmailHelper::getMailBoxInformation($mailBox, $this->featureContext->getStepLineRef()); + $actualCount = \count($mailBoxInfo); + $tryAgain = $actualCount !== $expectedCount && $retried <= STANDARD_RETRY_COUNT; + $retried++; + if ($tryAgain) { + echo "[INFO] Expected '$expectedCount' emails for mailbox '$mailBox'" + . " but got '$actualCount'. (Retry $retried)\n"; + // wait for 1 second before trying again + sleep(1); + } + } while ($tryAgain); + + Assert::assertCount( + $expectedCount, + $mailBoxInfo, + "Expected '$expectedCount' emails for user '$user' but found '" . \count($mailBoxInfo) . "'" + ); + } } diff --git a/tests/acceptance/bootstrap/SettingsContext.php b/tests/acceptance/bootstrap/SettingsContext.php index ff3d0421a1..46da44a487 100644 --- a/tests/acceptance/bootstrap/SettingsContext.php +++ b/tests/acceptance/bootstrap/SettingsContext.php @@ -518,4 +518,196 @@ public function userDisablesAutoAcceptingUsingSettingsApi(string $user): void { $this->featureContext->setResponse($response); $this->featureContext->rememberUserAutoSyncSetting($user, false); } + + /** + * maps a notification event name + */ + private const EVENT_TO_SETTING = [ + "Share Received" => "event-share-created-options", + "Share Removed" => "event-share-removed-options", + "Share Expired" => "event-share-expired-options", + "Added As Space Member" => "event-space-shared-options", + "Removed As Space Member" => "event-space-unshared-options", + "Space Membership Expired" => "event-space-membership-expired-options", + "Space Disabled" => "event-space-disabled-options", + "Space Deleted" => "event-space-deleted-options", + "File Rejected" => "event-postprocessing-step-finished-options", + ]; + + /** + * @param string $user + * @param string $enableOrDisable + * @param array $event + * + * @return ResponseInterface + * + * @throws GuzzleException + * @throws Exception + */ + public function sendRequestToEnableOrDisableNotificationForEvent( + string $user, + string $enableOrDisable, + array $event + ): ResponseInterface { + Assert::assertArrayHasKey( + $event['event'], + self::EVENT_TO_SETTING, + "Unknown notification event '{$event['event']}'" + ); + $settingName = self::EVENT_TO_SETTING[$event['event']]; + + $profileBundlesList = $this->getBundleByName($user, "Profile"); + Assert::assertNotEmpty($profileBundlesList, "bundles list is empty"); + + $settingId = ''; + foreach ($profileBundlesList["settings"] as $value) { + if ($value["name"] === $settingName) { + $settingId = $value["id"]; + break; + } + } + Assert::assertNotEmpty($settingId, "settingId for '$settingName' is empty"); + + $enable = \in_array($enableOrDisable, ["enables", "enabled"], true); + $value = [ + "account_uuid" => "me", + "bundleId" => $profileBundlesList["id"], + "settingId" => $settingId, + "resource" => [ + "type" => "TYPE_USER" + ], + ]; + foreach (explode(',', $event['notificationTypes']) as $type) { + $value["collectionValue"]["values"][] = [ + "key" => $type, + "boolValue" => $enable, + ]; + } + $body = json_encode(["value" => $value], JSON_THROW_ON_ERROR); + + return SettingsHelper::updateSettings( + $this->featureContext->getBaseUrl(), + $user, + $this->featureContext->getPasswordForUser($user), + $body, + $this->featureContext->getStepLineRef() + ); + } + + /** + * @param string $user + * @param string $enableOrDisable + * @param TableNode $table + * + * @return void + * + * @throws GuzzleException + * @throws Exception + */ + #[When('/^user "([^"]*)" (disables|enables) notification for the following event using the settings API:$/')] + public function userEnablesOrDisablesNotificationForTheFollowingEventUsingTheSettingsApi( + string $user, + string $enableOrDisable, + TableNode $table + ): void { + $response = $this->sendRequestToEnableOrDisableNotificationForEvent( + $user, + $enableOrDisable, + $table->getRowsHash() + ); + $this->featureContext->setResponse($response); + } + + /** + * @param string $user + * @param string $enableOrDisable + * @param TableNode $table + * + * @return void + * + * @throws GuzzleException + * @throws Exception + */ + #[Given('/^user "([^"]*)" has (disabled|enabled) notification for the following event using the settings API:$/')] + public function userHasEnabledOrDisabledNotificationForTheFollowingEventUsingTheSettingsApi( + string $user, + string $enableOrDisable, + TableNode $table + ): void { + $response = $this->sendRequestToEnableOrDisableNotificationForEvent( + $user, + $enableOrDisable, + $table->getRowsHash() + ); + $this->featureContext->theHTTPStatusCodeShouldBe( + 201, + "Expected response status code should be 201", + $response + ); + } + + /** + * @param string $user + * @param string $interval + * + * @return ResponseInterface + * + * @throws GuzzleException + * @throws Exception + */ + public function sendRequestToSetEmailSendingInterval(string $user, string $interval): ResponseInterface { + $profileBundlesList = $this->getBundleByName($user, "Profile"); + Assert::assertNotEmpty($profileBundlesList, "bundles list is empty"); + + $settingId = ''; + foreach ($profileBundlesList["settings"] as $value) { + if ($value["name"] === "email-sending-interval-options") { + $settingId = $value["id"]; + break; + } + } + Assert::assertNotEmpty($settingId, "settingId for 'email-sending-interval-options' is empty"); + + $body = json_encode( + [ + "value" => [ + "accountUuid" => "me", + "bundleId" => $profileBundlesList["id"], + "settingId" => $settingId, + "resource" => [ + "type" => "TYPE_USER" + ], + "stringValue" => $interval + ] + ], + JSON_THROW_ON_ERROR + ); + + return SettingsHelper::updateSettings( + $this->featureContext->getBaseUrl(), + $user, + $this->featureContext->getPasswordForUser($user), + $body, + $this->featureContext->getStepLineRef() + ); + } + + /** + * @param string $user + * @param string $interval + * + * @return void + * + * @throws GuzzleException + * @throws Exception + */ + #[Given('user :user has set the email sending interval to :interval using the settings API')] + public function userHasSetTheEmailSendingInterval(string $user, string $interval): void { + $response = $this->sendRequestToSetEmailSendingInterval($user, $interval); + $this->featureContext->theHTTPStatusCodeShouldBe( + 201, + "Expected response status code should be 201", + $response + ); + } } diff --git a/tests/acceptance/config/behat.yml b/tests/acceptance/config/behat.yml index 37008dbfd3..39d04b02cf 100644 --- a/tests/acceptance/config/behat.yml +++ b/tests/acceptance/config/behat.yml @@ -187,6 +187,7 @@ default: - OcConfigContext: - SharingNgContext: - OcmContext: + - CliContext: apiAntivirus: paths: @@ -347,6 +348,9 @@ default: - FeatureContext: *common_feature_context_params - GraphContext: - SettingsContext: + - SpacesContext: + - SharingNgContext: + - NotificationContext: apiSharingNgShareInvitation: paths: diff --git a/tests/acceptance/expected-failures-decomposed-storage.md b/tests/acceptance/expected-failures-decomposed-storage.md index 5e93d5f941..e47954807a 100644 --- a/tests/acceptance/expected-failures-decomposed-storage.md +++ b/tests/acceptance/expected-failures-decomposed-storage.md @@ -350,6 +350,11 @@ _ocdav: api compatibility, return correct status code_ - [apiSharingNg1/shareFileVersions.feature:55](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiSharingNg1/shareFileVersions.feature#L55) - [apiSharingNg1/shareFileVersions.feature:56](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiSharingNg1/shareFileVersions.feature#L56) +### notification issue #323 +- [apiNotification/emailNotification.feature:280](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiNotification/emailNotification.feature#L280) +- [apiNotification/emailNotification.feature:298](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiNotification/emailNotification.feature#L298) +- [apiNotification/spaceNotification.feature:463](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiNotification/spaceNotification.feature#L463) + ### Won't fix Not everything needs to be implemented for opencloud. diff --git a/tests/acceptance/expected-failures-posix-storage.md b/tests/acceptance/expected-failures-posix-storage.md index 035b126b91..f7389c873d 100644 --- a/tests/acceptance/expected-failures-posix-storage.md +++ b/tests/acceptance/expected-failures-posix-storage.md @@ -355,6 +355,11 @@ tests/acceptance/features/cliCommands/restoreTrashBinItems.feature - [apiSharingNg1/shareFileVersions.feature:55](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiSharingNg1/shareFileVersions.feature#L55) - [apiSharingNg1/shareFileVersions.feature:56](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiSharingNg1/shareFileVersions.feature#L56) +### notification issue #323 +- [apiNotification/emailNotification.feature:280](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiNotification/emailNotification.feature#L280) +- [apiNotification/emailNotification.feature:298](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiNotification/emailNotification.feature#L298) +- [apiNotification/spaceNotification.feature:463](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiNotification/spaceNotification.feature#L463) + ### Won't fix Not everything needs to be implemented for opencloud. diff --git a/tests/acceptance/features/apiNotification/emailNotification.feature b/tests/acceptance/features/apiNotification/emailNotification.feature index 774345a0eb..b08d2f8a9e 100644 --- a/tests/acceptance/features/apiNotification/emailNotification.feature +++ b/tests/acceptance/features/apiNotification/emailNotification.feature @@ -257,3 +257,108 @@ Feature: Email notification Click here to view it: %base_url%/files/shares/with-me """ + + + Scenario: user gets an email notification when a received share expires + Given using SharingNG + And user "Alice" has uploaded file with content "hello world" to "lorem.txt" + And user "Alice" has sent the following resource share invitation: + | resource | lorem.txt | + | space | Personal | + | sharee | Brian | + | shareType | user | + | permissionsRole | Viewer | + When user "Alice" expires the last share of resource "lorem.txt" inside of the space "Personal" + Then the HTTP status code should be "200" + When user "Brian" lists the shares shared with him using the Graph API + Then user "Brian" should have received the following email from user "Alice" + """ + Your share to lorem.txt has expired at + """ + + + Scenario: user gets an email notification when a space membership expires + Given the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API + And user "Alice" has created a space "new-space" with the default quota using the Graph API + And user "Alice" has sent the following space share invitation: + | space | new-space | + | sharee | Brian | + | shareType | user | + | permissionsRole | Space Viewer | + When user "Alice" expires the user share of space "new-space" for user "Brian" + Then the HTTP status code should be "200" + # trigger the email notification + When user "Brian" lists the shares shared with him using the Graph API + Then user "Brian" should have received the following email from user "Alice" + """ + Your membership of space new-space has expired at + """ + + + Scenario: user gets an email notification when a received share is removed + Given user "Alice" has uploaded file with content "sample text" to "lorem.txt" + And user "Alice" has sent the following resource share invitation: + | resource | lorem.txt | + | space | Personal | + | sharee | Brian | + | shareType | user | + | permissionsRole | Viewer | + When user "Alice" has removed the access of user "Brian" from resource "lorem.txt" of space "Personal" + Then user "Brian" should have received the following email from user "Alice" + """ + Hello Brian Murphy + + %displayname% has unshared "lorem.txt" with you. + """ + + + Scenario: no email is sent when the email sending interval is set to never + Given user "Brian" has set the email sending interval to "never" using the settings API + And user "Alice" has uploaded file with content "sample text" to "lorem.txt" + And user "Alice" has uploaded file with content "more sample text" to "textfile.txt" + And user "Alice" has sent the following resource share invitation: + | resource | lorem.txt | + | space | Personal | + | sharee | Brian | + | shareType | user | + | permissionsRole | Viewer | + And user "Alice" has sent the following resource share invitation: + | resource | textfile.txt | + | space | Personal | + | sharee | Brian | + | shareType | user | + | permissionsRole | Viewer | + Then user "Brian" should have "0" emails + + + Scenario Outline: queued notifications are delivered as one grouped email when the interval is + Given user "Brian" has set the email sending interval to "" using the settings API + And user "Alice" has uploaded file with content "sample text" to "lorem.txt" + And user "Alice" has uploaded file with content "more sample text" to "textfile.txt" + And user "Alice" has sent the following resource share invitation: + | resource | lorem.txt | + | space | Personal | + | sharee | Brian | + | shareType | user | + | permissionsRole | Viewer | + And user "Alice" has sent the following resource share invitation: + | resource | textfile.txt | + | space | Personal | + | sharee | Brian | + | shareType | user | + | permissionsRole | Viewer | + And user "Brian" should have "0" emails + When the administrator sends the grouped "" email notifications using the CLI + Then user "Brian" should have received the following email from user "Alice" + """ + %displayname% has shared "lorem.txt" with you. + """ + And user "Brian" should have received the following email from user "Alice" + """ + %displayname% has shared "textfile.txt" with you. + """ + And user "Brian" should have "1" emails + Examples: + | interval | + | daily | + | weekly | diff --git a/tests/acceptance/features/apiNotification/notification.feature b/tests/acceptance/features/apiNotification/notification.feature index ca654860f5..b873186b16 100644 --- a/tests/acceptance/features/apiNotification/notification.feature +++ b/tests/acceptance/features/apiNotification/notification.feature @@ -3,6 +3,17 @@ Feature: Notification I want to be notified of various events So that I can stay updated about the information + | Event | In-App received | Mail received | + | Share Received | apiNotification/notification.feature:27 | apiNotification/emailNotification.feature:33 | + | Share Removed | apiNotification/notification.feature:145 | apiNotification/emailNotification.feature:298 | + | Share Expired | apiNotification/notification.feature:346 | apiNotification/emailNotification.feature:262 | + | Added as space member | apiNotification/spaceNotification.feature:21 | apiNotification/emailNotification.feature:14 | + | Removed as space member | apiNotification/spaceNotification.feature:150 | apiNotification/emailNotification.feature:183 | + | Space membership expired | apiNotification/spaceNotification.feature:463 | apiNotification/emailNotification.feature:280 | + | Space disabled | apiNotification/spaceNotification.feature:280 | not implemented in backend | + | Space deleted | apiNotification/spaceNotification.feature:455 | not implemented in backend | + | File rejected | apiAntivirus/antivirus.feature:29 | not implemented in backend | + Background: Given these users have been created with default attributes: | username | @@ -330,3 +341,23 @@ Feature: Notification | resource | | textfile1.txt | | my_data | + + + Scenario Outline: user gets an in-app notification when a received share expires + Given using SharingNG + And user "Alice" has sent the following resource share invitation: + | resource | | + | space | Personal | + | sharee | Brian | + | shareType | user | + | permissionsRole | Viewer | + When user "Alice" expires the last share of resource "" inside of the space "Personal" + Then the HTTP status code should be "200" + When user "Brian" lists the shares shared with him using the Graph API + Then user "Brian" should get a notification with subject "Share expired" and message: + | message | + | Access to expired | + Examples: + | resource | + | textfile1.txt | + | my_data | diff --git a/tests/acceptance/features/apiNotification/spaceNotification.feature b/tests/acceptance/features/apiNotification/spaceNotification.feature index bf33c39b60..4ad280a05a 100644 --- a/tests/acceptance/features/apiNotification/spaceNotification.feature +++ b/tests/acceptance/features/apiNotification/spaceNotification.feature @@ -450,3 +450,20 @@ Feature: Notification When user "Brian" lists all notifications Then the HTTP status code should be "200" And there should be "2" notifications + + + Scenario: get a notification of space deleted + Given user "Alice" has disabled a space "notification checking" + When user "Alice" has deleted a space "notification checking" + Then user "Brian" should get a notification with subject "Space deleted" and message: + | message | + | Alice Hansen deleted Space notification checking | + + + Scenario: get a notification of space membership expired + When user "Alice" expires the user share of space "notification checking" for user "Brian" + Then the HTTP status code should be "200" + # trigger the notification to be sent to the user + And user "Brian" should get a notification with subject "Membership expired" and message: + | message | + | Access to Space notification checking lost | diff --git a/tests/acceptance/features/apiSettings/notificationSetting.feature b/tests/acceptance/features/apiSettings/notificationSetting.feature new file mode 100644 index 0000000000..e3b61f0cee --- /dev/null +++ b/tests/acceptance/features/apiSettings/notificationSetting.feature @@ -0,0 +1,929 @@ +@notification +Feature: Disable notifications for individual events + As a user + I want to disable notifications for specific events + So that I do not get notified of unimportant events + + | Event | Event description | In-App | Mail | + | Share Received | Notify when I have received a share | x | x | + | Share Removed | Notify when a received share has been removed | x | | + | Share Expired | Notify when a received share has expired | x | x | + | Added as space member | Notify when I have been added as a member to a space | x | x | + | Removed as space member | Notify when I have been removed as member from a space | x | x | + | Space membership expired | Notify when a space membership has expired | x | x | + | Space disabled | Notify when a space I am member of has been disabled | x | | + | Space deleted | Notify when a space I am member of has been deleted | x | | + | File rejected | Notify when a file I uploaded was rejected (virus/policy violation)| x | | + # "File rejected" (subject "Virus found") notification is covered in apiAntivirus/antivirus.feature + + Background: + Given these users have been created with default attributes: + | username | + | Alice | + | Brian | + And user "Alice" has uploaded file with content "some data" to "lorem.txt" + + @email + Scenario: disable mail and in-app notification for "Share Received" event + When user "Brian" disables notification for the following event using the settings API: + | event | Share Received | + | notificationTypes | mail,in-app | + Then the HTTP status code should be "201" + And the JSON data of the response should match + """ + { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "object", + "required": ["identifier","value"], + "properties": { + "identifier":{ + "type": "object", + "required": ["extension","bundle","setting"], + "properties": { + "extension":{ "const": "opencloud-accounts" }, + "bundle":{ "const": "profile" }, + "setting":{ "const": "event-share-created-options" } + } + }, + "value":{ + "type": "object", + "required": ["id","bundleId","settingId","accountUuid","resource","collectionValue"], + "properties":{ + "id":{ "pattern":"%uuidv4_pattern%" }, + "bundleId":{ "pattern":"%uuidv4_pattern%" }, + "settingId":{ "pattern":"%uuidv4_pattern%" }, + "accountUuid":{ "pattern":"%uuidv4_pattern%" }, + "resource":{ + "type": "object", + "required":["type"], + "properties": { + "type":{ "const": "TYPE_USER" } + } + }, + "collectionValue":{ + "type": "object", + "required":["values"], + "properties": { + "values":{ + "type": "array", + "maxItems": 2, + "minItems": 2, + "uniqueItems": true, + "items": { + "oneOf": [ + { + "type": "object", + "required": ["key","boolValue"], + "properties": { + "key":{ "const": "mail" }, + "boolValue":{ "const": false } + } + }, + { + "type": "object", + "required": ["key","boolValue"], + "properties": { + "key":{ "const": "in-app" }, + "boolValue":{ "const": false } + } + } + ] + } + } + } + } + } + } + } + } + } + } + """ + And user "Alice" has sent the following resource share invitation: + | resource | lorem.txt | + | space | Personal | + | sharee | Brian | + | shareType | user | + | permissionsRole | Viewer | + And user "Brian" should have "0" emails + When user "Brian" lists all notifications + Then the HTTP status code should be "200" + And the notifications should be empty + + @email + Scenario: disable mail and in-app notification for "Share Removed" event + And user "Alice" has sent the following resource share invitation: + | resource | lorem.txt | + | space | Personal | + | sharee | Brian | + | shareType | user | + | permissionsRole | Viewer | + When user "Brian" disables notification for the following event using the settings API: + | event | Share Removed | + | notificationTypes | mail,in-app | + Then the HTTP status code should be "201" + And the JSON data of the response should match + """ + { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "object", + "required": ["identifier","value"], + "properties": { + "identifier":{ + "type": "object", + "required": ["extension","bundle","setting"], + "properties": { + "extension":{ "const": "opencloud-accounts" }, + "bundle":{ "const": "profile" }, + "setting":{ "const": "event-share-removed-options" } + } + }, + "value":{ + "type": "object", + "required": ["id","bundleId","settingId","accountUuid","resource","collectionValue"], + "properties":{ + "id":{ "pattern":"%uuidv4_pattern%" }, + "bundleId":{ "pattern":"%uuidv4_pattern%" }, + "settingId":{ "pattern":"%uuidv4_pattern%" }, + "accountUuid":{ "pattern":"%uuidv4_pattern%" }, + "resource":{ + "type": "object", + "required":["type"], + "properties": { + "type":{ "const": "TYPE_USER" } + } + }, + "collectionValue":{ + "type": "object", + "required":["values"], + "properties": { + "values":{ + "type": "array", + "maxItems": 2, + "minItems": 2, + "uniqueItems": true, + "items": { + "oneOf": [ + { + "type": "object", + "required": ["key","boolValue"], + "properties": { + "key":{ "const": "mail" }, + "boolValue":{ "const": false } + } + }, + { + "type": "object", + "required": ["key","boolValue"], + "properties": { + "key":{ "const": "in-app" }, + "boolValue":{ "const": false } + } + } + ] + } + } + } + } + } + } + } + } + } + } + """ + And user "Alice" has removed the access of user "Brian" from resource "lorem.txt" of space "Personal" + And user "Brian" should have "1" emails + And user "Brian" should get a notification with subject "Resource shared" and message: + | message | + | Alice Hansen shared lorem.txt with you | + But user "Brian" should not have a notification related to resource "lorem.txt" with subject "Resource unshared" + + @email + Scenario: disable mail and in-app notification for "Share Removed" event (Project space) + Given using spaces DAV path + And the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API + And user "Alice" has created a space "newSpace" with the default quota using the Graph API + And user "Alice" has uploaded a file inside space "newSpace" with content "some content" to "insideSpace.txt" + And user "Alice" has sent the following resource share invitation: + | resource | insideSpace.txt | + | space | newSpace | + | sharee | Brian | + | shareType | user | + | permissionsRole | Viewer | + When user "Brian" disables notification for the following event using the settings API: + | event | Share Removed | + | notificationTypes | mail,in-app | + Then the HTTP status code should be "201" + And the JSON data of the response should match + """ + { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "object", + "required": ["identifier","value"], + "properties": { + "identifier":{ + "type": "object", + "required": ["extension","bundle","setting"], + "properties": { + "extension":{ "const": "opencloud-accounts" }, + "bundle":{ "const": "profile" }, + "setting":{ "const": "event-share-removed-options" } + } + }, + "value":{ + "type": "object", + "required": ["id","bundleId","settingId","accountUuid","resource","collectionValue"], + "properties":{ + "id":{ "pattern":"%user_id_pattern%" }, + "bundleId":{ "pattern":"%user_id_pattern%" }, + "settingId":{ "pattern":"%user_id_pattern%" }, + "accountUuid":{ "pattern":"%user_id_pattern%" }, + "resource":{ + "type": "object", + "required":["type"], + "properties": { + "type":{ "const": "TYPE_USER" } + } + }, + "collectionValue":{ + "type": "object", + "required":["values"], + "properties": { + "values":{ + "type": "array", + "maxItems": 2, + "minItems": 2, + "uniqueItems": true, + "items": { + "oneOf": [ + { + "type": "object", + "required": ["key","boolValue"], + "properties": { + "key":{ "const": "mail" }, + "boolValue":{ "const": false } + } + }, + { + "type": "object", + "required": ["key","boolValue"], + "properties": { + "key":{ "const": "in-app" }, + "boolValue":{ "const": false } + } + } + ] + } + } + } + } + } + } + } + } + } + } + """ + And user "Alice" has removed the access of user "Brian" from resource "insideSpace.txt" of space "newSpace" + And user "Brian" should have "1" emails + And user "Brian" should get a notification with subject "Resource shared" and message: + | message | + | Alice Hansen shared insideSpace.txt with you | + But user "Brian" should not have a notification related to resource "insideSpace.txt" with subject "Resource unshared" + + @email + Scenario: disable mail and in-app notification for "Share Expired" event + Given using SharingNG + And user "Alice" has uploaded file with content "hello world" to "testfile.txt" + When user "Brian" disables notification for the following event using the settings API: + | event | Share Expired | + | notificationTypes | mail,in-app | + Then the HTTP status code should be "201" + And the JSON data of the response should match + """ + { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "object", + "required": ["identifier","value"], + "properties": { + "identifier":{ + "type": "object", + "required": ["extension","bundle","setting"], + "properties": { + "extension":{ "const": "opencloud-accounts" }, + "bundle":{ "const": "profile" }, + "setting":{ + "const": "event-share-expired-options" + } + } + }, + "value":{ + "type": "object", + "required": ["id","bundleId","settingId","accountUuid","resource","collectionValue"], + "properties":{ + "id":{ "pattern":"%uuidv4_pattern%" }, + "bundleId":{ "pattern":"%uuidv4_pattern%" }, + "settingId":{ "pattern":"%uuidv4_pattern%" }, + "accountUuid":{ "pattern":"%uuidv4_pattern%" }, + "resource":{ + "type": "object", + "required":["type"], + "properties": { + "type":{ "const": "TYPE_USER" } + } + }, + "collectionValue":{ + "type": "object", + "required":["values"], + "properties": { + "values":{ + "type": "array", + "maxItems": 2, + "minItems": 2, + "uniqueItems": true, + "items": { + "oneOf": [ + { + "type": "object", + "required": ["key","boolValue"], + "properties": { + "key":{ "const": "mail" }, + "boolValue":{ "const": false } + } + }, + { + "type": "object", + "required": ["key","boolValue"], + "properties": { + "key":{ "const": "in-app" }, + "boolValue":{ "const": false } + } + } + ] + } + } + } + } + } + } + } + } + } + } + """ + + @email + Scenario Outline: no in-app and mail notification should appear when "Share Expired" event is disabled (Personal space) + Given using SharingNG + And user "Alice" has created folder "my_data" + And user "Alice" has uploaded file with content "hello world" to "lorem.txt" + And user "Brian" has disabled notification for the following event using the settings API: + | event | Share Expired | + | notificationTypes | mail,in-app | + And user "Alice" has sent the following resource share invitation: + | resource | | + | space | Personal | + | sharee | Brian | + | shareType | user | + | permissionsRole | Viewer | + When user "Alice" expires the last share of resource "" inside of the space "Personal" + Then the HTTP status code should be "200" + And user "Brian" should have "1" emails + And user "Brian" should have received the following email from user "Alice" + """ + Hello Brian Murphy + + %displayname% has shared "" with you. + + Click here to view it: %base_url%/files/shares/with-me + """ + And user "Brian" should get a notification with subject "Resource shared" and message: + | message | + | Alice Hansen shared with you | + But user "Brian" should not have a notification related to space "Alice Hansen" with subject "Share expired" + Examples: + | resource | + | lorem.txt | + | my_data | + + @email + Scenario Outline: no in-app and mail notification should appear when "Share Expired" event is disabled (Project space) + Given using spaces DAV path + And using SharingNG + And the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API + And user "Alice" has created a space "NewSpace" with the default quota using the Graph API + And user "Alice" has created a folder "uploadFolder" in space "NewSpace" + And user "Alice" has uploaded a file inside space "NewSpace" with content "share space items" to "lorem.txt" + And user "Alice" has sent the following resource share invitation: + | resource | | + | space | NewSpace | + | sharee | Brian | + | shareType | user | + | permissionsRole | Viewer | + And user "Brian" has disabled notification for the following event using the settings API: + | event | Share Expired | + | notificationTypes | mail,in-app | + When user "Alice" expires the last share of resource "" inside of the space "NewSpace" + Then the HTTP status code should be "200" + And user "Brian" should have "1" emails + And user "Brian" should have received the following email from user "Alice" about the share of project space "NewSpace" + """ + Hello Brian Murphy + + %displayname% has shared "" with you. + + Click here to view it: %base_url%/files/shares/with-me + """ + And user "Brian" should get a notification with subject "Resource shared" and message: + | message | + | Alice Hansen shared with you | + But user "Brian" should not have a notification related to space "NewSpace" with subject "Share expired" + Examples: + | resource | + | lorem.txt | + | uploadFolder | + + @email + Scenario: disable mail and in-app notification for "Added as space member" event + Given using spaces DAV path + And the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API + And user "Alice" has created a space "newSpace" with the default quota using the Graph API + When user "Brian" disables notification for the following event using the settings API: + | event | Added As Space Member | + | notificationTypes | mail,in-app | + Then the HTTP status code should be "201" + And the JSON data of the response should match + """ + { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "object", + "required": ["identifier","value"], + "properties": { + "identifier":{ + "type": "object", + "required": ["extension","bundle","setting"], + "properties": { + "extension":{ "const": "opencloud-accounts" }, + "bundle":{ "const": "profile" }, + "setting":{ "const": "event-space-shared-options" } + } + }, + "value":{ + "type": "object", + "required": ["id","bundleId","settingId","accountUuid","resource","collectionValue"], + "properties":{ + "id":{ "pattern":"%uuidv4_pattern%" }, + "bundleId":{ "pattern":"%uuidv4_pattern%" }, + "settingId":{ "pattern":"%uuidv4_pattern%" }, + "accountUuid":{ "pattern":"%uuidv4_pattern%" }, + "resource":{ + "type": "object", + "required":["type"], + "properties": { + "type":{ "const": "TYPE_USER" } + } + }, + "collectionValue":{ + "type": "object", + "required":["values"], + "properties": { + "values":{ + "type": "array", + "maxItems": 2, + "minItems": 2, + "uniqueItems": true, + "items": { + "oneOf": [ + { + "type": "object", + "required": ["key","boolValue"], + "properties": { + "key":{ "const": "mail" }, + "boolValue":{ "const": false } + } + }, + { + "type": "object", + "required": ["key","boolValue"], + "properties": { + "key":{ "const": "in-app" }, + "boolValue":{ "const": false } + } + } + ] + } + } + } + } + } + } + } + } + } + } + """ + And user "Alice" has sent the following space share invitation: + | space | newSpace | + | sharee | Brian | + | shareType | user | + | permissionsRole | Space Viewer | + When user "Brian" lists all notifications + Then the HTTP status code should be "200" + And the notifications should be empty + And user "Brian" should have "0" emails + + @email + Scenario: disable mail and in-app notification for "Removed as space member" event + Given using spaces DAV path + And the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API + And user "Alice" has created a space "newSpace" with the default quota using the Graph API + And user "Alice" has sent the following space share invitation: + | space | newSpace | + | sharee | Brian | + | shareType | user | + | permissionsRole | Space Viewer | + When user "Brian" disables notification for the following event using the settings API: + | event | Removed As Space Member | + | notificationTypes | mail,in-app | + Then the HTTP status code should be "201" + And the JSON data of the response should match + """ + { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "object", + "required": ["identifier","value"], + "properties": { + "identifier":{ + "type": "object", + "required": ["extension","bundle","setting"], + "properties": { + "extension":{ "const": "opencloud-accounts" }, + "bundle":{ "const": "profile" }, + "setting":{ "const": "event-space-unshared-options" } + } + }, + "value":{ + "type": "object", + "required": ["id","bundleId","settingId","accountUuid","resource","collectionValue"], + "properties":{ + "id":{ "pattern":"%uuidv4_pattern%" }, + "bundleId":{ "pattern":"%uuidv4_pattern%" }, + "settingId":{ "pattern":"%uuidv4_pattern%" }, + "accountUuid":{ "pattern":"%uuidv4_pattern%" }, + "resource":{ + "type": "object", + "required":["type"], + "properties": { + "type":{ "const": "TYPE_USER" } + } + }, + "collectionValue":{ + "type": "object", + "required":["values"], + "properties": { + "values":{ + "type": "array", + "maxItems": 2, + "minItems": 2, + "uniqueItems": true, + "items": { + "oneOf": [ + { + "type": "object", + "required": ["key","boolValue"], + "properties": { + "key":{ "const": "mail" }, + "boolValue":{ "const": false } + } + }, + { + "type": "object", + "required": ["key","boolValue"], + "properties": { + "key":{ "const": "in-app" }, + "boolValue":{ "const": false } + } + } + ] + } + } + } + } + } + } + } + } + } + } + """ + And user "Alice" has removed the access of user "Brian" from space "newSpace" + And user "Brian" should get a notification with subject "Space shared" and message: + | message | + | Alice Hansen added you to Space newSpace | + But user "Brian" should not have a notification related to space "newSpace" with subject "Removed from Space" + And user "Brian" should have "1" emails + And user "Brian" should have received the following email from user "Alice" about the share of project space "newSpace" + """ + Hello Brian Murphy, + + %displayname% has invited you to join "newSpace". + + Click here to view it: %base_url%/f/%space_id% + """ + + @email + Scenario: disable mail and in-app notification for "Space Membership Expired" event + Given using spaces DAV path + And the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API + And user "Alice" has created a space "newSpace" with the default quota using the Graph API + And user "Alice" has sent the following space share invitation: + | space | newSpace | + | sharee | Brian | + | shareType | user | + | permissionsRole | Space Viewer | + When user "Brian" disables notification for the following event using the settings API: + | event | Space Membership Expired | + | notificationTypes | mail,in-app | + Then the HTTP status code should be "201" + And the JSON data of the response should match + """ + { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "object", + "required": ["identifier","value"], + "properties": { + "identifier":{ + "type": "object", + "required": ["extension","bundle","setting"], + "properties": { + "extension":{ "const": "opencloud-accounts" }, + "bundle":{ "const": "profile" }, + "setting":{ "const": "event-space-membership-expired-options" } + } + }, + "value":{ + "type": "object", + "required": ["id","bundleId","settingId","accountUuid","resource","collectionValue"], + "properties":{ + "id":{ "pattern":"%uuidv4_pattern%" }, + "bundleId":{ "pattern":"%uuidv4_pattern%" }, + "settingId":{ "pattern":"%uuidv4_pattern%" }, + "accountUuid":{ "pattern":"%uuidv4_pattern%" }, + "resource":{ + "type": "object", + "required":["type"], + "properties": { + "type":{ "const": "TYPE_USER" } + } + }, + "collectionValue":{ + "type": "object", + "required":["values"], + "properties": { + "values":{ + "type": "array", + "maxItems": 2, + "minItems": 2, + "uniqueItems": true, + "items": { + "oneOf": [ + { + "type": "object", + "required": ["key","boolValue"], + "properties": { + "key":{ "const": "mail" }, + "boolValue":{ "const": false } + } + }, + { + "type": "object", + "required": ["key","boolValue"], + "properties": { + "key":{ "const": "in-app" }, + "boolValue":{ "const": false } + } + } + ] + } + } + } + } + } + } + } + } + } + } + """ + When user "Alice" expires the user share of space "newSpace" for user "Brian" + Then the HTTP status code should be "200" + And user "Brian" should get a notification with subject "Space shared" and message: + | message | + | Alice Hansen added you to Space newSpace | + But user "Brian" should not have a notification related to space "newSpace" with subject "Membership expired" + And user "Brian" should have "1" emails + And user "Brian" should have received the following email from user "Alice" about the share of project space "newSpace" + """ + Hello Brian Murphy, + + %displayname% has invited you to join "newSpace". + + Click here to view it: %base_url%/f/%space_id% + """ + + + Scenario: disable in-app notification for "Space disabled" event (note: no mail notification) + Given the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API + And user "Alice" has created a space "new-space" with the default quota using the Graph API + And user "Alice" has sent the following space share invitation: + | space | new-space | + | sharee | Brian | + | shareType | user | + | permissionsRole | Space Viewer | + When user "Brian" disables notification for the following event using the settings API: + | event | Space Disabled | + | notificationTypes | in-app | + Then the HTTP status code should be "201" + And the JSON data of the response should match + """ + { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "object", + "required": ["identifier","value"], + "properties": { + "identifier":{ + "type": "object", + "required": ["extension","bundle","setting"], + "properties": { + "extension":{ "const": "opencloud-accounts" }, + "bundle":{ "const": "profile" }, + "setting":{ + "const": "event-space-disabled-options" + } + } + }, + "value":{ + "type": "object", + "required": [ + "id", + "bundleId", + "settingId", + "accountUuid", + "resource", + "collectionValue" + ], + "properties":{ + "id":{ "pattern":"%uuidv4_pattern%" }, + "bundleId":{ "pattern":"%uuidv4_pattern%" }, + "settingId":{ "pattern":"%uuidv4_pattern%" }, + "accountUuid":{ "pattern":"%uuidv4_pattern%" }, + "resource":{ + "type": "object", + "required":["type"], + "properties": { + "type":{ "const": "TYPE_USER" } + } + }, + "collectionValue":{ + "type": "object", + "required":["values"], + "properties": { + "values":{ + "type": "array", + "maxItems": 1, + "minItems": 1, + "uniqueItems": true, + "items": { + "oneOf": [ + { + "type": "object", + "required": [ + "key", + "boolValue" + ], + "properties": { + "key":{ "const": "in-app" }, + "boolValue":{ "const": false } + } + } + ] + } + } + } + } + } + } + } + } + } + } + """ + And user "Alice" has disabled a space "new-space" + And user "Brian" should get a notification with subject "Space shared" and message: + | message | + | Alice Hansen added you to Space new-space | + But user "Brian" should not have a notification related to space "new-space" with subject "Space disabled" + + + Scenario: disable in-app notification for "Space Deleted" event + Given the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API + And user "Alice" has created a space "new-space" with the default quota using the Graph API + And user "Alice" has sent the following space share invitation: + | space | new-space | + | sharee | Brian | + | shareType | user | + | permissionsRole | Space Viewer | + When user "Brian" disables notification for the following event using the settings API: + | event | Space Deleted | + | notificationTypes | in-app | + Then the HTTP status code should be "201" + And the JSON data of the response should match + """ + { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "object", + "required": ["identifier", "value"], + "properties": { + "identifier": { + "type": "object", + "required": ["extension", "bundle", "setting"], + "properties": { + "extension": { "const": "opencloud-accounts" }, + "bundle": { "const": "profile" }, + "setting": { "const": "event-space-deleted-options" } + } + }, + "value": { + "type": "object", + "required": ["id", "bundleId", "settingId", "accountUuid", "resource", "collectionValue"], + "properties": { + "id": { "pattern": "%user_id_pattern%" }, + "bundleId": { "pattern": "%user_id_pattern%" }, + "settingId": { "pattern": "%user_id_pattern%" }, + "accountUuid": { "pattern": "%user_id_pattern%" }, + "resource": { + "type": "object", + "required": ["type"], + "properties": { + "type": { "const": "TYPE_USER" } + } + }, + "collectionValue": { + "type": "object", + "required": ["values"], + "properties": { + "values": { + "type": "array", + "minItems": 1, + "maxItems": 1, + "items": { + "type": "object", + "required": ["key", "boolValue"], + "properties": { + "key": { "const": "in-app" }, + "boolValue": { "const": false } + } + } + } + } + } + } + } + } + } + } + } + """ + And user "Alice" has disabled a space "new-space" + And user "Alice" has deleted a space "new-space" + When user "Brian" lists all notifications + Then the HTTP status code should be "200" + And user "Brian" should not have any notification From 100ac2dc14debed4a05080f77f8fc1c9b3deadb7 Mon Sep 17 00:00:00 2001 From: "v.scharf" Date: Thu, 13 Aug 2026 10:05:40 +0200 Subject: [PATCH 2/2] disable all email notifications --- .../acceptance/TestHelpers/SettingsHelper.php | 8 +++ .../acceptance/bootstrap/SettingsContext.php | 29 ++++++++++ .../apiSettings/notificationSetting.feature | 53 +++++++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/tests/acceptance/TestHelpers/SettingsHelper.php b/tests/acceptance/TestHelpers/SettingsHelper.php index b0407b9bfe..a9c539fc9c 100644 --- a/tests/acceptance/TestHelpers/SettingsHelper.php +++ b/tests/acceptance/TestHelpers/SettingsHelper.php @@ -30,6 +30,7 @@ */ class SettingsHelper { private static string $settingsEndpoint = '/api/v0/settings/'; + private const BUNDLE_ID = "2a506de7-99bd-4f0d-994e-c38e72c28fd9"; /** * @param string $baseUrl @@ -41,6 +42,13 @@ public static function buildFullUrl(string $baseUrl, string $path): string { return $baseUrl . self::$settingsEndpoint . $path; } + /** + * @return string + */ + public static function getBundleId(): string { + return self::BUNDLE_ID; + } + /** * @param string $baseUrl * @param string $user diff --git a/tests/acceptance/bootstrap/SettingsContext.php b/tests/acceptance/bootstrap/SettingsContext.php index 46da44a487..cd561f8184 100644 --- a/tests/acceptance/bootstrap/SettingsContext.php +++ b/tests/acceptance/bootstrap/SettingsContext.php @@ -532,6 +532,7 @@ public function userDisablesAutoAcceptingUsingSettingsApi(string $user): void { "Space Disabled" => "event-space-disabled-options", "Space Deleted" => "event-space-deleted-options", "File Rejected" => "event-postprocessing-step-finished-options", + "Disable Email Notifications" => "33ffb5d6-cd07-4dc0-afb0-84f7559ae438", ]; /** @@ -710,4 +711,32 @@ public function userHasSetTheEmailSendingInterval(string $user, string $interval $response ); } + + /** + * @param string $user + * + * @return void + */ + #[When('user :user disables email notification using the settings API')] + public function userDisablesEmailNotificationUsingTheSettingsAPI(string $user): void { + $body = [ + "value" => [ + "account_uuid" => "me", + "bundleId" => SettingsHelper::getBundleId(), + "settingId" => self::EVENT_TO_SETTING["Disable Email Notifications"], + "resource" => [ + "type" => "TYPE_USER", + ], + "boolValue" => true, + ], + ]; + $response = SettingsHelper::updateSettings( + $this->featureContext->getBaseUrl(), + $this->featureContext->getActualUsername($user), + $this->featureContext->getPasswordForUser($user), + json_encode($body), + $this->featureContext->getStepLineRef() + ); + $this->featureContext->setResponse($response); + } } diff --git a/tests/acceptance/features/apiSettings/notificationSetting.feature b/tests/acceptance/features/apiSettings/notificationSetting.feature index e3b61f0cee..a0909ec93c 100644 --- a/tests/acceptance/features/apiSettings/notificationSetting.feature +++ b/tests/acceptance/features/apiSettings/notificationSetting.feature @@ -23,6 +23,59 @@ Feature: Disable notifications for individual events | Brian | And user "Alice" has uploaded file with content "some data" to "lorem.txt" + @email + Scenario: disable all email notifications + When user "Brian" disables email notification using the settings API + Then the HTTP status code should be "201" + And the JSON data of the response should match + """ + { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "object", + "required": ["identifier","value"], + "properties": { + "identifier":{ + "type": "object", + "required": ["extension","bundle","setting"], + "properties": { + "extension":{ "const": "opencloud-accounts" }, + "bundle":{ "const": "profile" }, + "setting":{ "const": "disable-email-notifications" } + } + }, + "value":{ + "type": "object", + "required": ["id","bundleId","settingId","accountUuid","resource"], + "properties":{ + "id":{ "pattern": "%uuidv4_pattern%" }, + "bundleId":{ "pattern":"%uuidv4_pattern%" }, + "settingId":{ "pattern":"%uuidv4_pattern%" }, + "accountUuid":{ "pattern":"%uuidv4_pattern%" }, + "resource":{ + "type": "object", + "required":["type"], + "properties": { + "type":{ "const": "TYPE_USER" } + } + } + } + } + } + } + } + } + """ + And user "Alice" has sent the following resource share invitation: + | resource | lorem.txt | + | space | Personal | + | sharee | Brian | + | shareType | user | + | permissionsRole | Viewer | + And user "Brian" should have "0" emails + @email Scenario: disable mail and in-app notification for "Share Received" event When user "Brian" disables notification for the following event using the settings API: