Skip to content

feat:Added proper validations and testcases to diagnostic report api#3566

Open
nandkishorr wants to merge 11 commits intodevelopfrom
nandkishorr/fix/diagnostic_report
Open

feat:Added proper validations and testcases to diagnostic report api#3566
nandkishorr wants to merge 11 commits intodevelopfrom
nandkishorr/fix/diagnostic_report

Conversation

@nandkishorr
Copy link
Contributor

@nandkishorr nandkishorr commented Mar 9, 2026

Proposed Changes

  • Added detailed permission validation exceptions

  • Added testcases for the diagnostic report api

ohcnetwork/roadmap#246

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

  • Bug Fixes

    • Strengthened authorization checks with explicit permission validation and improved error messaging for restricted clinical data access.
  • Tests

    • Added comprehensive test suite covering diagnostic report creation, retrieval, updates, and observation management with authorization boundary testing.

@nandkishorr nandkishorr self-assigned this Mar 9, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 9, 2026

📝 Walkthrough

Walkthrough

The pull request refactors authorization checks in the diagnostic report viewset to use explicit PermissionDenied exceptions instead of conditional filtering, and introduces a comprehensive test suite covering CRUD operations, filtering, and observation upserts across multiple permission scenarios.

Changes

Cohort / File(s) Summary
Authorization Logic Refactor
care/emr/api/viewsets/diagnostic_report.py
Inverted authorization checks in get_queryset to raise PermissionDenied on failure rather than returning conditionally filtered querysets. Updated encounter, service_request, and patient-based filtering to enforce explicit permission validation with standardized error messages.
Diagnostic Report Test Suite
care/emr/tests/test_diagnostic_report_api.py
Added comprehensive test coverage across two test classes: DiagnosticReportAPITestCases (covering creation, retrieval, listing, and updates with various permission levels and filters) and DiagnosticReportUpsertObservationAPITestCases (covering observation upsert operations, validation, and authorization boundaries).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 73.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning PR description lacks required details: missing 'Associated Issue' section structure, no explanation of how changes solve the issue, and 'Proposed Changes' section is vague. Expand 'Proposed Changes' with specific implementation details; add 'Associated Issue' section with issue link and explanation; clarify which test cases were added and what they cover.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main changes: adding proper validations and test cases to the diagnostic report API, which matches the file modifications.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch nandkishorr/fix/diagnostic_report

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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 (4)
care/emr/api/viewsets/diagnostic_report.py (1)

148-158: Redundant patient filter on line 158.

The queryset is already filtered by patient=self.get_patient_obj() on line 117. The additional .filter(patient=patient) on line 158 is technically harmless but unnecessary.

🔧 Suggested simplification
         # Authorize with Patient
         patient = self.get_patient_obj()
         if not AuthorizationController.call(
             "can_view_clinical_data",
             self.request.user,
             patient,
         ):
             raise PermissionDenied(
                 "You do not have permission to view clinical data for this patient"
             )
-        return queryset.filter(patient=patient)
+        return queryset
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@care/emr/api/viewsets/diagnostic_report.py` around lines 148 - 158, The extra
queryset.filter(patient=patient) after the authorization check is redundant
because get_patient_obj() was already used to filter the queryset earlier;
remove the final .filter(patient=patient) and simply return the existing
queryset after the AuthorizationController.call check (locate this in the
DiagnosticReportViewSet or the view method using get_patient_obj,
AuthorizationController.call and PermissionDenied).
care/emr/tests/test_diagnostic_report_api.py (3)

576-594: Same setdefault pattern as noted earlier.

The create_observation helper also uses setdefault on kwargs, which has the same mutation side effect mentioned before.

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

In `@care/emr/tests/test_diagnostic_report_api.py` around lines 576 - 594, The
helper create_observation mutates the incoming kwargs by repeatedly calling
kwargs.setdefault (on keys like "diagnostic_report", "encounter", "patient",
"created_by"), which can cause surprising side effects for callers; replace the
setdefault usage by constructing local defaults and merging them with a new dict
(e.g., build a local defaults = {...} using self.diagnostic_report,
self.encounter, self.patient, self.superuser and then do data.update(defaults)
followed by data.update(kwargs)) so create_observation no longer mutates the
caller's kwargs.

1-1: Consider using random.choice instead of secrets.choice.

The secrets module is designed for cryptographic purposes like generating tokens and passwords. For test fixtures where security isn't a concern, random.choice is the conventional and more readable option.

🔧 Suggested change
-from secrets import choice
+from random import choice
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@care/emr/tests/test_diagnostic_report_api.py` at line 1, Replace the
cryptographic import and usage of secrets.choice with the standard library
random.choice in the test file: change the import from "from secrets import
choice" to use "import random" (or "from random import choice") and update any
calls that reference choice to use random.choice (or leave as choice if using
from random import choice); target the test module where the import occurs and
the functions/tests that rely on choice so tests use random.choice for
non-crypto randomness.

