Skip to content

add perms mixin for healthcare service and facility location#3561

Open
Jacobjeevan wants to merge 1 commit intoohcnetwork:developfrom
Jacobjeevan:service-location-perms
Open

add perms mixin for healthcare service and facility location#3561
Jacobjeevan wants to merge 1 commit intoohcnetwork:developfrom
Jacobjeevan:service-location-perms

Conversation

@Jacobjeevan
Copy link
Contributor

@Jacobjeevan Jacobjeevan commented Mar 6, 2026

Proposed Changes

  • added permissions mixin for healthcare service and facility location

Architecture changes

  • Remove this section if not used

Merge Checklist

  • Tests added/fixed
  • Update docs in /docs
  • Linting Complete
  • Any other necessary step

Only PR's with test cases included and passing lint and test pipelines will be reviewed

@ohcnetwork/care-backend-maintainers @ohcnetwork/care-backend-admins

Summary by CodeRabbit

Release Notes

  • New Features
    • Implemented permission management for healthcare services and facility location resources
    • Users now see their assigned permissions for these resources based on role assignments
    • Enhanced access control to determine user permissions at the resource level

@Jacobjeevan Jacobjeevan requested a review from a team as a code owner March 6, 2026 05:16
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 6, 2026

📝 Walkthrough

Walkthrough

This change introduces permissions mixins for healthcare service and facility location resources, consistently following established architectural patterns. New access methods enable role determination for users within these resource contexts, and spec classes are updated to leverage the new permission-handling mixins.

Changes

Cohort / File(s) Summary
Permissions Mixins
care/emr/resources/permissions.py
Added FacilityLocationPermissionsMixin and HealthcareServicePermissionsMixin classes with add_permissions methods that determine user roles and populate permission mappings from RolePermission queries.
Spec Resource Updates
care/emr/resources/healthcare_service/spec.py, care/emr/resources/location/spec.py
Updated HealthcareServiceRetrieveSpec and FacilityLocationRetrieveSpec to inherit from their respective permissions mixins, enabling permission assignment on retrieval operations.
Access Role Resolution
care/security/authorization/facility_location.py, care/security/authorization/healthcare_service.py
Added find_roles_on_facility_location and find_roles_on_healthcare_service methods to their respective Access classes for querying user role assignments within resource organization hierarchies.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description is incomplete. While it mentions the proposed changes, it lacks detail about what the mixins do, omits the associated issue link, and leaves architecture changes section present but marked for removal. Expand the description with specific details about the permission mixins' functionality, add the associated issue/feature link, and remove the unused architecture changes section.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding permission mixins for healthcare service and facility location resources.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
care/security/authorization/facility_location.py (1)

14-18: Guard facility_organization_cache before using it in __in.

This is fine for happy-path data, but it’ll fail noisily if the cache is ever None. A small guard keeps this method robust.

Suggested patch
 def find_roles_on_facility_location(self, user, facility_location):
-    roles = FacilityOrganizationUser.objects.filter(
-        organization_id__in=facility_location.facility_organization_cache, user=user
+    org_ids = facility_location.facility_organization_cache or []
+    roles = FacilityOrganizationUser.objects.filter(
+        organization_id__in=org_ids, user=user
     ).values_list("role_id", flat=True)
     return set(roles)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@care/security/authorization/facility_location.py` around lines 14 - 18, The
method find_roles_on_facility_location uses
facility_location.facility_organization_cache directly in a filter __in which
will raise if the cache is None; guard the cache first (in
find_roles_on_facility_location) by checking
facility_location.facility_organization_cache is truthy/iterable and if not
return an empty set, otherwise perform the
FacilityOrganizationUser.objects.filter(...,
organization_id__in=facility_location.facility_organization_cache,
user=user).values_list("role_id", flat=True) and return set(roles).
care/security/authorization/healthcare_service.py (1)

10-21: Handle nullable parent_cache defensively in role resolution.

Current logic works as long as parent_cache is always iterable; if not, this blows up quickly in production.

Suggested patch
 def find_roles_on_healthcare_service(self, user, healthcare_service):
-    roles = set()
-    if healthcare_service.managing_organization:
-        orgs = [
-            *healthcare_service.managing_organization.parent_cache,
-            healthcare_service.managing_organization.id,
-        ]
-        roles = FacilityOrganizationUser.objects.filter(
-            organization_id__in=orgs,
-            user=user,
-        ).values_list("role_id", flat=True)
-    return set(roles)
+    if not healthcare_service.managing_organization:
+        return set()
+
+    parent_cache = healthcare_service.managing_organization.parent_cache or []
+    orgs = [*parent_cache, healthcare_service.managing_organization.id]
+    roles = FacilityOrganizationUser.objects.filter(
+        organization_id__in=orgs,
+        user=user,
+    ).values_list("role_id", flat=True)
+    return set(roles)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@care/security/authorization/healthcare_service.py` around lines 10 - 21, The
method find_roles_on_healthcare_service can raise if
healthcare_service.managing_organization.parent_cache is None or not iterable;
defensively handle this by treating parent_cache as an empty iterable when
absent. Update the logic in find_roles_on_healthcare_service to access
parent_cache via a safe fallback (e.g., parent_cache =
getattr(healthcare_service.managing_organization, "parent_cache", []) or check
for None) and build orgs = [*parent_cache,
healthcare_service.managing_organization.id] only after ensuring parent_cache is
iterable, then call
FacilityOrganizationUser.objects.filter(...).values_list("role_id", flat=True)
as before.
care/emr/resources/permissions.py (1)

77-81: De-duplicate permission slugs before serializing.

Right now users with overlapping roles can get repeated permission strings. Not fatal, just unnecessarily noisy.

Suggested patch
         mapping["permissions"] = list(
             RolePermission.objects.filter(
                 role_id__in=roles, permission__context__in=["FACILITY"]
-            ).values_list("permission__slug", flat=True)
+            ).values_list("permission__slug", flat=True).distinct()
         )
