fix(addresses): require group visibility for book creation
This commit is contained in:
@@ -175,7 +175,7 @@ def _scope_id_for_create(principal: ApiPrincipal, payload: AddressBookCreateRequ
|
|||||||
group_id = _trim(payload.group_id)
|
group_id = _trim(payload.group_id)
|
||||||
if not group_id:
|
if not group_id:
|
||||||
raise AddressBookError("Group address books require a group id.")
|
raise AddressBookError("Group address books require a group id.")
|
||||||
if principal.group_ids and group_id not in principal.group_ids and not principal.has("addresses:address_book:admin"):
|
if group_id not in principal.group_ids and not principal.has("addresses:address_book:admin"):
|
||||||
raise AddressBookError("The selected group is not visible to the current principal.")
|
raise AddressBookError("The selected group is not visible to the current principal.")
|
||||||
return tenant_id, group_id
|
return tenant_id, group_id
|
||||||
raise AddressBookError("Unsupported address book scope.")
|
raise AddressBookError("Unsupported address book scope.")
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ from govoplan_addresses.backend.schemas import (
|
|||||||
)
|
)
|
||||||
from govoplan_addresses.backend.manifest import manifest
|
from govoplan_addresses.backend.manifest import manifest
|
||||||
from govoplan_addresses.backend.service import (
|
from govoplan_addresses.backend.service import (
|
||||||
|
AddressBookError,
|
||||||
address_book_contact_counts,
|
address_book_contact_counts,
|
||||||
address_list_entry_counts,
|
address_list_entry_counts,
|
||||||
create_address_book,
|
create_address_book,
|
||||||
@@ -146,6 +147,15 @@ class ReadOnlyPrincipal(Principal):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class NoGroupPrincipal(Principal):
|
||||||
|
group_ids = frozenset()
|
||||||
|
|
||||||
|
|
||||||
|
class AddressBookAdminPrincipal(NoGroupPrincipal):
|
||||||
|
def has(self, scope: str) -> bool:
|
||||||
|
return scope == "addresses:address_book:admin" or super().has(scope)
|
||||||
|
|
||||||
|
|
||||||
class AddressServiceTest(unittest.TestCase):
|
class AddressServiceTest(unittest.TestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
engine = create_engine("sqlite:///:memory:")
|
engine = create_engine("sqlite:///:memory:")
|
||||||
@@ -169,6 +179,29 @@ class AddressServiceTest(unittest.TestCase):
|
|||||||
self.session = sessionmaker(bind=engine)()
|
self.session = sessionmaker(bind=engine)()
|
||||||
self.principal = Principal()
|
self.principal = Principal()
|
||||||
|
|
||||||
|
def test_group_book_creation_requires_membership_or_admin_scope(self) -> None:
|
||||||
|
with self.assertRaisesRegex(AddressBookError, "selected group is not visible"):
|
||||||
|
create_address_book(
|
||||||
|
self.session,
|
||||||
|
NoGroupPrincipal(),
|
||||||
|
AddressBookCreateRequest(scope_type="group", group_id="group-2", name="Unassigned"),
|
||||||
|
)
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(AddressBookError, "selected group is not visible"):
|
||||||
|
create_address_book(
|
||||||
|
self.session,
|
||||||
|
self.principal,
|
||||||
|
AddressBookCreateRequest(scope_type="group", group_id="group-2", name="Other group"),
|
||||||
|
)
|
||||||
|
|
||||||
|
admin_book = create_address_book(
|
||||||
|
self.session,
|
||||||
|
AddressBookAdminPrincipal(),
|
||||||
|
AddressBookCreateRequest(scope_type="group", group_id="group-2", name="Admin-created"),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(admin_book.scope_id, "group-2")
|
||||||
|
|
||||||
def test_scoped_book_contact_lookup_and_soft_delete(self) -> None:
|
def test_scoped_book_contact_lookup_and_soft_delete(self) -> None:
|
||||||
book = create_address_book(self.session, self.principal, AddressBookCreateRequest(scope_type="user", name="Personal"))
|
book = create_address_book(self.session, self.principal, AddressBookCreateRequest(scope_type="user", name="Personal"))
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|||||||
Reference in New Issue
Block a user