80-96: setdefault mutates the incoming kwargs dictionary.

Using setdefault on kwargs modifies the caller's dictionary in place, which could cause surprising behavior if the same dict were ever reused. This is a minor concern since each test typically passes fresh kwargs, but it's worth noting for maintainability.

🔧 Safer approach using `get` with defaults
     def create_diagnostic_report(self, **kwargs):
         data = {
             "status": DiagnosticReportStatusChoices.final.value,
             "category": {
                 "display": "Laboratory",
                 "code": "LAB",
                 "system": "http://terminology.hl7.org/CodeSystem/v2-0074",
             },
-            "service_request": kwargs.setdefault(
-                "service_request", self.service_request
-            ),
-            "patient": kwargs.setdefault("patient", self.patient),
-            "encounter": kwargs.setdefault("encounter", self.encounter),
-            "facility": kwargs.setdefault("facility", self.facility),
+            "service_request": kwargs.get("service_request", self.service_request),
+            "patient": kwargs.get("patient", self.patient),
+            "encounter": kwargs.get("encounter", self.encounter),
+            "facility": kwargs.get("facility", self.facility),
         }
         data.update(**kwargs)
         return baker.make(DiagnosticReport, **data)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@care/emr/tests/test_diagnostic_report_api.py` around lines 80 - 96, The
helper create_diagnostic_report mutates the incoming kwargs via
kwargs.setdefault; change it to avoid in-place mutation by reading defaults with
kwargs.get (e.g., service_request = kwargs.get("service_request",
self.service_request), patient = kwargs.get("patient", self.patient), encounter
= kwargs.get("encounter", self.encounter), facility = kwargs.get("facility",
self.facility)), use those local variables when building data, then call
data.update(kwargs) and return baker.make(DiagnosticReport, **data) so the
original kwargs is not modified; update the setdefault usages in
create_diagnostic_report accordingly.
🤖 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/api/viewsets/diagnostic_report.py`:
- Around line 148-158: The extra queryset.filter(patient=patient) after the
authorization check is redundant because get_patient_obj() was already used to
filter the queryset earlier; remove the final .filter(patient=patient) and
simply return the existing queryset after the AuthorizationController.call check
(locate this in the DiagnosticReportViewSet or the view method using
get_patient_obj, AuthorizationController.call and PermissionDenied).

In `@care/emr/tests/test_diagnostic_report_api.py`:
- Around line 576-594: The helper create_observation mutates the incoming kwargs
by repeatedly calling kwargs.setdefault (on keys like "diagnostic_report",
"encounter", "patient", "created_by"), which can cause surprising side effects
for callers; replace the setdefault usage by constructing local defaults and
merging them with a new dict (e.g., build a local defaults = {...} using
self.diagnostic_report, self.encounter, self.patient, self.superuser and then do
data.update(defaults) followed by data.update(kwargs)) so create_observation no
longer mutates the caller's kwargs.
- Line 1: Replace the cryptographic import and usage of secrets.choice with the
standard library random.choice in the test file: change the import from "from
secrets import choice" to use "import random" (or "from random import choice")
and update any calls that reference choice to use random.choice (or leave as
choice if using from random import choice); target the test module where the
import occurs and the functions/tests that rely on choice so tests use
random.choice for non-crypto randomness.
- Around line 80-96: The helper create_diagnostic_report mutates the incoming
kwargs via kwargs.setdefault; change it to avoid in-place mutation by reading
defaults with kwargs.get (e.g., service_request = kwargs.get("service_request",
self.service_request), patient = kwargs.get("patient", self.patient), encounter
= kwargs.get("encounter", self.encounter), facility = kwargs.get("facility",
self.facility)), use those local variables when building data, then call
data.update(kwargs) and return baker.make(DiagnosticReport, **data) so the
original kwargs is not modified; update the setdefault usages in
create_diagnostic_report accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 87feb246-9c46-4116-bc38-6d72acd5bec9

📥 Commits

Reviewing files that changed from the base of the PR and between 924ca74 and 79c223d.

📒 Files selected for processing (2)
  • care/emr/api/viewsets/diagnostic_report.py
  • care/emr/tests/test_diagnostic_report_api.py

@nandkishorr nandkishorr requested a review from a team as a code owner March 10, 2026 05:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant