Skip to content

Commit

Permalink
Update admission queryset to be admission-specific
Browse files Browse the repository at this point in the history
  • Loading branch information
norbye committed Sep 6, 2023
1 parent 70957c3 commit 824a145
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 106 deletions.
4 changes: 1 addition & 3 deletions admissions/admissions/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@
COURSES_LONG = ((DATA_LONG, DATA_LONG), (KOMTEK_LONG, KOMTEK_LONG))

# Groups that give privileges to their leaders
SUPERUSER_LEADER_GROUPS = ["Hovedstyret", "RevyStyret"]
""" Members of this group with role leader should attain the is_superuser attribute """
STAFF_LEADER_GROUPS = ["backup", "Hovedstyret", "RevyStyret"]
""" Members of this group with role leader should attain the is_staff attribute """
""" Members of this group with role leader should attain the is_staff attribute and be able to manage admissions """
WEBKOM_GROUPNAME = "Webkom"
""" Group name of Webkom """
18 changes: 0 additions & 18 deletions admissions/admissions/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,6 @@
class LegoUser(AbstractUser):
profile_picture = models.URLField(null=True, blank=True)

@property
def is_privileged(self):
"""
Return true if the user is Abakus Leader or has admission privileges
"""
return bool(self.is_superuser or self.admission_privileges)

@property
def admission_privileges(self):
"""
Return true if the user has the role of LEADER or RECRUTING
"""
return (
Membership.objects.filter(user=self)
.filter(Q(role=constants.LEADER) | Q(role=constants.RECRUITING))
.exists()
)

