Skip to content

Commit 26daaa2

Browse files
sudip-khanalsusilnem
authored andcommitted
feat(local-unit): add permission for regional admin to edit local unit
1 parent cde9995 commit 26daaa2

File tree

2 files changed

+67
-14
lines changed

2 files changed

+67
-14
lines changed

local_units/permissions.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from django.contrib.auth.models import Permission
12
from rest_framework import permissions
23

34
from api.models import Country
@@ -24,7 +25,7 @@ def has_object_permission(self, request, view, obj):
2425

2526

2627
class IsAuthenticatedForLocalUnit(permissions.BasePermission):
27-
message = "Only Country admin, Local Unit validators and superusers are allowed to update Local Units"
28+
message = "Only Country Admins, Local Unit Validators, Region Admins, or Superusers are allowed to update Local Units."
2829

2930
def has_object_permission(self, request, view, obj):
3031
if request.method not in ["PUT", "PATCH"]:
@@ -36,15 +37,27 @@ def has_object_permission(self, request, view, obj):
3637
return True
3738

3839
country_id = obj.country_id
39-
try:
40-
country = Country.objects.get(id=country_id)
41-
except Country.DoesNotExist:
42-
return False
40+
country = Country.objects.get(id=country_id)
41+
region_id = country.region_id
4342
# Country admin specific permissions
44-
codename = f"country_admin_{country.id}"
45-
if user.groups.filter(permissions__codename=codename).exists():
43+
country_admin_ids = [
44+
int(codename.replace("country_admin_", ""))
45+
for codename in Permission.objects.filter(
46+
group__user=user,
47+
codename__startswith="country_admin_",
48+
).values_list("codename", flat=True)
49+
]
50+
# Regional admin specific permissions
51+
region_admin_ids = [
52+
int(codename.replace("region_admin_", ""))
53+
for codename in Permission.objects.filter(
54+
group__user=user,
55+
codename__startswith="region_admin_",
56+
).values_list("codename", flat=True)
57+
]
58+
if country_id in country_admin_ids or region_id in region_admin_ids:
4659
return True
47-
# Validator permission
60+
4861
return (
4962
get_local_unit_country_validators(obj).filter(id=user.id).exists()
5063
or get_local_unit_region_validators(obj).filter(id=user.id).exists()

local_units/test_views.py

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -882,31 +882,60 @@ def test_create_local_unit_with_externally_managed_country_and_type(self):
882882
self.assertEqual(response.status_code, 400)
883883
self.assertEqual(LocalUnitChangeRequest.objects.count(), 0)
884884

885-
def test_country_admin_permission_for_local_unit_update(self):
885+
def test_country_region_admin_permission_for_local_unit_update(self):
886+
region1 = RegionFactory.create(name=2, label="Asia Pacific")
887+
888+
region2 = RegionFactory.create(name=0, label="Africa")
889+
886890
country = CountryFactory.create(
887891
name="India",
888892
iso3="IND",
889893
record_type=CountryType.COUNTRY,
890894
is_deprecated=False,
891895
independent=True,
896+
region=region1,
892897
)
893-
898+
self.asia_admin = UserFactory.create(email="[email protected]")
899+
self.africa_admin = UserFactory.create(email="[email protected]")
894900
self.india_admin = UserFactory.create(email="[email protected]")
895901
# India admin setup
896902
management.call_command("make_permissions")
897903
country_admin_codename = f"country_admin_{country.id}"
898904
country_admin_permission = Permission.objects.get(codename=country_admin_codename)
899-
country__admin_group_name = "%s Admins" % country.name
900-
country__admin_group = Group.objects.get(name=country__admin_group_name)
901-
country__admin_group.permissions.add(country_admin_permission)
902-
self.india_admin.groups.add(country__admin_group)
905+
country_admin_group_name = "%s Admins" % country.name
906+
country_admin_group = Group.objects.get(name=country_admin_group_name)
907+
country_admin_group.permissions.add(country_admin_permission)
908+
self.india_admin.groups.add(country_admin_group)
909+
# Asia admin
910+
asia_admin_codename = f"region_admin_{region1.id}"
911+
asia_admin_permission = Permission.objects.get(codename=asia_admin_codename)
912+
asia_admin_group_name = "%s Regional Admins" % region1.name
913+
asia_admin_group = Group.objects.get(name=asia_admin_group_name)
914+
asia_admin_group.permissions.add(asia_admin_permission)
915+
self.asia_admin.groups.add(asia_admin_group)
916+
917+
# Africa admin
918+
africa_admin_codename = f"region_admin_{region2.id}"
919+
africa_admin_permission = Permission.objects.get(codename=africa_admin_codename)
920+
africa_admin_group_name = "%s Regional Admins" % region2.name
921+
africa_admin_group = Group.objects.get(name=africa_admin_group_name)
922+
africa_admin_group.permissions.add(africa_admin_permission)
923+
self.africa_admin.groups.add(africa_admin_group)
924+
903925
local_unit = LocalUnitFactory.create(
904926
country=country,
905927
type=self.local_unit_type,
906928
draft=False,
907929
status=LocalUnit.Status.VALIDATED,
908930
date_of_data="2023-08-08",
909931
)
932+
local_unit2 = LocalUnitFactory.create(
933+
country=country,
934+
type=self.local_unit_type,
935+
draft=False,
936+
status=LocalUnit.Status.VALIDATED,
937+
date_of_data="2023-08-08",
938+
)
910939
url = f"/api/v2/local-units/{local_unit.id}/"
911940
data = {
912941
"local_branch_name": "Updated local branch name",
@@ -929,6 +958,17 @@ def test_country_admin_permission_for_local_unit_update(self):
929958
self.assert_200(response)
930959
self.assertEqual(response.data["local_branch_name"], "Updated local branch name")
931960

961+
url = f"/api/v2/local-units/{local_unit2.id}/"
962+
# Test: different region admin
963+
self.authenticate(self.africa_admin)
964+
response = self.client.patch(url, data=data, format="json")
965+
self.assert_403(response)
966+
# Test: same region admin
967+
self.authenticate(self.asia_admin)
968+
response = self.client.patch(url, data=data, format="json")
969+
self.assert_200(response)
970+
self.assertEqual(response.data["local_branch_name"], "Updated local branch name")
971+
932972

933973
class TestExternallyManagedLocalUnit(APITestCase):
934974
def setUp(self):

0 commit comments

Comments
 (0)