From b4a877381a83251212660322c374ec88988dafef Mon Sep 17 00:00:00 2001 From: Quentin BEY Date: Thu, 30 Jan 2025 16:45:05 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B(teams)=20disable=20creation=20endp?= =?UTF-8?q?oint=20from=20abilities?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we don't allow the user to see the team creation button, we also want to disable the corresponding API. --- CHANGELOG.md | 1 + src/backend/core/api/client/viewsets.py | 2 +- src/backend/core/api/permissions.py | 15 +++++++ src/backend/core/models.py | 4 +- .../tests/teams/test_core_api_teams_create.py | 41 ++++++++++++++++++- .../tests/users/test_api_users_retrieve.py | 11 ++++- 6 files changed, 68 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63837f9..b7cc066 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to ### Fixed +- 🚑️(teams) do not display add button when disallowed #676 - 🚑️(plugins) fix name from SIRET specific case #674 - 🐛(api) restrict mailbox sync to enabled domains diff --git a/src/backend/core/api/client/viewsets.py b/src/backend/core/api/client/viewsets.py index bc63f5d..3626f7e 100644 --- a/src/backend/core/api/client/viewsets.py +++ b/src/backend/core/api/client/viewsets.py @@ -303,7 +303,7 @@ class TeamViewSet( ): """Team ViewSet""" - permission_classes = [permissions.AccessPermission] + permission_classes = [permissions.TeamPermission, permissions.AccessPermission] serializer_class = serializers.TeamSerializer filter_backends = [filters.OrderingFilter] ordering_fields = ["created_at", "name", "path"] diff --git a/src/backend/core/api/permissions.py b/src/backend/core/api/permissions.py index 30d3731..1ff3668 100644 --- a/src/backend/core/api/permissions.py +++ b/src/backend/core/api/permissions.py @@ -53,3 +53,18 @@ class AccessPermission(IsAuthenticated): """Check permission for a given object.""" abilities = obj.get_abilities(request.user) return abilities.get(request.method.lower(), False) + + +class TeamPermission(IsAuthenticated): + """Permission class for team objects viewset.""" + + def has_permission(self, request, view): + """Check permission only when the user tries to create a new team.""" + if not super().has_permission(request, view): + return False + + if request.method != "POST": + return True + + abilities = request.user.get_abilities() + return abilities["teams"]["can_create"] diff --git a/src/backend/core/models.py b/src/backend/core/models.py index 3f55d0e..535777c 100644 --- a/src/backend/core/models.py +++ b/src/backend/core/models.py @@ -573,7 +573,7 @@ class User(AbstractBaseUser, BaseModel, auth_models.PermissionsMixin): .get() ) - teams_can_view = user_info.teams_can_view + teams_can_view = user_info.teams_can_view or settings.FEATURES["TEAMS_DISPLAY"] mailboxes_can_view = user_info.mailboxes_can_view return { @@ -585,7 +585,7 @@ class User(AbstractBaseUser, BaseModel, auth_models.PermissionsMixin): ), }, "teams": { - "can_view": teams_can_view and settings.FEATURES["TEAMS_DISPLAY"], + "can_view": teams_can_view, "can_create": teams_can_view and settings.FEATURES["TEAMS_CREATE"], }, "mailboxes": { diff --git a/src/backend/core/tests/teams/test_core_api_teams_create.py b/src/backend/core/tests/teams/test_core_api_teams_create.py index 54c40e0..3d0b670 100644 --- a/src/backend/core/tests/teams/test_core_api_teams_create.py +++ b/src/backend/core/tests/teams/test_core_api_teams_create.py @@ -6,6 +6,7 @@ import pytest from rest_framework.status import ( HTTP_201_CREATED, HTTP_401_UNAUTHORIZED, + HTTP_403_FORBIDDEN, ) from rest_framework.test import APIClient @@ -28,7 +29,7 @@ def test_api_teams_create_anonymous(): assert not Team.objects.exists() -def test_api_teams_create_authenticated(): +def test_api_teams_create_authenticated(settings): """ Authenticated users should be able to create teams and should automatically be declared as the owner of the newly created team. @@ -39,6 +40,14 @@ def test_api_teams_create_authenticated(): client = APIClient() client.force_login(user) + settings.FEATURES = { + "TEAMS_DISPLAY": True, + "TEAMS_CREATE": True, + "CONTACTS_DISPLAY": False, + "CONTACTS_CREATE": False, + "MAILBOXES_CREATE": False, + } + response = client.post( "/api/v1.0/teams/", { @@ -54,6 +63,36 @@ def test_api_teams_create_authenticated(): assert team.accesses.filter(role="owner", user=user).exists() +def test_api_teams_create_authenticated_feature_disabled(settings): + """ + Authenticated users should not be able to create teams when feature is disabled. + """ + organization = OrganizationFactory(with_registration_id=True) + user = UserFactory(organization=organization) + + client = APIClient() + client.force_login(user) + + settings.FEATURES = { + "TEAMS_DISPLAY": True, + "TEAMS_CREATE": False, + "CONTACTS_DISPLAY": False, + "CONTACTS_CREATE": False, + "MAILBOXES_CREATE": False, + } + + response = client.post( + "/api/v1.0/teams/", + { + "name": "my team", + }, + format="json", + ) + + assert response.status_code == HTTP_403_FORBIDDEN + assert not Team.objects.exists() + + def test_api_teams_create_cannot_override_organization(): """ Authenticated users should be able to create teams and not diff --git a/src/backend/core/tests/users/test_api_users_retrieve.py b/src/backend/core/tests/users/test_api_users_retrieve.py index 9bb217b..4422c86 100644 --- a/src/backend/core/tests/users/test_api_users_retrieve.py +++ b/src/backend/core/tests/users/test_api_users_retrieve.py @@ -56,7 +56,7 @@ def test_api_users_retrieve_me_authenticated(): "abilities": { "contacts": {"can_create": True, "can_view": True}, "mailboxes": {"can_create": False, "can_view": False}, - "teams": {"can_create": False, "can_view": False}, + "teams": {"can_create": True, "can_view": True}, }, "organization": { "id": str(user.organization.pk), @@ -66,11 +66,18 @@ def test_api_users_retrieve_me_authenticated(): } -def test_api_users_retrieve_me_authenticated_abilities(): +def test_api_users_retrieve_me_authenticated_abilities(settings): """ Authenticated users should be able to retrieve their own user via the "/users/me" path with the proper abilities. """ + settings.FEATURES = { + "TEAMS_DISPLAY": False, + "TEAMS_CREATE": True, + "CONTACTS_DISPLAY": True, + "CONTACTS_CREATE": True, + "MAILBOXES_CREATE": True, + } user = factories.UserFactory() client = APIClient()