Skip to content

Commit 34218f4

Browse files
sudip-khanalsusilnem
authored andcommitted
fix(dref): update dref approve permission
1 parent 4b06103 commit 34218f4

3 files changed

Lines changed: 94 additions & 76 deletions

File tree

dref/permissions.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from django.contrib.auth.models import Permission
22
from rest_framework import permissions
33

4-
from dref.models import Dref, DrefFinalReport, DrefOperationalUpdate
4+
from dref.models import DrefFinalReport, DrefOperationalUpdate
55
from dref.utils import get_dref_users
66

77

@@ -35,13 +35,24 @@ def has_object_permission(self, request, view, obj):
3535
return False
3636

3737

38-
class PublishDrefPermission(permissions.BasePermission):
39-
message = "You need to be regional admin to publish dref"
38+
class ApproveDrefPermission(permissions.BasePermission):
39+
message = "You need to be Superuser or Dref Regional admin to approve"
4040

4141
def has_object_permission(self, request, view, obj):
42-
region = obj.country.region.name
43-
codename = f"dref_region_admin_{region}"
42+
4443
user = request.user
45-
if Permission.objects.filter(user=user, codename=codename).exists() and obj.status != Dref.Status.APPROVED:
44+
region_id = obj.country.region_id
45+
46+
if user.is_superuser:
47+
return True
48+
49+
dref_region_admins_ids = [
50+
int(codename.replace("dref_region_admin_", ""))
51+
for codename in Permission.objects.filter(
52+
group__user=user,
53+
codename__startswith="dref_region_admin_",
54+
).values_list("codename", flat=True)
55+
]
56+
if region_id in dref_region_admins_ids:
4657
return True
4758
return False

dref/test_views.py

