Skip to content

Commit b0e265e

Browse files
authored
Merge pull request #7834 from LibreSign/backport/7820/stable33
[stable33] Improve notification preference when try to send email notification
2 parents 7d9b629 + 27585c8 commit b0e265e

9 files changed

Lines changed: 597 additions & 85 deletions

lib/Listener/MailNotifyListener.php

Lines changed: 13 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use OCA\Libresign\Service\IdentifyMethod\IdentifyService;
1818
use OCA\Libresign\Service\IdentifyMethod\IIdentifyMethod;
1919
use OCA\Libresign\Service\MailService;
20+
use OCA\Libresign\Service\NotificationPreferenceResolver;
2021
use OCP\EventDispatcher\Event;
2122
use OCP\EventDispatcher\IEventListener;
2223
use OCP\IUser;
@@ -33,6 +34,7 @@ public function __construct(
3334
protected MailService $mail,
3435
private SignRequestMapper $signRequestMapper,
3536
private LoggerInterface $logger,
37+
private NotificationPreferenceResolver $notificationPreferenceResolver,
3638
) {
3739
}
3840

@@ -82,7 +84,11 @@ protected function sendSignMailNotification(
8284
$users = $this->userManager->getByEmail($email);
8385
if (count($users) === 1) {
8486
$userId = $users[0]->getUID();
85-
if ($this->isNotificationDisabledAtActivity($userId, SendSignNotificationEvent::FILE_TO_SIGN)) {
87+
if ($this->notificationPreferenceResolver->isEmailNotificationDisabled(
88+
$userId,
89+
SendSignNotificationEvent::FILE_TO_SIGN,
90+
true,
91+
)) {
8692
return;
8793
}
8894
}
@@ -112,7 +118,11 @@ protected function sendSignedMailNotification(
112118
if ($identifyMethod->getEntity()->isDeletedAccount()) {
113119
return;
114120
}
115-
if ($this->isNotificationDisabledAtActivity($libreSignFile->getUserId(), SignedEvent::FILE_SIGNED)) {
121+
if ($this->notificationPreferenceResolver->isEmailNotificationDisabled(
122+
$libreSignFile->getUserId(),
123+
SignedEvent::FILE_SIGNED,
124+
true,
125+
)) {
116126
return;
117127
}
118128

@@ -158,7 +168,7 @@ protected function sendCanceledMailNotification(
158168
$users = $this->userManager->getByEmail($email);
159169
if (count($users) === 1) {
160170
$userId = $users[0]->getUID();
161-
if ($this->isNotificationDisabledAtActivity($userId, SignRequestCanceledEvent::SIGN_REQUEST_CANCELED)) {
171+
if ($this->notificationPreferenceResolver->isEmailNotificationDisabled($userId, SignRequestCanceledEvent::SIGN_REQUEST_CANCELED, true)) {
162172
return;
163173
}
164174
}
@@ -170,33 +180,4 @@ protected function sendCanceledMailNotification(
170180
return;
171181
}
172182
}
173-
174-
private function isNotificationDisabledAtActivity(string $userId, string $type): bool {
175-
if (!class_exists(\OCA\Activity\UserSettings::class)) {
176-
return false;
177-
}
178-
$activityUserSettings = \OCP\Server::get(\OCA\Activity\UserSettings::class);
179-
if ($activityUserSettings) {
180-
$manager = \OCP\Server::get(\OCP\Activity\IManager::class);
181-
try {
182-
$manager->getSettingById($type);
183-
} catch (\Exception) {
184-
return false;
185-
}
186-
187-
$adminSetting = $activityUserSettings->getAdminSetting('email', $type);
188-
if (!$adminSetting) {
189-
return true;
190-
}
191-
$notificationSetting = $activityUserSettings->getUserSetting(
192-
$userId,
193-
'email',
194-
$type
195-
);
196-
if (!$notificationSetting) {
197-
return true;
198-
}
199-
}
200-
return false;
201-
}
202183
}

lib/Listener/NotificationListener.php

Lines changed: 8 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use OCA\Libresign\Events\SignedEvent;
1717
use OCA\Libresign\Events\SignRequestCanceledEvent;
1818
use OCA\Libresign\Service\IdentifyMethod\IIdentifyMethod;
19+
use OCA\Libresign\Service\NotificationPreferenceResolver;
1920
use OCP\AppFramework\Utility\ITimeFactory;
2021
use OCP\EventDispatcher\Event;
2122
use OCP\EventDispatcher\IEventListener;
@@ -34,6 +35,7 @@ public function __construct(
3435
private ITimeFactory $timeFactory,
3536
protected IURLGenerator $url,
3637
private SignRequestMapper $signRequestMapper,
38+
private NotificationPreferenceResolver $notificationPreferenceResolver,
3739
) {
3840
}
3941

@@ -72,9 +74,10 @@ private function sendSignNotification(
7274
if ($identifyMethod->getEntity()->isDeletedAccount()) {
7375
return;
7476
}
75-
$notificationDisabled = $this->isNotificationDisabledAtActivity(
77+
$notificationDisabled = $this->notificationPreferenceResolver->isInAppNotificationDisabled(
7678
$identifyMethod->getEntity()->getIdentifierValue(),
7779
SendSignNotificationEvent::FILE_TO_SIGN,
80+
true,
7881
);
7982
if ($notificationDisabled) {
8083
return;
@@ -117,9 +120,10 @@ private function sendSignedNotification(
117120
if ($identifyMethod->getEntity()->isDeletedAccount()) {
118121
return;
119122
}
120-
$notificationDisabled = $this->isNotificationDisabledAtActivity(
123+
$notificationDisabled = $this->notificationPreferenceResolver->isInAppNotificationDisabled(
121124
$libreSignFile->getUserId(),
122125
SignedEvent::FILE_SIGNED,
126+
true,
123127
);
124128
if ($notificationDisabled) {
125129
return;
@@ -169,9 +173,10 @@ private function sendCanceledNotification(
169173
if ($identifyMethod->getEntity()->isDeletedAccount()) {
170174
return;
171175
}
172-
$notificationDisabled = $this->isNotificationDisabledAtActivity(
176+
$notificationDisabled = $this->notificationPreferenceResolver->isInAppNotificationDisabled(
173177
$identifyMethod->getEntity()->getIdentifierValue(),
174178
SignRequestCanceledEvent::SIGN_REQUEST_CANCELED,
179+
true,
175180
);
176181
if ($notificationDisabled) {
177182
return;
@@ -204,36 +209,6 @@ private function sendCanceledNotification(
204209
$this->notificationManager->notify($notification);
205210
}
206211

207-
private function isNotificationDisabledAtActivity(string $userId, string $type): bool {
208-
if (!class_exists(\OCA\Activity\UserSettings::class)) {
209-
return false;
210-
}
211-
$activityUserSettings = \OCP\Server::get(\OCA\Activity\UserSettings::class);
212-
if ($activityUserSettings) {
213-
$manager = \OCP\Server::get(\OCP\Activity\IManager::class);
214-
try {
215-
$manager->getSettingById($type);
216-
} catch (\Exception) {
217-
return false;
218-
}
219-
220-
$adminSetting = $activityUserSettings->getAdminSetting('notification', $type);
221-
if (!$adminSetting) {
222-
return true;
223-
}
224-
225-
$notificationSetting = $activityUserSettings->getUserSetting(
226-
$userId,
227-
'notification',
228-
$type
229-
);
230-
if ($notificationSetting === false) {
231-
return true;
232-
}
233-
}
234-
return false;
235-
}
236-
237212
/**
238213
* @psalm-return array{type: 'file', id: string, name: string, path: string, link: string}
239214
*/
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
6+
* SPDX-License-Identifier: AGPL-3.0-or-later
7+
*/
8+
9+
namespace OCA\Libresign\Service;
10+
11+
class ActivitySettingsStore {
12+
private const USER_SETTINGS_CLASS = 'OCA\\Activity\\UserSettings';
13+
14+
private bool $resolved = false;
15+
private ?object $activityUserSettings = null;
16+
17+
public function isAvailable(): bool {
18+
return $this->getActivityUserSettings() !== null;
19+
}
20+
21+
public function hasSetting(string $type): bool {
22+
if (!$this->isAvailable()) {
23+
return false;
24+
}
25+
26+
try {
27+
$manager = \OCP\Server::get(\OCP\Activity\IManager::class);
28+
$manager->getSettingById($type);
29+
return true;
30+
} catch (\Throwable) {
31+
return false;
32+
}
33+
}
34+
35+
public function getAdminSetting(string $channel, string $type): mixed {
36+
return $this->getActivityUserSettings()?->getAdminSetting($channel, $type);
37+
}
38+
39+
public function getUserSetting(string $userId, string $channel, string $type): mixed {
40+
return $this->getActivityUserSettings()?->getUserSetting($userId, $channel, $type);
41+
}
42+
43+
private function getActivityUserSettings(): ?object {
44+
if ($this->resolved) {
45+
return $this->activityUserSettings;
46+
}
47+
48+
$this->resolved = true;
49+
if (!class_exists(self::USER_SETTINGS_CLASS)) {
50+
return null;
51+
}
52+
53+
try {
54+
$activityUserSettings = \OCP\Server::get(self::USER_SETTINGS_CLASS);
55+
if (is_object($activityUserSettings)) {
56+
$this->activityUserSettings = $activityUserSettings;
57+
}
58+
} catch (\Throwable) {
59+
$this->activityUserSettings = null;
60+
}
61+
62+
return $this->activityUserSettings;
63+
}
64+
}

lib/Service/Identify/ResultEnricher.php

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
use OCA\Libresign\Service\IdentifyMethod\Account;
1212
use OCA\Libresign\Service\IdentifyMethod\Email;
13+
use OCA\Libresign\Service\NotificationPreferenceResolver;
1314
use OCP\IUser;
1415
use OCP\IUserManager;
1516
use OCP\IUserSession;
@@ -20,6 +21,7 @@ public function __construct(
2021
private IUserManager $userManager,
2122
private Email $identifyEmailMethod,
2223
private Account $identifyAccountMethod,
24+
private NotificationPreferenceResolver $notificationPreferenceResolver,
2325
) {
2426
}
2527

@@ -111,7 +113,11 @@ public function addEmailNotificationPreference(array $list): array {
111113
continue;
112114
}
113115

114-
$acceptsNotifications = !$this->isNotificationDisabledAtActivity($user->getUID(), 'libresign_file_to_sign');
116+
$acceptsNotifications = !$this->notificationPreferenceResolver->isEmailNotificationDisabled(
117+
$user->getUID(),
118+
'libresign_file_to_sign',
119+
false,
120+
);
115121

116122
if ($acceptsNotifications) {
117123
$list[$key]['emailAddress'] = $email;
@@ -126,23 +132,4 @@ private function userMatchesSearch(IUser $user, string $searchLower): bool {
126132
|| str_contains(strtolower($user->getDisplayName()), $searchLower)
127133
|| ($user->getEMailAddress() !== null && str_contains($user->getEMailAddress(), $searchLower));
128134
}
129-
130-
private function isNotificationDisabledAtActivity(string $userId, string $type): bool {
131-
if (!class_exists(\OCA\Activity\UserSettings::class)) {
132-
return false;
133-
}
134-
$activityUserSettings = \OCP\Server::get(\OCA\Activity\UserSettings::class);
135-
136-
$adminSetting = $activityUserSettings->getAdminSetting('email', $type);
137-
if (!$adminSetting) {
138-
return true;
139-
}
140-
141-
$userSetting = $activityUserSettings->getUserSetting($userId, 'email', $type);
142-
if (!$userSetting) {
143-
return true;
144-
}
145-
146-
return false;
147-
}
148135
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
6+
* SPDX-License-Identifier: AGPL-3.0-or-later
7+
*/
8+
9+
namespace OCA\Libresign\Service;
10+
11+
use OCP\Config\IUserConfig;
12+
use OCP\IAppConfig;
13+
14+
class NotificationPreferenceResolver {
15+
public function __construct(
16+
private IAppConfig $appConfig,
17+
private IUserConfig $userConfig,
18+
private ActivitySettingsStore $activitySettingsStore,
19+
) {
20+
}
21+
22+
public function isEmailNotificationDisabled(
23+
string $userId,
24+
string $type,
25+
bool $requireKnownActivitySetting = true,
26+
): bool {
27+
return $this->isNotificationDisabled($userId, 'email', $type, $requireKnownActivitySetting);
28+
}
29+
30+
public function isInAppNotificationDisabled(
31+
string $userId,
32+
string $type,
33+
bool $requireKnownActivitySetting = true,
34+
): bool {
35+
return $this->isNotificationDisabled($userId, 'notification', $type, $requireKnownActivitySetting);
36+
}
37+
38+
private function isNotificationDisabled(
39+
string $userId,
40+
string $channel,
41+
string $type,
42+
bool $requireKnownActivitySetting,
43+
): bool {
44+
if ($this->activitySettingsStore->isAvailable()) {
45+
if ($requireKnownActivitySetting && !$this->activitySettingsStore->hasSetting($type)) {
46+
return false;
47+
}
48+
49+
$adminSetting = $this->activitySettingsStore->getAdminSetting($channel, $type);
50+
if (!$this->isActivitySettingEnabled($adminSetting)) {
51+
return true;
52+
}
53+
54+
$userSetting = $this->activitySettingsStore->getUserSetting($userId, $channel, $type);
55+
if (!$this->isActivitySettingEnabled($userSetting)) {
56+
return true;
57+
}
58+
59+
return false;
60+
}
61+
62+
$configKey = sprintf('notify_%s_%s', $channel, $type);
63+
if (!$this->isActivitySettingEnabled($this->appConfig->getValueString('activity', $configKey, '1'))) {
64+
return true;
65+
}
66+
67+
return !$this->isActivitySettingEnabled(
68+
$this->userConfig->getValueString($userId, 'activity', $configKey, '1')
69+
);
70+
}
71+
72+
private function isActivitySettingEnabled(mixed $setting): bool {
73+
if (is_bool($setting)) {
74+
return $setting;
75+
}
76+
if (is_int($setting)) {
77+
return $setting === 1;
78+
}
79+
if ($setting === null) {
80+
return true;
81+
}
82+
83+
$normalized = strtolower(trim((string)$setting));
84+
return !in_array($normalized, ['', '0', 'false', 'off', 'no'], true);
85+
}
86+
}

0 commit comments

Comments
 (0)