Skip to content

Fix/owner case creation rights#228

Merged
annikaholmqvist94 merged 6 commits into
mainfrom
fix/owner-case-creation-rights
Apr 22, 2026
Merged

Fix/owner case creation rights#228
annikaholmqvist94 merged 6 commits into
mainfrom
fix/owner-case-creation-rights

Conversation

@annikaholmqvist94

@annikaholmqvist94 annikaholmqvist94 commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

Efter #216 kunde OWNER inte längre skapa ärenden eller ladda upp bilagor. Den här PR:en särar på "skapa/ladda upp/läsa" från "uppdatera/stänga/radera" så att OWNER fungerar som på 1177 kan
registrera och följa sitt eget djurs ärende

OWNER kan

  • POST /api/medical-records för eget djur
  • POST /api/attachments/record/{id} på eget öppet ärende
  • POST /api/comments på eget ärende (typ OWNER_MESSAGE)
  • Läsa eget ärende, egna bilagor och samtliga kommentarer på eget ärende — inklusive VET:ens VET_CLINICAL_NOTE

OWNER kan inte

  • PUT /api/medical-records/{id} (journal-uppdatering)
  • PUT /api/medical-records/{id}/status · /close · /assign-vet
  • DELETE /api/attachments/**

Ändringar

SecurityConfig

  • PUT /api/medical-records/* och DELETE /api/attachments/** → hasAnyRole("VET","ADMIN")
  • POST /api/medical-records och POST /api/attachments/** faller igenom till authenticated() — policy tar ägarskapet

MedicalRecordPolicy

  • canCreate: OWNER tillåts för eget djur
  • canUpdate: OWNER spärrad ("Ägare får inte uppdatera journaler")
  • Roll-/ägarskapskontroll körs nu före isFinal → OWNER på stängt ärende får 403, inte 422 (CodeRabbit-kommentar på Fix/role based endpoint rules #216)

AttachmentPolicy

  • canUpload: kaskaden till canUpdate borttagen. Egna regler: ADMIN ✓, VET samma klinik ✓, OWNER eget ärende + ej CLOSED ✓
  • canDelete: OWNER spärrad ("Djurägare får inte radera bilagor"); VET/ADMIN oförändrat

CommentPolicy

  • isVisibleTo släpper alla roller — OWNER ser VET:ens journalanteckningar på eget ärende (1177-modellen)

Tester

  • MedicalRecordPolicyTest: uppdaterade canCreate-meddelande, ny canUpdate_owner_shouldThrowForbidden + canUpdate_ownerOnClosedRecord_shouldThrowForbiddenNotBusinessRule
  • AttachmentPolicyTest (ny, 14 tester): OWNER/VET/ADMIN × upload/delete, stängt case, fel klinik, tom fil, otillåten content-type
  • CommentPolicyTest: fyra isVisibleTo-test uppdaterade till nytt beteende

Test plan

  • OWNER skapar ärende för eget djur → 201
  • OWNER laddar upp bilaga på eget öppet ärende → 201; på stängt → 403
  • OWNER PUT/status/close/assign-vet + DELETE attachment → 403
  • OWNER ser VET:ens journalanteckning på eget ärende
  • VET/ADMIN-flöden oförändrade

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced role-based authorization for attachment uploads and deletions; owners are now prohibited from deleting attachments
    • Restricted medical record creation and updates for owners; owners cannot modify journals
    • Improved access controls for veterinarians with clinic affiliation verification
    • Revised comment visibility rules to enable broader access within authorization boundaries
  • Chores

    • Updated security configuration to enforce authorization changes

@coderabbitai

coderabbitai Bot commented Apr 21, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Authorization logic refactored across policies: AttachmentPolicy now implements role-specific upload/delete rules independent of MedicalRecordPolicy; CommentPolicy.isVisibleTo simplified to always return true; MedicalRecordPolicy restructures control flow for create/update/close operations; SecurityConfig adds authorization matchers for attachment and medical record endpoints.

Changes

Cohort / File(s) Summary
Authorization Policies
src/main/java/org/example/vet1177/policy/AttachmentPolicy.java, src/main/java/org/example/vet1177/policy/CommentPolicy.java, src/main/java/org/example/vet1177/policy/MedicalRecordPolicy.java
Attachment policy now enforces role-specific authorization (ADMIN unrestricted; VET requires clinic match; OWNER forbidden for delete). Comment visibility simplified to always return true. Medical record policy restructures authorization checks with reordered control flow and updated error messages for create/update/close operations.
Security Configuration
src/main/java/org/example/vet1177/security/SecurityConfig.java
Added HTTP authorization matchers for PUT /api/medical-records/* (VET/ADMIN) and DELETE /api/attachments/** (VET/ADMIN); updated comments to reference policy-level authorization logic.
Policy Tests
src/test/java/org/example/vet1177/policy/CommentPolicyTest.java, src/test/java/org/example/vet1177/policy/MedicalRecordPolicyTest.java
Updated test expectations for isVisibleTo owner visibility (now always true); renamed and restructured canCreate/canUpdate owner tests with new exception messages; added validation order test for closed records.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • Issue #225: Directly addresses the code changes in this PR—modifies AttachmentPolicy.canUpload/canDelete, restructures MedicalRecordPolicy authorization for OWNER role, and updates SecurityConfig matchers to enforce new access rules.

Possibly related PRs

  • PR #49: Introduces/modifies CommentPolicy visibility authorization; this PR's changes to isVisibleTo (removing type-based filtering) directly relate to that policy's authorization behavior.
  • PR #106: Modifies AttachmentPolicy.canUpload/canDelete methods; this PR replaces the delegation pattern with new role- and clinic-aware authorization logic in the same methods.
  • PR #216: Modifies all four affected policy files (AttachmentPolicy, CommentPolicy, MedicalRecordPolicy, SecurityConfig) at the code level with overlapping authorization and security logic changes.

Suggested labels

säkerhet, test

Suggested reviewers

  • johanbriger
  • TatjanaTrajkovic

Poem

🐰 Role checks now flow with clarity and care,
Attachments guarded by clinic-aware stare,
Comments for all, but access still gated,
Medical records where OWNER's been slated,
Security tightened, policies aligned—hop, hooray! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix/owner case creation rights' directly addresses the main objective: restoring OWNER's ability to create medical records for their own animals after losing it in PR #216.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/owner-case-creation-rights

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/test/java/org/example/vet1177/policy/MedicalRecordPolicyTest.java (1)

145-149: Optional: also assert the message to lock in ordering.

The test guarantees type but not that the forbidden path came from the role check rather than any other ForbiddenException. Adding .hasMessage("Ägare får inte uppdatera journaler") would pin the ordering (role → isFinal) more strictly and future-proof against regressions where someone adds an earlier forbidden throw.

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

In `@src/test/java/org/example/vet1177/policy/MedicalRecordPolicyTest.java` around
lines 145 - 149, The test
canUpdate_ownerOnClosedRecord_shouldThrowForbiddenNotBusinessRule currently only
asserts the exception type, so add an assertion on the exception message to
ensure the forbidden came from the role check ordering; update the assertion on
policy.canUpdate(owner, closedRecord) to also call .hasMessage("Ägare får inte
uppdatera journaler") after .isInstanceOf(ForbiddenException.class) so the test
verifies both type and exact message.
src/main/java/org/example/vet1177/policy/AttachmentPolicy.java (1)

36-58: Minor: authz check runs after file validation.

validateFileType/validateFileSize run before the role/ownership switch, so an unauthorized caller uploading a bad file gets a BusinessRuleException about file format/size instead of a 403. Not a security hole — the call is still rejected — but it leaks business rules to callers who shouldn't be touching the record and can be confusing to debug. Consider reordering: role/ownership first, then file-content validations.

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

In `@src/main/java/org/example/vet1177/policy/AttachmentPolicy.java` around lines
36 - 58, The authorization checks in canUpload are performed after file
validations, leaking business rules to unauthorized callers; reorder the logic
in canUpload so the role/ownership switch (checks using user.getRole(),
user.getClinic(), record.getClinic(), record.getOwner(), record.getStatus(), and
RecordStatus.CLOSED) runs first and returns/throws ForbiddenException for
ADMIN/VET/OWNER as appropriate, and only after passing those auth checks call
validateFileType(contentType) and validateFileSize(fileSize) (including the
fileSize <= 0 IllegalArgumentException check) so file-format/size errors are
only exposed to authorized callers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/java/org/example/vet1177/policy/AttachmentPolicy.java`:
- Around line 51-56: Replace the direct enum comparison in AttachmentPolicy's
OWNER branch: instead of checking "record.getStatus() == RecordStatus.CLOSED"
use the existing status helper by calling "record.getStatus().isFinal()"; update
the conditional in the OWNER case (inside the AttachmentPolicy class, where
record.getOwner() is compared to user.getId()) to throw the same
ForbiddenException when record.getStatus().isFinal() is true so it matches
MedicalRecordService/MedicalRecordPolicy/CommentPolicy behavior.

---

Nitpick comments:
In `@src/main/java/org/example/vet1177/policy/AttachmentPolicy.java`:
- Around line 36-58: The authorization checks in canUpload are performed after
file validations, leaking business rules to unauthorized callers; reorder the
logic in canUpload so the role/ownership switch (checks using user.getRole(),
user.getClinic(), record.getClinic(), record.getOwner(), record.getStatus(), and
RecordStatus.CLOSED) runs first and returns/throws ForbiddenException for
ADMIN/VET/OWNER as appropriate, and only after passing those auth checks call
validateFileType(contentType) and validateFileSize(fileSize) (including the
fileSize <= 0 IllegalArgumentException check) so file-format/size errors are
only exposed to authorized callers.

In `@src/test/java/org/example/vet1177/policy/MedicalRecordPolicyTest.java`:
- Around line 145-149: The test
canUpdate_ownerOnClosedRecord_shouldThrowForbiddenNotBusinessRule currently only
asserts the exception type, so add an assertion on the exception message to
ensure the forbidden came from the role check ordering; update the assertion on
policy.canUpdate(owner, closedRecord) to also call .hasMessage("Ägare får inte
uppdatera journaler") after .isInstanceOf(ForbiddenException.class) so the test
verifies both type and exact message.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f6a846f4-f5f1-4d51-a728-d97f7a9513c8

📥 Commits

Reviewing files that changed from the base of the PR and between 60f6cea and e888a95.

📒 Files selected for processing (6)
  • src/main/java/org/example/vet1177/policy/AttachmentPolicy.java
  • src/main/java/org/example/vet1177/policy/CommentPolicy.java
  • src/main/java/org/example/vet1177/policy/MedicalRecordPolicy.java
  • src/main/java/org/example/vet1177/security/SecurityConfig.java
  • src/test/java/org/example/vet1177/policy/CommentPolicyTest.java
  • src/test/java/org/example/vet1177/policy/MedicalRecordPolicyTest.java

Comment on lines +51 to +56
case OWNER -> {
if (!record.getOwner().getId().equals(user.getId()))
throw new ForbiddenException("Du kan bara ladda upp bilagor på egna ärenden");
if (record.getStatus() == RecordStatus.CLOSED)
throw new ForbiddenException("Bilagor kan inte laddas upp på stängda ärenden");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -t f 'RecordStatus.java' --exec cat {}
rg -nP '\bisFinal\s*\(' --type=java -C2

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 5640


Use RecordStatus.isFinal() instead of == CLOSED for consistency with the rest of the codebase.

MedicalRecordService, MedicalRecordPolicy, and CommentPolicy all use record.getStatus().isFinal(). For consistency, AttachmentPolicy should do the same instead of the direct enum comparison.

♻️ Proposed fix
             case OWNER -> {
                 if (!record.getOwner().getId().equals(user.getId()))
                     throw new ForbiddenException("Du kan bara ladda upp bilagor på egna ärenden");
-                if (record.getStatus() == RecordStatus.CLOSED)
+                if (record.getStatus().isFinal())
                     throw new ForbiddenException("Bilagor kan inte laddas upp på stängda ärenden");
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/vet1177/policy/AttachmentPolicy.java` around lines
51 - 56, Replace the direct enum comparison in AttachmentPolicy's OWNER branch:
instead of checking "record.getStatus() == RecordStatus.CLOSED" use the existing
status helper by calling "record.getStatus().isFinal()"; update the conditional
in the OWNER case (inside the AttachmentPolicy class, where record.getOwner() is
compared to user.getId()) to throw the same ForbiddenException when
record.getStatus().isFinal() is true so it matches
MedicalRecordService/MedicalRecordPolicy/CommentPolicy behavior.

@annikaholmqvist94
annikaholmqvist94 merged commit 23b6423 into main Apr 22, 2026
2 checks passed
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