Lines changed: 63 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -642,66 +642,71 @@ def test_dref_is_approved(self, mock_now):
642642
- Can only approve when status=FINALIZED
643643
- Approve sets status=APPROVED
644644
"""
645+
management.call_command("make_dref_regional_permission")
646+
645647
initial_now = datetime.now()
646648
mock_now.return_value = initial_now
647649

650+
# Users
651+
root_user = self.root_user
652+
user1 = UserFactory.create(email="dref@test.com")
653+
654+
# Region and country
648655
region = Region.objects.create(name=RegionName.AFRICA)
649656
country = Country.objects.create(name="country1", region=region)
657+
658+
# Create DREF with DRAFT status
650659
dref = DrefFactory.create(
651660
title="test",
652-
created_by=self.user,
661+
created_by=root_user,
653662
country=country,
654663
status=Dref.Status.DRAFT,
655664
type_of_dref=Dref.DrefType.IMMINENT,
656665
)
657-
# Normal PATCH
666+
667+
self.client.force_authenticate(root_user)
668+
# ---- PATCH updates ----
658669
url = f"/api/v2/dref/{dref.id}/"
659-
data = {
660-
"title": "New Update Title",
661-
"modified_at": initial_now + timedelta(days=1),
662-
}
663-
self.client.force_authenticate(self.user)
670+
data = {"title": "Updated Title", "modified_at": initial_now + timedelta(days=1)}
664671
response = self.client.patch(url, data)
665672
self.assert_200(response)
666-
# create new dref with status = DRAFT
667-
not_approved_dref = DrefFactory.create(
668-
title="test",
669-
created_by=self.user,
670-
country=country,
671-
status=Dref.Status.DRAFT,
672-
)
673-
url = f"/api/v2/dref/{not_approved_dref.id}/"
674-
self.client.force_authenticate(self.user)
675-
data["modified_at"] = initial_now + timedelta(days=10)
676-
response = self.client.patch(url, data)
677-
self.assert_200(response)
678-
679-
data["modified_at"] = initial_now - timedelta(seconds=10)
680-
response = self.client.patch(url, data)
681-
self.assert_400(response)
682-
# ---- Test publishing ----
683-
publish_url = f"/api/v2/dref/{dref.id}/approve/"
684-
data = {}
685-
response = self.client.post(publish_url, data)
686-
self.assert_403(response)
687-
# Add permission to user
688-
self.dref_permission = Permission.objects.create(
689-
codename="dref_region_admin_0",
673+
# ---- Add DREF regional admin permission to user1 ----
674+
region_permission = Permission.objects.create(
675+
codename=f"dref_region_admin_{region.id}",
690676
content_type=ContentType.objects.get_for_model(Region),
691-
name="Dref Admin for 0",
677+
name=f"Dref Admin for region {region.id}",
692678
)
693-
self.user.user_permissions.add(self.dref_permission)
694-
# Try again while DRAFT. Should fail(not finalized yet)
695-
response = self.client.post(publish_url, data)
696-
self.assert_400(response)
697-
# Update status to FINALIZED, then publish should succeed
679+
user1.user_permissions.add(region_permission)
680+
681+
# ---- Approve while DRAFT as superuser ----
682+
approve_url = f"/api/v2/dref/{dref.id}/approve/"
683+
self.authenticate(root_user)
684+
response = self.client.post(approve_url, {})
685+
self.assert_400(response) # Not finalized yet
686+
687+
# ---- Update DREF to FINALIZED ----
698688
dref.status = Dref.Status.FINALIZED
699689
dref.save(update_fields=["status"])
700690
dref.refresh_from_db()
701-
response = self.client.post(publish_url, data)
691+
692+
# ---- Approve as superuser ----
693+
self.authenticate(root_user)
694+
response = self.client.post(approve_url, {})
695+
self.assert_200(response)
702696
dref.refresh_from_db()
697+
self.assertEqual(dref.status, Dref.Status.APPROVED)
698+
699+
# ---- Reset to FINALIZED for regional admin test ----
700+
dref.status = Dref.Status.FINALIZED
701+
dref.save(update_fields=["status"])
702+
dref.refresh_from_db()
703+
704+
# ---- Approve as regional admin ----
705+
self.authenticate(user1)
706+
response = self.client.post(approve_url, {})
703707
self.assert_200(response)
704-
self.assertEqual(response.data["status"], Dref.Status.APPROVED)
708+
dref.refresh_from_db()
709+
self.assertEqual(dref.status, Dref.Status.APPROVED)
705710

706711
def test_dref_operation_update_create(self):
707712
"""
@@ -934,6 +939,8 @@ def test_final_report_update_once_published(self):
934939
user1 = UserFactory.create()
935940
region = Region.objects.create(name=RegionName.AFRICA)
936941
country = Country.objects.create(name="country1", region=region)
942+
management.call_command("make_dref_regional_permission")
943+
# Create DREF and final report
937944
dref = DrefFactory.create(
938945
title="Test Title",
939946
type_of_dref=Dref.DrefType.ASSESSMENT,
@@ -949,29 +956,25 @@ def test_final_report_update_once_published(self):
949956
status=Dref.Status.FINALIZED,
950957
)
951958
final_report.users.set([user1])
952-
url = f"/api/v2/dref-final-report/{final_report.id}/approve/"
953-
data = {}
954-
self.client.force_authenticate(user1)
955-
response = self.client.post(url, data)
956-
self.assert_403(response)
957-
# add permission to request user
958-
self.dref_permission = Permission.objects.create(
959-
codename="dref_region_admin_0",
960-
content_type=ContentType.objects.get_for_model(Region),
961-
name="Dref Admin for 0",
962-
)
963-
user1.user_permissions.add(self.dref_permission)
959+
960+
patch_url = f"/api/v2/dref-final-report/{final_report.id}/"
961+
962+
# ---- Normal PATCH update before approval ----
964963
self.client.force_authenticate(user1)
965-
response = self.client.post(url, data)
966-
self.assert_200(response)
967-
self.assertEqual(response.data["status"], Dref.Status.APPROVED)
968-
# now try to patch to the final report
969-
url = f"/api/v2/dref-final-report/{final_report.id}/"
970964
data = {
971-
"title": "New Field Report Title",
965+
"title": "Updated Title Before Approval",
966+
"modified_at": datetime.now(),
972967
}
973-
response = self.client.patch(url, data)
974-
self.assert_400(response)
968+
response = self.client.patch(patch_url, data)
969+
self.assert_200(response)
970+
final_report.refresh_from_db()
971+
972+
self.client.force_authenticate(self.root_user)
973+
approve_url = f"/api/v2/dref-final-report/{final_report.id}/approve/"
974+
response = self.client.post(approve_url, {})
975+
self.assert_200(response)
976+
final_report.refresh_from_db()
977+
self.assertEqual(final_report.status, Dref.Status.APPROVED)
975978