@property
def representative_of_group(self):
"""
Expand Down
54 changes: 28 additions & 26 deletions admissions/admissions/permissions.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
from rest_framework import permissions

from .models import GroupApplication, LegoUser, UserApplication
from django.db.models import Q

from admissions.admissions import constants
from .models import Admission, GroupApplication, LegoUser, Membership, UserApplication


def cast_as_lego_user(user_obj) -> LegoUser:
user_obj.__class__ = LegoUser
return user_obj


def user_is_privileged(admission_slug, user):
# Return true if the user has some sort of privileges in the admission
admission = Admission.objects.get(slug=admission_slug)
for group in admission.admin_groups.all():
if Membership.objects.filter(user=user.pk, group=group.pk).exists():
return True
for group in admission.groups.all():
if (
Membership.objects.filter(user=user.pk, group=group.pk)
.filter(Q(role=constants.LEADER) | Q(role=constants.RECRUITING))
.exists()
):
return True
return False


class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow owners of an object to edit it.
Expand All @@ -19,14 +38,6 @@ def has_object_permission(self, request, view, obj):
return obj.user == request.user


class IsSuperuser(permissions.BasePermission):
def has_permission(self, request):
return cast_as_lego_user(request.user).is_superuser

def has_object_permission(self, request):
return cast_as_lego_user(request.user).is_superuser


class IsStaff(permissions.BasePermission):
def has_permission(self, request, *_):
return cast_as_lego_user(request.user).is_staff
Expand All @@ -53,40 +64,32 @@ def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True

user = request.user
user.__class__ = LegoUser

# Here obj will be the name of the group
if obj == user.representative_of_group or user.is_superuser:
return True

return False
# Allow a user to edit a group if it is a leader or recruiter in that group
return Membership.objects.filter(user=request.user.pk, group=obj.pk).filter(Q(role=constants.LEADER) | Q(role=constants.RECRUITING)).exists()


class AdmissionPermissions(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True

# If the user is AbakusLeader -> give access
return request.user.is_superuser
# If the user is staff (can edit admissions)
return request.user.is_staff

def has_permission(self, request, view):
if request.method in permissions.SAFE_METHODS:
return True

# If the user is AbakusLeader -> give access
return request.user.is_superuser
# If the user is staff (can edit admissions)
return request.user.is_staff


class ApplicationPermissions(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return False

def has_permission(self, request, view):
user = request.user
user.__class__ = LegoUser
return user.is_privileged
return user_is_privileged(view.kwargs.get("admission_slug"), request.user)


class GroupApplicationPermissions(permissions.BasePermission):
Expand All @@ -98,5 +101,4 @@ def has_object_permission(self, request, view, obj):
return GroupApplication.objects.filter(application=obj).count() == 0

def has_permission(self, request, view):
request.user.__class__ = LegoUser
return request.user.is_privileged
return user_is_privileged(view.kwargs.get("admission_slug"), request.user)
64 changes: 39 additions & 25 deletions admissions/admissions/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,18 +111,18 @@ def test_group_recruiter_can_edit_group(self):

self.assertEqual(res.status_code, status.HTTP_200_OK)

def test_abakus_leader_cannot_edit_group(self):
abakus_leader = LegoUser.objects.create(
username="bigsupremeleader", is_superuser=True
def test_staff_user_cannot_edit_group(self):
staff_user = LegoUser.objects.create(
username="bigsupremeleader", is_staff=True
)
self.client.force_authenticate(user=abakus_leader)
self.client.force_authenticate(user=staff_user)

res = self.client.patch(
reverse("group-detail", kwargs={"pk": self.arrkom.pk}),
self.edit_group_data,
)

self.assertEqual(res.status_code, status.HTTP_200_OK)
self.assertEqual(res.status_code, status.HTTP_403_FORBIDDEN)

# What about when not logged in aka. have a user? Rewrite api (remove LoginRequiredMixins
# from views to stop from redirecting, and handle redirecting ourselves with permissions.
Expand Down Expand Up @@ -186,12 +186,12 @@ def test_unauthorized_user_cannot_edit_admission(self):

self.assertEqual(res.status_code, status.HTTP_401_UNAUTHORIZED)

def test_abakus_leader_can_edit_admission(self):
abakus_leader = LegoUser.objects.create(
username="bigsupremeleader", is_superuser=True
def test_staff_user_can_edit_admission(self):
staff_user = LegoUser.objects.create(
username="bigsupremeleader", is_staff=True
)

self.client.force_authenticate(user=abakus_leader)
self.client.force_authenticate(user=staff_user)

res = self.client.patch(
reverse("admission-detail", kwargs={"slug": self.admission.slug}),
Expand Down Expand Up @@ -304,12 +304,26 @@ def setUp(self):
self.admission_slug = admission_slug

self.pleb = LegoUser.objects.create()
leader_group = Group.objects.create(name="Abakus-Leder")

self.admission = create_admission()
self.admission.admin_groups.add(leader_group)

# Abakus leader
self.staff_user = LegoUser.objects.create(
username="staff_user", is_staff=True
)

Membership.objects.create(
user=self.staff_user, role=MEMBER, group=leader_group
)

# Webkom
self.webkom_leader = LegoUser.objects.create(username="webkomleader")
self.webkom_rec = LegoUser.objects.create(username="webkomrec")

self.webkom = Group.objects.create(name="Webkom")
self.admission.groups.add(self.webkom)

Membership.objects.create(
user=self.webkom_leader, role=LEADER, group=self.webkom
Expand All @@ -318,17 +332,21 @@ def setUp(self):
user=self.webkom_rec, role=RECRUITING, group=self.webkom
)

# Bedkom
self.bedkom_leader = LegoUser.objects.create(username="bedkomleader")
self.bedkom_rec = LegoUser.objects.create(username="bedkomrec")

self.bedkom = Group.objects.create(name="Bedkom")
self.admission.groups.add(self.bedkom)

Membership.objects.create(
user=self.bedkom_leader, role=LEADER, group=self.bedkom
)
Membership.objects.create(
user=self.bedkom_rec, role=RECRUITING, group=self.bedkom
)

# Sample application data
self.application_data = {
"text": "testtest",
"applications": {
Expand All @@ -339,12 +357,9 @@ def setUp(self):
}

def unauthorized_user_cannot_see_other_applications(self):
"""Normal users should not be able to list applications"""
self.client.force_authenticate(user=self.pleb)

res = self.client.get(
reverse(
"userapplication-mine", kwargs={"admission_slug": self.admission_slug}
"userapplication-list", kwargs={"admission_slug": self.admission_slug}
)
)

Expand Down Expand Up @@ -511,7 +526,7 @@ def test_group_recruiter_cannot_see_applications_for_other_group(self):
for group_application in json[0]["group_applications"]:
self.assertNotEqual(group_application["group"]["name"], "Webkom")

def test_abakus_leader_can_see_all_applications(self):
def test_staff_user_can_see_all_applications(self):
self.client.force_authenticate(user=self.pleb)
self.client.post(
reverse(
Expand All @@ -522,11 +537,7 @@ def test_abakus_leader_can_see_all_applications(self):
)

# Auth user as AbakusLeader
abakus_leader = LegoUser.objects.create(
username="abakus_leader", is_superuser=True
)

self.client.force_authenticate(user=abakus_leader)
self.client.force_authenticate(user=self.staff_user)
res = self.client.get(
reverse(
"userapplication-list", kwargs={"admission_slug": self.admission_slug}
Expand All @@ -539,12 +550,12 @@ def test_abakus_leader_can_see_all_applications(self):
self.assertEqual(apps[1]["group"]["name"], "Bedkom")


class DeleteComitteeApplicationsTestCase(APITestCase):
class DeleteGroupApplicationsTestCase(APITestCase):
"""
Tests for api endpoint allowing leader of group / opptaksansvarlig and abakus_leader to delete group
Tests for api endpoint allowing leader of group / opptaksansvarlig and staff_user to delete group
applications
representative_of_group can only delete applications to their own group. abakus_leader can
representative_of_group can only delete applications to their own group. staff_user can
delete any group applications.
Users can delete their own applications with the /mine endpoint
Expand All @@ -553,17 +564,20 @@ class DeleteComitteeApplicationsTestCase(APITestCase):
def setUp(self):
global admission_slug
self.admission_slug = admission_slug
self.pleb = LegoUser.objects.create()
self.admission = create_admission()

self.webkom_leader = LegoUser.objects.create(username="webkomleader")
self.pleb = LegoUser.objects.create()

self.webkom = Group.objects.create(name="Webkom")
self.arrkom = Group.objects.create(name="Arrkom")

Membership.objects.create(
user=self.webkom_leader, role=LEADER, group=self.webkom
)
self.abakus_leader = LegoUser.objects.create(
username="bigsupremeleader", is_superuser=True

self.staff_user = LegoUser.objects.create(
username="bigsupremeleader", is_staff=True
)

def unauthorized_user_cannot_delete_application(self):
Expand Down

0 comments on commit 824a145

Please sign in to comment.