Moved role to organisation viewset and added extra tests
This commit is contained in:
parent
4d6c86b355
commit
2790677407
2 changed files with 139 additions and 3 deletions
|
|
@ -4,7 +4,7 @@ from django.utils import timezone
|
|||
from rest_framework.test import APIRequestFactory, force_authenticate
|
||||
from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_204_NO_CONTENT, HTTP_400_BAD_REQUEST, HTTP_403_FORBIDDEN, HTTP_404_NOT_FOUND
|
||||
from apps.orgs.viewsets import OrganizationViewSet, InviteViewSet, RoleViewSet
|
||||
from apps.orgs.models import Organization, OrganizationMembership, OrganizationInvitation
|
||||
from apps.orgs.models import Organization, OrganizationMembership, OrganizationInvitation, Role
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
|
@ -98,6 +98,50 @@ class OrganizationAPITests(TestCase):
|
|||
resp = view(req, uuid=str(org.uuid))
|
||||
self.assertEqual(resp.status_code, HTTP_403_FORBIDDEN)
|
||||
|
||||
def test_role_create_forbidden_for_non_manager(self):
|
||||
org = Organization.objects.create(name='RoleNoCreateOrg', owner=self.user)
|
||||
OrganizationMembership.objects.create(organization=org, user=self.user, is_manager=False)
|
||||
view = OrganizationViewSet.as_view({'post': 'role'})
|
||||
req = self.factory.post('/', {'name': 'ForbiddenRole'}, format='json')
|
||||
force_authenticate(req, user=self.user)
|
||||
resp = view(req, uuid=str(org.uuid))
|
||||
self.assertEqual(resp.status_code, HTTP_403_FORBIDDEN)
|
||||
|
||||
def test_role_members_post_missing_user_id_returns_400(self):
|
||||
org = Organization.objects.create(name='RoleMissingParamOrg', owner=self.user)
|
||||
OrganizationMembership.objects.create(organization=org, user=self.user, is_manager=True)
|
||||
role = org.roles.create(name='Ops')
|
||||
role_members_view = OrganizationViewSet.as_view({'post': 'role_members'})
|
||||
req = self.factory.post('/', {}, format='json')
|
||||
force_authenticate(req, user=self.user)
|
||||
resp = role_members_view(req, uuid=str(org.uuid), role_id=str(role.id))
|
||||
self.assertEqual(resp.status_code, HTTP_400_BAD_REQUEST)
|
||||
|
||||
def test_role_members_post_non_manager_cannot_add_other_user(self):
|
||||
org = Organization.objects.create(name='RoleAddForbiddenOrg', owner=self.user)
|
||||
OrganizationMembership.objects.create(organization=org, user=self.user, is_manager=False)
|
||||
target = User.objects.create_user(email_address='target@example.com', password='pass')
|
||||
OrganizationMembership.objects.create(organization=org, user=target, is_manager=False)
|
||||
role = org.roles.create(name='Contributor')
|
||||
|
||||
role_members_view = OrganizationViewSet.as_view({'post': 'role_members'})
|
||||
req = self.factory.post('/', {'user_id': target.id}, format='json')
|
||||
force_authenticate(req, user=self.user)
|
||||
resp = role_members_view(req, uuid=str(org.uuid), role_id=str(role.id))
|
||||
self.assertEqual(resp.status_code, HTTP_403_FORBIDDEN)
|
||||
|
||||
def test_role_members_get_outsider_returns_404(self):
|
||||
org = Organization.objects.create(name='RoleOutsiderOrg', owner=self.user)
|
||||
OrganizationMembership.objects.create(organization=org, user=self.user, is_manager=True)
|
||||
role = org.roles.create(name='Viewer')
|
||||
outsider = User.objects.create_user(email_address='outsider2@example.com', password='pass')
|
||||
|
||||
role_members_view = OrganizationViewSet.as_view({'get': 'role_members', 'post': 'role_members'})
|
||||
req = self.factory.get('/')
|
||||
force_authenticate(req, user=outsider)
|
||||
resp = role_members_view(req, uuid=str(org.uuid), role_id=str(role.id))
|
||||
self.assertEqual(resp.status_code, HTTP_404_NOT_FOUND)
|
||||
|
||||
def test_non_member_cannot_view_org(self):
|
||||
other = User.objects.create_user(email_address='outside@example.com', password='pass')
|
||||
org = Organization.objects.create(name='HiddenOrg', owner=self.user)
|
||||
|
|
@ -226,3 +270,46 @@ class OrganizationAPITests(TestCase):
|
|||
force_authenticate(req, user=self.user)
|
||||
resp = revoke_view(req, uuid=str(org.uuid), token=str(token.token))
|
||||
self.assertEqual(resp.status_code, HTTP_403_FORBIDDEN)
|
||||
|
||||
def test_role_create_and_visibility(self):
|
||||
org = Organization.objects.create(name='RoleCreateOrg', owner=self.user)
|
||||
OrganizationMembership.objects.create(organization=org, user=self.user, is_manager=True)
|
||||
|
||||
org_role_view = OrganizationViewSet.as_view({'post': 'role'})
|
||||
req = self.factory.post('/', {'name': 'Tester'}, format='json')
|
||||
force_authenticate(req, user=self.user)
|
||||
resp = org_role_view(req, uuid=str(org.uuid))
|
||||
self.assertEqual(resp.status_code, HTTP_201_CREATED)
|
||||
|
||||
view = RoleViewSet.as_view({'get': 'list'})
|
||||
req2 = self.factory.get('/')
|
||||
force_authenticate(req2, user=self.user)
|
||||
resp2 = view(req2)
|
||||
self.assertEqual(resp2.status_code, HTTP_200_OK)
|
||||
self.assertTrue(any(r['name'] == 'Tester' for r in resp2.data))
|
||||
|
||||
def test_role_members_get_and_post(self):
|
||||
org = Organization.objects.create(name='RoleMembersOrg', owner=self.user)
|
||||
OrganizationMembership.objects.create(organization=org, user=self.user, is_manager=True)
|
||||
member = User.objects.create_user(email_address='memberrole@example.com', password='pass')
|
||||
OrganizationMembership.objects.create(organization=org, user=member, is_manager=False)
|
||||
role = org.roles.create(name='Developer')
|
||||
|
||||
role_members_view = OrganizationViewSet.as_view({'get': 'role_members', 'post': 'role_members'})
|
||||
req = self.factory.get('/')
|
||||
force_authenticate(req, user=self.user)
|
||||
resp = role_members_view(req, uuid=str(org.uuid), role_id=str(role.id))
|
||||
self.assertEqual(resp.status_code, HTTP_200_OK)
|
||||
|
||||
req2 = self.factory.post('/', {'user_id': member.id}, format='json')
|
||||
force_authenticate(req2, user=self.user)
|
||||
resp2 = role_members_view(req2, uuid=str(org.uuid), role_id=str(role.id))
|
||||
self.assertIn(resp2.status_code, (HTTP_200_OK, HTTP_201_CREATED))
|
||||
|
||||
mem = OrganizationMembership.objects.get(organization=org, user=member)
|
||||
self.assertIsNotNone(mem)
|
||||
|
||||
req3 = self.factory.post('/', {'user_id': member.id}, format='json')
|
||||
force_authenticate(req3, user=member)
|
||||
resp3 = role_members_view(req3, uuid=str(org.uuid), role_id=str(role.id))
|
||||
self.assertIn(resp3.status_code, (HTTP_200_OK, HTTP_201_CREATED))
|
||||
|
|
|
|||
|
|
@ -6,8 +6,14 @@ from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_204_NO_CON
|
|||
from django.shortcuts import get_object_or_404
|
||||
from django.utils import timezone
|
||||
from django.db.models import Q
|
||||
from apps.orgs.models import Organization, OrganizationMembership, OrganizationInvitation, Role
|
||||
from apps.orgs.serializers import OrganizationSerializer, OrganizationMembershipSerializer, OrganizationInvitationSerializer, RoleSerializer
|
||||
from apps.orgs.models import Organization, OrganizationMembership, OrganizationInvitation, Role, RoleMembership
|
||||
from apps.orgs.serializers import (
|
||||
OrganizationSerializer,
|
||||
OrganizationMembershipSerializer,
|
||||
OrganizationInvitationSerializer,
|
||||
RoleSerializer,
|
||||
RoleMembershipSerializer,
|
||||
)
|
||||
|
||||
class OrganizationViewSet(ModelViewSet):
|
||||
queryset = Organization.objects.all()
|
||||
|
|
@ -98,6 +104,49 @@ class OrganizationViewSet(ModelViewSet):
|
|||
invite.save()
|
||||
return Response(status=HTTP_204_NO_CONTENT)
|
||||
|
||||
@action(detail=True, methods=['get', 'post'], url_path='role')
|
||||
def role(self, request, uuid=None):
|
||||
org = self.get_object()
|
||||
|
||||
if request.method == 'GET':
|
||||
roles = Role.objects.filter(organization=org)
|
||||
serializer = RoleSerializer(roles, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
membership = OrganizationMembership.objects.filter(organization=org, user=request.user, is_manager=True).first()
|
||||
if not membership:
|
||||
return Response({'error': 'Only managers can create roles'}, status=HTTP_403_FORBIDDEN)
|
||||
|
||||
serializer = RoleSerializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
serializer.save(organization=org)
|
||||
return Response(serializer.data, status=HTTP_201_CREATED)
|
||||
return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
|
||||
|
||||
@action(detail=True, methods=['get', 'post'], url_path='role/(?P<role_id>[^/.]+)/members')
|
||||
def role_members(self, request, uuid=None, role_id=None):
|
||||
org = self.get_object()
|
||||
role = get_object_or_404(Role, id=role_id, organization=org)
|
||||
requester_membership = OrganizationMembership.objects.filter(organization=org, user=request.user).first()
|
||||
if not requester_membership:
|
||||
return Response(status=HTTP_404_NOT_FOUND)
|
||||
|
||||
if request.method == 'GET':
|
||||
memberships = RoleMembership.objects.filter(role=role)
|
||||
serializer = RoleMembershipSerializer(memberships, many=True)
|
||||
return Response(serializer.data)
|
||||
manager_membership = OrganizationMembership.objects.filter(organization=org, user=request.user, is_manager=True).first()
|
||||
user_id = request.data.get('user_id')
|
||||
if not user_id:
|
||||
return Response({'error': 'user_id is required'}, status=HTTP_400_BAD_REQUEST)
|
||||
if request.user.id != int(user_id) and not manager_membership:
|
||||
return Response({'error': 'Only managers can add other users to roles'}, status=HTTP_403_FORBIDDEN)
|
||||
|
||||
role_membership, created = RoleMembership.objects.get_or_create(role=role, user_id=user_id)
|
||||
|
||||
serializer = RoleMembershipSerializer(role_membership)
|
||||
return Response(serializer.data, status=HTTP_201_CREATED if created else HTTP_200_OK)
|
||||
|
||||
class InviteViewSet(ModelViewSet):
|
||||
queryset = OrganizationInvitation.objects.all()
|
||||
serializer_class = OrganizationInvitationSerializer
|
||||
|
|
|
|||
Loading…
Reference in a new issue