@@
         mapping["permissions"] = list(
             RolePermission.objects.filter(
                 role_id__in=roles, permission__context__in=["FACILITY"]
-            ).values_list("permission__slug", flat=True)
+            ).values_list("permission__slug", flat=True).distinct()
         )

Also applies to: 91-95

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@care/emr/resources/permissions.py` around lines 77 - 81, The permission slug
list constructed via mapping["permissions"] is not deduplicated; change the
query to return unique slugs by appending .distinct() to
RolePermission.objects.filter(...).values_list("permission__slug",
flat=True).distinct() and convert that to a list, and apply the same fix to the
other occurrence that builds permissions (the similar
RolePermission.objects.filter(...) block around lines 91-95) so serialized
permission strings are unique.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@care/emr/resources/permissions.py`:
- Around line 77-81: The permission slug list constructed via
mapping["permissions"] is not deduplicated; change the query to return unique
slugs by appending .distinct() to
RolePermission.objects.filter(...).values_list("permission__slug",
flat=True).distinct() and convert that to a list, and apply the same fix to the
other occurrence that builds permissions (the similar
RolePermission.objects.filter(...) block around lines 91-95) so serialized
permission strings are unique.

In `@care/security/authorization/facility_location.py`:
- Around line 14-18: The method find_roles_on_facility_location uses
facility_location.facility_organization_cache directly in a filter __in which
will raise if the cache is None; guard the cache first (in
find_roles_on_facility_location) by checking
facility_location.facility_organization_cache is truthy/iterable and if not
return an empty set, otherwise perform the
FacilityOrganizationUser.objects.filter(...,
organization_id__in=facility_location.facility_organization_cache,
user=user).values_list("role_id", flat=True) and return set(roles).

In `@care/security/authorization/healthcare_service.py`:
- Around line 10-21: The method find_roles_on_healthcare_service can raise if
healthcare_service.managing_organization.parent_cache is None or not iterable;
defensively handle this by treating parent_cache as an empty iterable when
absent. Update the logic in find_roles_on_healthcare_service to access
parent_cache via a safe fallback (e.g., parent_cache =
getattr(healthcare_service.managing_organization, "parent_cache", []) or check
for None) and build orgs = [*parent_cache,
healthcare_service.managing_organization.id] only after ensuring parent_cache is
iterable, then call
FacilityOrganizationUser.objects.filter(...).values_list("role_id", flat=True)
as before.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 511231b8-1be6-4ab7-8ef4-b86e6b199bf3

📥 Commits

Reviewing files that changed from the base of the PR and between 82591d7 and c994114.

📒 Files selected for processing (5)
  • care/emr/resources/healthcare_service/spec.py
  • care/emr/resources/location/spec.py
  • care/emr/resources/permissions.py
  • care/security/authorization/facility_location.py
  • care/security/authorization/healthcare_service.py

@codecov
Copy link

codecov bot commented Mar 6, 2026

Codecov Report

❌ Patch coverage is 89.28571% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.24%. Comparing base (82591d7) to head (c994114).

Files with missing lines Patch % Lines
care/security/authorization/healthcare_service.py 57.14% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3561      +/-   ##
===========================================
+ Coverage    76.22%   76.24%   +0.01%     
===========================================
  Files          474      474              
  Lines        22261    22287      +26     
  Branches      2324     2325       +1     
===========================================
+ Hits         16969    16992      +23     
- Misses        4764     4766       +2     
- Partials       528      529       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant