from types import SimpleNamespace from django.core.cache import cache from django.test import TestCase from rest_framework.test import APITestCase from apps.users.models import User from apps.workspaces.api.permissions import ( CanWorkspaceManageMembers, IsWorkspaceAdmin, IsWorkspaceMember, IsWorkspaceOwner, ) from apps.workspaces.models import Workspace, WorkspaceMembership class WorkspacePermissionTests(TestCase): @classmethod def setUpTestData(cls): cls.owner = User.objects.create_user(mobile="09127770021", password="secret123") cls.admin = User.objects.create_user(mobile="09127770022", password="secret123") cls.member = User.objects.create_user(mobile="09127770023", password="secret123") cls.guest = User.objects.create_user(mobile="09127770024", password="secret123") cls.outsider = User.objects.create_user(mobile="09127770025", password="secret123") cls.workspace = Workspace.objects.create(name="Workspace Perms", owner=cls.owner) cls.admin_membership = WorkspaceMembership.objects.create( workspace=cls.workspace, user=cls.admin, role=WorkspaceMembership.Role.ADMIN, is_active=True, ) cls.member_membership = WorkspaceMembership.objects.create( workspace=cls.workspace, user=cls.member, role=WorkspaceMembership.Role.MEMBER, is_active=True, ) cls.guest_membership = WorkspaceMembership.objects.create( workspace=cls.workspace, user=cls.guest, role=WorkspaceMembership.Role.GUEST, is_active=True, ) cls.workspace_note = SimpleNamespace(workspace=cls.workspace) def _request_for(self, user): return SimpleNamespace(user=user) def test_is_workspace_owner_handles_workspace_and_membership_objects(self): permission = IsWorkspaceOwner() self.assertTrue( permission.has_object_permission( self._request_for(self.owner), None, self.workspace, ) ) self.assertTrue( permission.has_object_permission( self._request_for(self.owner), None, self.admin_membership, ) ) self.assertFalse( permission.has_object_permission( self._request_for(self.admin), None, self.workspace, ) ) def test_is_workspace_admin_accepts_workspace_related_objects(self): permission = IsWorkspaceAdmin() self.assertTrue( permission.has_object_permission( self._request_for(self.admin), None, self.workspace, ) ) self.assertTrue( permission.has_object_permission( self._request_for(self.admin), None, self.workspace_note, ) ) self.assertFalse( permission.has_object_permission( self._request_for(self.member), None, self.workspace, ) ) def test_is_workspace_member_allows_active_guest_but_not_outsider(self): permission = IsWorkspaceMember() self.assertTrue( permission.has_object_permission( self._request_for(self.guest), None, self.workspace, ) ) self.assertFalse( permission.has_object_permission( self._request_for(self.outsider), None, self.workspace, ) ) def test_can_workspace_manage_members_only_allows_owner_and_admin(self): permission = CanWorkspaceManageMembers() self.assertTrue( permission.has_object_permission( self._request_for(self.owner), None, self.workspace, ) ) self.assertTrue( permission.has_object_permission( self._request_for(self.admin), None, self.admin_membership, ) ) self.assertFalse( permission.has_object_permission( self._request_for(self.member), None, self.workspace, ) ) self.assertFalse( permission.has_object_permission( self._request_for(self.owner), None, object(), ) ) class WorkspaceMembershipCacheTests(APITestCase): @classmethod def setUpTestData(cls): cls.owner = User.objects.create_user(mobile="09127770031", password="secret123") cls.member = User.objects.create_user(mobile="09127770032", password="secret123") cls.workspace = Workspace.objects.create(name="Membership Cache", owner=cls.owner) cls.membership = WorkspaceMembership.objects.create( workspace=cls.workspace, user=cls.member, role=WorkspaceMembership.Role.MEMBER, is_active=True, ) def setUp(self): cache.clear() self.client.force_authenticate(user=self.owner) def test_membership_list_cache_invalidates_after_membership_save(self): params = {"workspace": str(self.workspace.id)} first_response = self.client.get("/api/workspace-memberships/", params) self.assertEqual(first_response.status_code, 200) target = next(item for item in first_response.data["items"] if item["id"] == str(self.membership.id)) self.assertEqual(target["role"], WorkspaceMembership.Role.MEMBER) WorkspaceMembership.objects.filter(id=self.membership.id).update(role=WorkspaceMembership.Role.GUEST) cached_response = self.client.get("/api/workspace-memberships/", params) self.assertEqual(cached_response.status_code, 200) target = next(item for item in cached_response.data["items"] if item["id"] == str(self.membership.id)) self.assertEqual(target["role"], WorkspaceMembership.Role.MEMBER) self.membership.refresh_from_db() self.membership.is_active = False self.membership.save(update_fields=["is_active"]) fresh_response = self.client.get("/api/workspace-memberships/", params) self.assertEqual(fresh_response.status_code, 200) target = next(item for item in fresh_response.data["items"] if item["id"] == str(self.membership.id)) self.assertEqual(target["role"], WorkspaceMembership.Role.GUEST) self.assertFalse(target["is_active"])