Skip to content

Commit 8f70cee

Browse files
committed
A limited admin, an administrator and a manager can always remove a watcher from an object.
1 parent 79ddc37 commit 8f70cee

10 files changed

Lines changed: 99 additions & 7 deletions

File tree

changes/TI-1935.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
A limited admin, an administrator and a manager can always remove a watcher from an object. [elioschmutz]

opengever/api/permissions.zcml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@
88
<permission id="opengever.api.ManageGroups" title="opengever.api: Manage Groups" />
99
<permission id="opengever.api.NotifyArbitraryUsers" title="opengever.api: Notify Arbitrary Users" />
1010
<permission id="opengever.api.AccessErrorLog" title="opengever.api: Access error log" />
11+
<permission id="opengever.api.RemoveAnyWatcher" title="opengever.api: Remove any watcher" />
1112

1213
</configure>

opengever/api/tests/test_watchers.py

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -851,24 +851,77 @@ def test_delete_raises_forbidden_if_not_allowed(self):
851851

852852
def test_can_delete_returns_true_for_current_user(self):
853853
self.login(self.regular_user)
854+
855+
center = notification_center()
856+
center.add_watcher_to_resource(self.task, self.regular_user.getId(), WATCHER_ROLE)
857+
858+
self.assertTrue(WatcherDeleter(self.task).can_delete(self.regular_user.getId()))
859+
860+
def test_can_delete_returns_true_if_actor_has_watcher_role(self):
861+
self.login(self.regular_user)
862+
center = notification_center()
863+
864+
# No one is watching with the WATCHER_ROLE
865+
self.assertItemsEqual(
866+
[],
867+
[watcher.actorid for watcher in center.get_watchers(self.task, WATCHER_ROLE)]
868+
)
869+
870+
# But with other roles
871+
self.assertItemsEqual(
872+
[self.regular_user.getId(), self.dossier_responsible.getId()],
873+
[watcher.actorid for watcher in center.get_watchers(self.task)]
874+
)
875+
876+
# Delete should not be possible because the WATCHER_ROLE is missing for the user
877+
self.assertFalse(WatcherDeleter(self.task).can_delete(self.regular_user.getId()))
878+
879+
center.add_watcher_to_resource(self.task, self.regular_user.getId(), WATCHER_ROLE)
880+
881+
self.assertItemsEqual(
882+
[self.regular_user.getId()],
883+
[watcher.actorid for watcher in center.get_watchers(self.task, WATCHER_ROLE)]
884+
)
885+
886+
# Now it's possible because the user is watching with the required role
854887
self.assertTrue(WatcherDeleter(self.task).can_delete(self.regular_user.getId()))
855888

856889
def test_can_delete_returns_true_for_groups(self):
857890
self.login(self.regular_user)
891+
892+
center = notification_center()
893+
center.add_watcher_to_resource(self.task, 'fa_users', WATCHER_ROLE)
894+
858895
self.assertTrue(WatcherDeleter(self.task).can_delete('fa_users'))
859896

860897
def test_can_delete_returns_false_for_foreign_actors_as_editor(self):
861898
self.login(self.regular_user)
899+
900+
center = notification_center()
901+
center.add_watcher_to_resource(self.task, self.dossier_responsible.getId(), WATCHER_ROLE)
902+
862903
self.assertFalse(WatcherDeleter(self.task).can_delete(self.dossier_responsible.getId()))
863904

864-
def test_can_delete_returns_false_for_foreign_actors_as_limited_admin(self):
905+
def test_can_delete_returns_true_for_foreign_actors_as_limited_admin(self):
865906
self.login(self.limited_admin)
866-
self.assertFalse(WatcherDeleter(self.task).can_delete(self.dossier_responsible.getId()))
867907

