From a326bfb0812c3b2dd927d3fe2aac57850c29df6d Mon Sep 17 00:00:00 2001 From: Sushil Tiwari Date: Tue, 17 Dec 2024 17:13:00 +0545 Subject: [PATCH] Add Validators level check in permission (#2345) * Add current validators level while validators * Add changes in validate api * Add Global validator permission command * Permission set for the global validator on validate api * Change queryset value in group permission * Fix permission issue on validator check --- .../make_global_validator_permission.py | 29 +++++++ local_units/permissions.py | 7 +- local_units/test_views.py | 86 +++++++++++++++++++ local_units/views.py | 20 ++++- 4 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 local_units/management/commands/make_global_validator_permission.py diff --git a/local_units/management/commands/make_global_validator_permission.py b/local_units/management/commands/make_global_validator_permission.py new file mode 100644 index 000000000..f39a875ab --- /dev/null +++ b/local_units/management/commands/make_global_validator_permission.py @@ -0,0 +1,29 @@ +import logging + +from django.contrib.auth.models import Group, Permission +from django.contrib.contenttypes.models import ContentType +from django.core.management.base import BaseCommand + +from local_units.models import LocalUnit + +logger = logging.getLogger(__name__) + + +class Command(BaseCommand): + help = "Create standard local unit global validator permission class and group" + + def handle(self, *args, **options): + logger.info("Creating/Updating permissions/groups for local unit global validator") + print("- Creating/Updating permissions/groups for local unit global validator") + codename = "local_unit_global_validator" + content_type = ContentType.objects.get_for_model(LocalUnit) + permission, created = Permission.objects.get_or_create( + codename=codename, + name="Local Unit Global Validator", + content_type=content_type, + ) + + # If it's a new permission, create a group for it + group, created = Group.objects.get_or_create(name="Local Unit Global Validators") + group.permissions.add(permission) + logger.info("Local unit global validator permission and group created") diff --git a/local_units/permissions.py b/local_units/permissions.py index 075694f26..0bff8003a 100644 --- a/local_units/permissions.py +++ b/local_units/permissions.py @@ -3,11 +3,12 @@ class ValidateLocalUnitPermission(permissions.BasePermission): - message = "You need to be super user/ country admin/ region admin to validate local unit" + message = "You need to be super user/ global validator/ region admin/ country admin to validate local unit" def has_object_permission(self, request, view, object): user = request.user - if user.is_superuser: + + if user.is_superuser or user.has_perm("local_units.local_unit_global_validator"): return True country_admin_ids = [ int(codename.replace("country_admin_", "")) @@ -23,7 +24,7 @@ def has_object_permission(self, request, view, object): codename__startswith="region_admin_", ).values_list("codename", flat=True) ] - if object.country_id in country_admin_ids or object.region_id in region_admin_ids: + if object.country_id in country_admin_ids or object.country.region_id in region_admin_ids: return True return False diff --git a/local_units/test_views.py b/local_units/test_views.py index c7dd97a4f..4913f420d 100644 --- a/local_units/test_views.py +++ b/local_units/test_views.py @@ -1,7 +1,9 @@ import datetime import factory +from django.contrib.auth.models import Group, Permission from django.contrib.gis.geos import Point +from django.core import management from factory import fuzzy from api.models import Country, Region @@ -308,6 +310,29 @@ def test_detail(self): class TestLocalUnitCreate(APITestCase): + def setUp(self): + super().setUp() + self.region = Region.objects.create(name=2) + self.country = Country.objects.create(name="Nepal", iso3="NLP", region=self.region) + management.call_command("make_permissions") + management.call_command("make_global_validator_permission") + + # Permissions and different validators + self.global_validator_user = UserFactory.create() + self.local_unit_admin_user = UserFactory.create() + self.regional_validator_user = UserFactory.create() + + # Adding permissions to the users + global_validator_permission = Permission.objects.filter(codename="local_unit_global_validator").first() + + country_group = Group.objects.filter(name="%s Admins" % self.country.name).first() + region_group = Group.objects.filter(name="%s Regional Admins" % self.region.name).first() + + self.local_unit_admin_user.groups.add(country_group) + self.regional_validator_user.groups.add(region_group) + + self.global_validator_user.user_permissions.add(global_validator_permission) + def test_create_local_unit_administrative(self): region = Region.objects.create(name=2) country = Country.objects.create( @@ -624,3 +649,64 @@ def test_latest_changes(self): self.assert_200(response) self.assertEqual(response.data["previous_data_details"]["local_branch_name"], previous_data["local_branch_name"]) self.assertEqual(response.data["previous_data_details"]["english_branch_name"], previous_data["english_branch_name"]) + + def test_validate_local_unit(self): + type = LocalUnitType.objects.create(code=0, name="Code 0") + data = { + "local_branch_name": "Silele Red Cross Clinic, Sigombeni Red Cross Clinic & Mahwalala Red Cross Clinic", + "english_branch_name": None, + "type": type.id, + "country": self.country.id, + "date_of_data": "2024-05-13", + "location_json": { + "lat": 42.066667, + "lng": 19.983333, + }, + } + self.authenticate() + response = self.client.post("/api/v2/local-units/", data=data, format="json") + self.assert_201(response) + + local_unit_id = response.data["id"] + # Testing For the local unit Global validator + self.authenticate(self.global_validator_user) + # validating the local unit by the Global validator + response = self.client.post(f"/api/v2/local-units/{local_unit_id}/validate/") + self.assert_200(response) + local_unit_request = LocalUnitChangeRequest.objects.filter( + local_unit=local_unit_id, status=LocalUnitChangeRequest.Status.APPROVED + ).last() + self.assertEqual(local_unit_request.current_validator, LocalUnitChangeRequest.Validator.GLOBAL) + + # Testing For the local unit admin/Local validator + self.authenticate(self.local_unit_admin_user) + response = self.client.put(f"/api/v2/local-units/{local_unit_id}/", data=data, format="json") + self.assert_200(response) + # validating the local unit by the local unit admin + response = self.client.post(f"/api/v2/local-units/{local_unit_id}/validate/") + local_unit_request = LocalUnitChangeRequest.objects.filter( + local_unit=local_unit_id, status=LocalUnitChangeRequest.Status.APPROVED + ).last() + self.assertEqual(local_unit_request.current_validator, LocalUnitChangeRequest.Validator.LOCAL) + + # Testing For the regional validator + self.authenticate(self.regional_validator_user) + response = self.client.put(f"/api/v2/local-units/{local_unit_id}/", data=data, format="json") + self.assert_200(response) + # validating the local unit by the regional validator + response = self.client.post(f"/api/v2/local-units/{local_unit_id}/validate/") + local_unit_request = LocalUnitChangeRequest.objects.filter( + local_unit=local_unit_id, status=LocalUnitChangeRequest.Status.APPROVED + ).last() + self.assertEqual(local_unit_request.current_validator, LocalUnitChangeRequest.Validator.REGIONAL) + + # Testing for Root User/Global validator + self.authenticate(self.root_user) + response = self.client.put(f"/api/v2/local-units/{local_unit_id}/", data=data, format="json") + self.assert_200(response) + # validating the local unit by the global validator + response = self.client.post(f"/api/v2/local-units/{local_unit_id}/validate/") + local_unit_request = LocalUnitChangeRequest.objects.filter( + local_unit=local_unit_id, status=LocalUnitChangeRequest.Status.APPROVED + ).last() + self.assertEqual(local_unit_request.current_validator, LocalUnitChangeRequest.Validator.GLOBAL) diff --git a/local_units/views.py b/local_units/views.py index 129648b13..7965e9a23 100644 --- a/local_units/views.py +++ b/local_units/views.py @@ -1,3 +1,4 @@ +from django.contrib.auth.models import Permission from django.shortcuts import get_object_or_404 from django.utils import timezone from drf_spectacular.utils import extend_schema @@ -121,10 +122,27 @@ def get_validate(self, request, pk=None, version=None): if not change_request_instance: return bad_request("No change request found to validate") + # Checking the validator type + + validator = LocalUnitChangeRequest.Validator.LOCAL + if request.user.is_superuser or request.user.has_perm("local_units.local_unit_global_validator"): + validator = LocalUnitChangeRequest.Validator.GLOBAL + else: + region_admin_ids = [ + int(codename.replace("region_admin_", "")) + for codename in Permission.objects.filter( + group__user=request.user, + codename__startswith="region_admin_", + ).values_list("codename", flat=True) + ] + if local_unit.country.region_id in region_admin_ids: + validator = LocalUnitChangeRequest.Validator.REGIONAL + + change_request_instance.current_validator = validator change_request_instance.status = LocalUnitChangeRequest.Status.APPROVED change_request_instance.updated_by = request.user change_request_instance.updated_at = timezone.now() - change_request_instance.save(update_fields=["status", "updated_by", "updated_at"]) + change_request_instance.save(update_fields=["status", "updated_by", "updated_at", "current_validator"]) # Validate the local unit local_unit.validated = True