976979
def test_dref_for_assessment_report(self):
977980
old_count = Dref.objects.count()
@@ -1960,7 +1963,7 @@ def test_dref_imminent(self):
19601963
sct_2 = SectorFactory(
19611964
title="health",
19621965
)
1963-
national_society = Country.objects.create(name="abc")
1966+
national_society = Country.objects.create(name="abc123")
19641967
disaster_type = DisasterType.objects.create(name="disaster 1")
19651968
data = {
19661969
"title": "Dref test title",

dref/views.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
DrefShareUserFilterSet,
3131
)
3232
from dref.models import Dref, DrefFile, DrefFinalReport, DrefOperationalUpdate
33-
from dref.permissions import PublishDrefPermission
33+
from dref.permissions import ApproveDrefPermission
3434
from dref.serializers import (
3535
AddDrefUserSerializer,
3636
CompletedDrefOperationsSerializer,
@@ -90,14 +90,14 @@ def get_queryset(self):
9090
detail=True,
9191
url_path="approve",
9292
methods=["post"],
93-
permission_classes=[permissions.IsAuthenticated, PublishDrefPermission, DenyGuestUserPermission],
93+
permission_classes=[permissions.IsAuthenticated, ApproveDrefPermission, DenyGuestUserPermission],
9494
)
9595
def get_approved(self, request, pk=None, version=None):
9696
dref = self.get_object()
97+
if dref.status == Dref.Status.APPROVED:
98+
raise serializers.ValidationError(gettext("This Dref has already been approved."))
9799
if dref.status != Dref.Status.FINALIZED:
98100
raise serializers.ValidationError(gettext("Must be finalized before it can be approved"))
99-
if dref.status == Dref.Status.APPROVED:
100-
raise serializers.ValidationError(gettext("Dref %s is already approved" % dref))
101101
dref.status = Dref.Status.APPROVED
102102
dref.save(update_fields=["status"])
103103
serializer = DrefSerializer(dref, context={"request": request})
@@ -184,14 +184,16 @@ def get_queryset(self):
184184
detail=True,
185185
url_path="approve",
186186
methods=["post"],
187-
permission_classes=[permissions.IsAuthenticated, PublishDrefPermission, DenyGuestUserPermission],
187+
permission_classes=[permissions.IsAuthenticated, ApproveDrefPermission, DenyGuestUserPermission],
188188
)
189189
def get_approved(self, request, pk=None, version=None):
190190
operational_update = self.get_object()
191+
192+
if operational_update.status == Dref.Status.APPROVED:
193+
raise serializers.ValidationError(gettext("This Operational update has already been approved."))
191194
if operational_update.status != Dref.Status.FINALIZED:
192195
raise serializers.ValidationError(gettext("Must be finalized before it can be approved."))
193-
if operational_update.status == Dref.Status.APPROVED:
194-
raise serializers.ValidationError(gettext("Operational update %s is already approved" % operational_update))
196+
195197
operational_update.status = Dref.Status.APPROVED
196198
operational_update.save(update_fields=["status"])
197199
serializer = DrefOperationalUpdateSerializer(operational_update, context={"request": request})
@@ -247,14 +249,16 @@ def get_queryset(self):
247249
detail=True,
248250
url_path="approve",
249251
methods=["post"],
250-
permission_classes=[permissions.IsAuthenticated, PublishDrefPermission, DenyGuestUserPermission],
252+
permission_classes=[permissions.IsAuthenticated, ApproveDrefPermission, DenyGuestUserPermission],
251253
)
252254
def get_approved(self, request, pk=None, version=None):
253255
final_report = self.get_object()
256+
if final_report.status == Dref.Status.APPROVED:
257+
raise serializers.ValidationError(gettext("This Final Report has already been approved."))
258+
254259
if final_report.status != Dref.Status.FINALIZED:
255260
raise serializers.ValidationError(gettext("Must be finalized before it can be approved."))
256-
if final_report.status == Dref.Status.APPROVED:
257-
raise serializers.ValidationError(gettext("Final Report %s is already approved" % final_report))
261+
258262
final_report.status = Dref.Status.APPROVED
259263
final_report.save(update_fields=["status"])
260264
final_report.dref.is_active = False

0 commit comments

Comments
 (0)