868-
def test_can_delete_returns_false_for_foreign_actors_as_administrator(self):
908+
center = notification_center()
909+
center.add_watcher_to_resource(self.task, self.dossier_responsible.getId(), WATCHER_ROLE)
910+
911+
self.assertTrue(WatcherDeleter(self.task).can_delete(self.dossier_responsible.getId()))
912+
913+
def test_can_delete_returns_true_for_foreign_actors_as_administrator(self):
869914
self.login(self.administrator)
870-
self.assertFalse(WatcherDeleter(self.task).can_delete(self.dossier_responsible.getId()))
871915

872-
def test_can_delete_returns_false_for_foreign_actors_as_manager(self):
916+
center = notification_center()
917+
center.add_watcher_to_resource(self.task, self.dossier_responsible.getId(), WATCHER_ROLE)
918+
919+
self.assertTrue(WatcherDeleter(self.task).can_delete(self.dossier_responsible.getId()))
920+
921+
def test_can_delete_returns_true_for_foreign_actors_as_manager(self):
873922
self.login(self.manager)
874-
self.assertFalse(WatcherDeleter(self.task).can_delete(self.dossier_responsible.getId()))
923+
924+
center = notification_center()
925+
center.add_watcher_to_resource(self.task, self.dossier_responsible.getId(), WATCHER_ROLE)
926+
927+
self.assertTrue(WatcherDeleter(self.task).can_delete(self.dossier_responsible.getId()))

opengever/api/watchers.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,20 @@ class WatcherDeleter(object):
9898

9999
def __init__(self, context):
100100
self.context = context
101+
self.center = notification_center()
101102

102103
def can_delete(self, actor_id):
103-
# The user can always remove itslef
104+
watchers = self.center.get_watchers(self.context, WATCHER_ROLE)
105+
106+
# Delete watcher is only possible for the WATCHER_ROLE
107+
if actor_id not in [watcher.actorid for watcher in watchers]:
108+
return False
109+
110+
# Always allow depending on a permission
111+
if api.user.has_permission('opengever.api: Remove any watcher', obj=self.context):
112+
return True
113+
114+
# The user can always remove itself
104115
if actor_id == api.user.get_current().getId():
105116
return True
106117

opengever/base/monkey/patches/readonly.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ def getRolesInContext(self, context):
230230
'opengever.api: Manage Role Assignment Reports',
231231
'opengever.api: Notify Arbitrary Users',
232232
'opengever.api: Transfer Assignment',
233+
'opengever.api: Remove any watcher',
233234
'opengever.contact: Edit team',
234235
'opengever.disposition: Edit transfer number',
235236
'opengever.document: Cancel',

opengever/core/lawgiver.zcml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@
233233
opengever.api: Manage Groups,
234234
opengever.api: Manage Role Assignment Reports,
235235
opengever.api: Notify Arbitrary Users,
236+
opengever.api: Remove any watcher,
236237
opengever.api: Transfer Assignment,
237238
opengever.api: View AllowedRolesAndPrincipals,
238239
opengever.bumblebee: Revive Preview,

opengever/core/profiles/default/rolemap.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,12 @@
454454
<role name="Reviewer" />
455455
</permission>
456456

457+
<permission name="opengever.api: Remove any watcher" acquire="True">
458+
<role name="Manager" />
459+
<role name="Administrator" />
460+
<role name="LimitedAdmin" />
461+
</permission>
462+
457463
</permissions>
458464

459465
</rolemap>

opengever/core/upgrades/20250605111905_add_remove_any_watcher_permission/__init__.py

Whitespace-only changes.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<rolemap>
2+
<permissions>
3+
<permission name="opengever.api: Remove any watcher" acquire="True">
4+
<role name="Manager" />
5+
<role name="Administrator" />
6+
<role name="LimitedAdmin" />
7+
</permission>
8+
</permissions>
9+
</rolemap>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from ftw.upgrade import UpgradeStep
2+
3+
4+
class AddRemoveAnyWatcherPermission(UpgradeStep):
5+
"""Add remove any watcher permission.
6+
"""
7+
8+
def __call__(self):
9+
self.install_upgrade_profile()

0 commit comments

Comments
 (0)