-
Notifications
You must be signed in to change notification settings - Fork 83
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[SDESK-7459] Implement ability for a Module to register new privileges (
#2813) * Implement privilege registry for async app SDESK-7459 * Cleanup code and add tests SDESK-7459 * Remove not needed yield/teardown SDESK-7459
- Loading branch information
Showing
6 changed files
with
152 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
from dataclasses import dataclass | ||
from quart_babel.speaklater import LazyString | ||
|
||
|
||
@dataclass(frozen=True) | ||
class Privilege: | ||
name: str | ||
label: LazyString | None = None | ||
category: LazyString | None = None | ||
description: LazyString | None = None | ||
|
||
|
||
class PrivilegesRegistry: | ||
__privileges: set[Privilege] | frozenset[Privilege] | ||
|
||
def __init__(self): | ||
self.__privileges = set() | ||
|
||
def add(self, privilege: Privilege): | ||
"""Add a privilege if the registry is not locked.""" | ||
|
||
if self.is_locked: | ||
raise RuntimeError("Cannot add privileges after the app has started.") | ||
|
||
self.__privileges.add(privilege) # type: ignore[union-attr] | ||
|
||
@property | ||
def is_locked(self): | ||
return isinstance(self.__privileges, frozenset) | ||
|
||
def lock(self): | ||
"""Lock the registry by converting the privileges to a frozenset.""" | ||
|
||
if not self.is_locked: | ||
self.__privileges = frozenset(self.__privileges) | ||
|
||
def get_all(self) -> list[Privilege]: | ||
"""Retrieve all privileges.""" | ||
|
||
return list(self.__privileges) | ||
|
||
def __contains__(self, name: str) -> bool: | ||
"""Check if a privilege exists.""" | ||
|
||
return any(priv.name == name for priv in self.__privileges) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from quart_babel import lazy_gettext | ||
|
||
from superdesk.core.module import Module | ||
from superdesk.core.privileges import Privilege | ||
|
||
module = Module( | ||
name="tests.module_with_privileges", | ||
privileges=[ | ||
Privilege(name="can_test", description=lazy_gettext("Test privilege can test")), | ||
Privilege(name="can_play", description=lazy_gettext("Test privilege can play")), | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import pytest | ||
from superdesk.core.privileges import PrivilegesRegistry, Privilege | ||
|
||
|
||
@pytest.fixture(scope="function") | ||
def registry(): | ||
return PrivilegesRegistry() | ||
|
||
|
||
def test_add_privilege_before_lock(registry): | ||
privilege = Privilege(name="edit_article") | ||
|
||
registry.add(privilege) | ||
|
||
assert "edit_article" in registry | ||
assert registry.get_all() == [privilege] | ||
|
||
|
||
def test_add_multiple_privileges(registry): | ||
privilege1 = Privilege(name="edit_article") | ||
privilege2 = Privilege(name="delete_article") | ||
|
||
registry.add(privilege1) | ||
registry.add(privilege2) | ||
|
||
assert "edit_article" in registry | ||
assert "delete_article" in registry | ||
assert len(registry.get_all()) == 2 | ||
|
||
|
||
def test_lock_registry(registry): | ||
privilege = Privilege(name="edit_article") | ||
|
||
registry.add(privilege) | ||
registry.lock() | ||
|
||
assert registry.is_locked | ||
assert "edit_article" in registry | ||
|
||
|
||
def test_cannot_add_after_lock(registry): | ||
privilege = Privilege(name="edit_article") | ||
|
||
registry.add(privilege) | ||
registry.lock() | ||
|
||
with pytest.raises(RuntimeError): | ||
registry.add(Privilege(name="new_privilege")) | ||
|
||
|
||
def test_lock_prevents_further_additions(registry): | ||
privilege = Privilege(name="edit_article") | ||
|
||
registry.add(privilege) | ||
registry.lock() | ||
|
||
with pytest.raises(RuntimeError, match="Cannot add privileges after the app has started."): | ||
registry.add(Privilege(name="new_privilege")) | ||
|
||
assert len(registry.get_all()) == 1 | ||
assert registry.is_locked |