Skip to content

Commit

Permalink
Merge branch 'develop' into payment-managerial-console
Browse files Browse the repository at this point in the history
  • Loading branch information
pkujawa authored Apr 3, 2024
2 parents 7a4a613 + 2721fd6 commit d0dbd1f
Show file tree
Hide file tree
Showing 13 changed files with 503 additions and 248 deletions.
3 changes: 2 additions & 1 deletion backend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
Makefile
*.isorted
test_times.txt
screenshot
screenshot
report
2 changes: 1 addition & 1 deletion backend/hct_mis_api/api/endpoints/rdi/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def perform_create(self, serializer: serializers.BaseSerializer) -> None:
obj: RegistrationDataImportDatahub = serializer.save(
business_area_slug=self.selected_business_area.slug, import_done=RegistrationDataImportDatahub.LOADING
)
serializer.validated_data.pop("import_done")
serializer.validated_data.pop("import_done", None)
self.rdi: RegistrationDataImport = RegistrationDataImport.objects.create(
**serializer.validated_data,
status=RegistrationDataImport.LOADING,
Expand Down
2 changes: 1 addition & 1 deletion backend/hct_mis_api/api/endpoints/rdi/push_people.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def _create_individual(
individual_fields = [field.name for field in ImportedIndividual._meta.get_fields()]
individual_data = {field: value for field, value in person_data.items() if field in individual_fields}
person_type = person_data.get("type")
individual_data.pop("relationship")
individual_data.pop("relationship", None)
relationship = NON_BENEFICIARY if person_type is NON_BENEFICIARY else HEAD

ind = ImportedIndividual.objects.create(
Expand Down
2 changes: 1 addition & 1 deletion backend/hct_mis_api/api/endpoints/rdi/upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ def create(self, validated_data: Dict) -> Dict:
**validated_data, business_area_slug=self.business_area.slug
)
info = self.save_households(rdi_datahub, program.id, households)
validated_data.pop("import_done")
validated_data.pop("import_done", None)
rdi_mis = RegistrationDataImport.objects.create(
**validated_data,
imported_by=created_by,
Expand Down
2 changes: 1 addition & 1 deletion backend/hct_mis_api/api/endpoints/rdi/upload_people.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def create(self, validated_data: Dict) -> Dict:
rdi_datahub = RegistrationDataImportDatahub.objects.create(
**validated_data, business_area_slug=self.business_area.slug
)
validated_data.pop("import_done")
validated_data.pop("import_done", None)
rdi_mis = RegistrationDataImport.objects.create(
**validated_data,
imported_by=created_by,
Expand Down
85 changes: 23 additions & 62 deletions backend/hct_mis_api/apps/account/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
from django.db.models import JSONField, Q, QuerySet
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

from model_utils.models import UUIDModel
from mptt.fields import TreeForeignKey
from mptt.models import MPTTModel
from natural_keys import NaturalKeyModel

from hct_mis_api.apps.account.fields import ChoiceArrayField
Expand All @@ -36,8 +37,6 @@
DoubleSpaceValidator,
StartEndSpaceValidator,
)
from mptt.fields import TreeForeignKey
from mptt.models import MPTTModel

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -317,39 +316,39 @@ def permissions_in_business_area(self, business_area_slug: str, program_id: Opti
return list of permissions based on User Role BA and User Partner
if program_id is in arguments need to check if user.partner.permissions json has program_id
"""
has_program_access = True
# Partner is_unicef has access to all Programs and check perms based on user perms
user_roles_query = UserRole.objects.filter(user=self, business_area__slug=business_area_slug).exclude(
expiry_date__lt=timezone.now()
)
all_user_roles_permissions_list = list(
Role.objects.filter(user_roles__in=user_roles_query).values_list("permissions", flat=True)
)

# Regular user, need to check access to the program
if not self.partner.is_unicef:
# check program access and partner roles permissions list
# Check program access
if program_id:
has_program_access = str(program_id) in self.get_partner_programs_areas_dict(
business_area_slug=business_area_slug
)
if not has_program_access:
return []

# Prepare partner permissions
partner_role_ids_per_ba = self.get_partner_role_ids_list(business_area_slug=business_area_slug)

all_partner_roles_permissions_list = list(
Role.objects.filter(id__in=partner_role_ids_per_ba).values_list("permissions", flat=True)
)
else:
# default perms for is_unicef partner
elif all_user_roles_permissions_list:
# Default partner permissions for UNICEF partner with access to business area
all_partner_roles_permissions_list = [DEFAULT_PERMISSIONS_LIST_FOR_IS_UNICEF_PARTNER]
else:
all_partner_roles_permissions_list = []

user_roles_query = UserRole.objects.filter(user=self, business_area__slug=business_area_slug).exclude(
expiry_date__lt=timezone.now()
)
all_user_roles_permissions_list = list(
Role.objects.filter(user_roles__in=user_roles_query).values_list("permissions", flat=True)
)
return (
list(
set(
[perm for perms in all_partner_roles_permissions_list for perm in perms]
+ [perm for perms in all_user_roles_permissions_list if perms for perm in perms]
)
return list(
set(
[perm for perms in all_partner_roles_permissions_list for perm in perms]
+ [perm for perms in all_user_roles_permissions_list if perms for perm in perms]
)
if has_program_access
else list()
)

@property
Expand All @@ -359,48 +358,10 @@ def business_areas(self) -> QuerySet[BusinessArea]:
| Q(id__in=self.partner.business_area_ids)
).distinct()

@test_conditional(lru_cache())
def cached_has_partner_roles_for_business_area_and_permission(
self, business_area: BusinessArea, permission: str
) -> bool:
return Role.objects.filter(
id__in=self.get_partner_role_ids_list(business_area_id=business_area.pk), permissions__contains=[permission]
).exists()

@test_conditional(lru_cache())
def cached_has_user_roles_for_business_area_and_permission(
self, business_area: BusinessArea, permission: str
) -> bool:
user_roles_query = UserRole.objects.filter(user=self, business_area=business_area).exclude(
expiry_date__lt=timezone.now()
)
return Role.objects.filter(
user_roles__in=user_roles_query,
permissions__contains=[permission],
).exists()

def has_permission(
self, permission: str, business_area: BusinessArea, program_id: Optional[UUID] = None, write: bool = False
) -> bool:
has_user_roles = self.cached_has_user_roles_for_business_area_and_permission(
business_area=business_area,
permission=permission,
)

if self.partner.is_unicef:
return has_user_roles

has_partner_roles = self.cached_has_partner_roles_for_business_area_and_permission(
business_area=business_area,
permission=permission,
)
has_role_access = has_user_roles or has_partner_roles

if not program_id:
return has_role_access

has_program_access = str(program_id) in self.get_partner_programs_areas_dict(business_area_id=business_area.pk)
return has_program_access and has_role_access
return permission in self.permissions_in_business_area(business_area.slug, program_id)

def get_partner_areas_ids_per_program(self, program_id: UUID, business_area_id: UUID) -> List:
partner_areas_ids_per_program = self.get_partner_programs_areas_dict(business_area_id=business_area_id).get(
Expand Down
62 changes: 34 additions & 28 deletions backend/hct_mis_api/apps/account/tests/test_user_roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
)
from hct_mis_api.apps.account.fixtures import PartnerFactory, UserFactory
from hct_mis_api.apps.account.models import IncompatibleRoles, Role, User, UserRole
from hct_mis_api.apps.account.permissions import Permissions
from hct_mis_api.apps.account.permissions import (
DEFAULT_PERMISSIONS_IS_UNICEF_PARTNER,
Permissions,
)
from hct_mis_api.apps.core.fixtures import create_afghanistan, create_ukraine
from hct_mis_api.apps.core.models import BusinessArea

Expand Down Expand Up @@ -102,28 +105,17 @@ def test_user_role_exclude_by_expiry_date(self) -> None:
user=user_not_unicef_partner,
)

self.assertEqual(
self.assertIn(
Permissions.RDI_VIEW_LIST.value,
user_not_unicef_partner.permissions_in_business_area(self.business_area_afg.slug),
[Permissions.RDI_VIEW_LIST.value],
)
self.assertEqual(
user_not_unicef_partner.permissions_in_business_area(self.business_area_ukr.slug),
[Permissions.REPORTING_EXPORT.value],
)
self.assertTrue(
user_not_unicef_partner.cached_has_user_roles_for_business_area_and_permission(
self.business_area_afg, Permissions.RDI_VIEW_LIST.value
)
)
self.assertFalse(
user_not_unicef_partner.cached_has_user_roles_for_business_area_and_permission(
self.business_area_afg, Permissions.REPORTING_EXPORT.value
)
self.assertNotIn(
Permissions.REPORTING_EXPORT.value,
user_not_unicef_partner.permissions_in_business_area(self.business_area_afg.slug),
)
self.assertTrue(
user_not_unicef_partner.cached_has_user_roles_for_business_area_and_permission(
self.business_area_ukr, Permissions.REPORTING_EXPORT.value
)
self.assertIn(
Permissions.REPORTING_EXPORT.value,
user_not_unicef_partner.permissions_in_business_area(self.business_area_ukr.slug),
)

user_role_1.expiry_date = "2024-02-02"
Expand All @@ -136,13 +128,27 @@ def test_user_role_exclude_by_expiry_date(self) -> None:
user_not_unicef_partner.permissions_in_business_area(self.business_area_afg.slug),
[],
)
self.assertFalse(
user_not_unicef_partner.cached_has_user_roles_for_business_area_and_permission(
self.business_area_afg, Permissions.RDI_VIEW_LIST.value
)
self.assertNotIn(
Permissions.RDI_VIEW_LIST.value,
user_not_unicef_partner.permissions_in_business_area(self.business_area_afg.slug),
)
self.assertNotIn(
Permissions.REPORTING_EXPORT.value,
user_not_unicef_partner.permissions_in_business_area(self.business_area_afg.slug),
)
self.assertFalse(
user_not_unicef_partner.cached_has_user_roles_for_business_area_and_permission(
self.business_area_afg, Permissions.REPORTING_EXPORT.value
)

def test_unicef_partner_has_permission_from_user_and_default_permission(self) -> None:
partner = PartnerFactory(name="UNICEF")
user = UserFactory(partner=partner)
role = Role.objects.create(name="111", permissions=[Permissions.GRIEVANCES_CREATE.value])
UserRole.objects.create(role=role, business_area=self.business_area_afg, user=user)

self.assertIn(
Permissions.GRIEVANCES_CREATE.value, user.permissions_in_business_area(self.business_area_afg.slug)
)
for permission in DEFAULT_PERMISSIONS_IS_UNICEF_PARTNER:
self.assertIn(permission.value, user.permissions_in_business_area(self.business_area_afg.slug))

self.assertNotIn(
Permissions.GRIEVANCES_UPDATE.value, user.permissions_in_business_area(self.business_area_afg.slug)
)
Loading

0 comments on commit d0dbd1f

Please sign in to comment.