Skip to content

feat: implement AttachmentController and record-based file management#129

Merged
johanbriger merged 6 commits intomainfrom
44-feat-attachmentcontrollerjava
Apr 6, 2026
Merged

feat: implement AttachmentController and record-based file management#129
johanbriger merged 6 commits intomainfrom
44-feat-attachmentcontrollerjava

Conversation

@johanbriger
Copy link
Copy Markdown
Contributor

@johanbriger johanbriger commented Apr 5, 2026

  • Added AttachmentController with endpoints for upload, download, and listing.
  • Updated AttachmentService with multipart support and S3 integration.
  • Implemented findByMedicalRecordId in AttachmentRepository.

Summary by CodeRabbit

  • New Features

    • Added attachment management endpoints: authenticated upload (multipart) with optional description and validation, list attachments for a record, download, and delete.
    • Service support to fetch attachments by record with access checks.
  • Bug Fixes / Improvements

    • Sanitized filenames before storage; improved upload error handling, logging and cleanup to reduce orphaned storage.
    • Validation failures now return structured 400 responses with error details.

@johanbriger johanbriger linked an issue Apr 5, 2026 that may be closed by this pull request
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 5, 2026

📝 Walkthrough

Walkthrough

Added an Attachment REST controller with upload/list/download/delete endpoints, service additions for listing attachments by medical record and S3 key filename sanitization, a small repository parameter rename, and a global handler for jakarta.validation.ConstraintViolationException.

Changes

Cohort / File(s) Summary
REST Controller
src/main/java/org/example/vet1177/controller/AttachmentController.java
New @RestController at /api/attachments: POST /record/{recordId} (multipart upload + optional description, validation), GET /record/{recordId} (list), GET /{id}/download (download), DELETE /{id} (delete). Delegates to AttachmentService.
Service Layer
src/main/java/org/example/vet1177/services/AttachmentService.java
Added getAttachmentsByRecord(User, UUID); constructor now accepts MedicalRecordPolicy; S3 key generation uses sanitized filename; removed throws IOException and handles IO with local catch converting to RuntimeException; refined S3/database error logging and cleanup.
Repository
src/main/java/org/example/vet1177/repository/AttachmentRepository.java
Parameter rename in findByMedicalRecordId(...): recordIdmedicalRecordId (name-only change).
Exception Handling
src/main/java/org/example/vet1177/exception/GlobalExceptionHandler.java
Added handler for jakarta.validation.ConstraintViolationException that maps violations to a Map<String,List<String>> and returns an ErrorResponse with HTTP 400.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Controller as "AttachmentController"
    participant Auth as "Authentication (User)"
    participant Service as "AttachmentService"
    participant MRRepo as "MedicalRecordRepository"
    participant AttachRepo as "AttachmentRepository"
    participant FileStorage as "FileStorageService (S3)"

    Client->>Controller: POST /api/attachments/record/{recordId} (multipart file, description)
    Controller->>Auth: resolve current User
    Controller->>Service: uploadAttachment(User, recordId, file, description)
    Service->>MRRepo: findById(recordId)
    MRRepo-->>Service: MedicalRecord
    Service->>FileStorage: upload(s3Key (uses sanitizedName), fileStream, metadata)
    FileStorage-->>Service: upload result
    Service->>AttachRepo: save(Attachment entity)
    AttachRepo-->>Service: saved Attachment
    Service-->>Controller: AttachmentResponse
    Controller-->>Client: 201 Created + body
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • annikaholmqvist94
  • lindaeskilsson
  • TatjanaTrajkovic

Poem

🐰 I hopped through code to open a crate,
Saved tiny files to S3's gate,
Lists that gather, downloads that sing,
Deletions tidy — click and spring,
A rabbit cheers: attachments, celebrate! 📎

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: implementing AttachmentController with record-based file management functionality, which directly aligns with the additions across multiple files.

✏️ 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 44-feat-attachmentcontrollerjava

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
Copy Markdown

@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.

Actionable comments posted: 2

🤖 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/controller/AttachmentController.java`:
- Around line 33-45: The controller currently lets IOException bubble out from
uploadAttachment in AttachmentController, which causes it to be handled as a
generic 500; either catch IOException inside uploadAttachment (around the call
to attachmentService.uploadAttachment) and return a descriptive ResponseEntity
(e.g., 400 Bad Request with a message like "Invalid or corrupted upload" or 502
for storage backend issues) or translate the IOException into a domain-specific
runtime exception (e.g., AttachmentStorageException) and throw that so
GlobalExceptionHandler can map it; alternatively add an
`@ExceptionHandler`(IOException.class) to GlobalExceptionHandler to return a clear
status and payload for IO failures—use the method name uploadAttachment, DTOs
AttachmentRequest/AttachmentResponse, and the attachmentService call to locate
where to implement the try/catch or exception translation.

In `@src/main/java/org/example/vet1177/services/AttachmentService.java`:
- Around line 167-176: The method getAttachmentsByRecord currently loads the
MedicalRecord via medicalRecordRepository.findById(recordId) but does not
enforce any authorization; before returning the attachments from
attachmentRepository.findByMedicalRecordId(recordId) you must perform the same
permission check used elsewhere (either call
medicalRecordPolicy.canView(currentUser, record) or, if you prefer
AttachmentPolicy, add and call an overloaded attachmentPolicy.canDownload(User,
MedicalRecord) or similar) and throw an appropriate access denied exception when
the check fails; ensure you inject/use medicalRecordPolicy or attachmentPolicy
in AttachmentService and run the check right after fetching the MedicalRecord
and before mapping/returning attachments.
🪄 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: cf9a4ebc-7a41-4df4-9490-ea751c276fb8

📥 Commits

Reviewing files that changed from the base of the PR and between f98cc06 and 21ee3d3.

📒 Files selected for processing (3)
  • src/main/java/org/example/vet1177/controller/AttachmentController.java
  • src/main/java/org/example/vet1177/repository/AttachmentRepository.java
  • src/main/java/org/example/vet1177/services/AttachmentService.java

Copy link
Copy Markdown

@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.

Actionable comments posted: 1

🤖 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/controller/AttachmentController.java`:
- Around line 33-37: The controller currently declares
`@RequestPart`("description") as a required parameter, bypassing the optional
nature and `@Size`(max=500) validation on AttachmentRequest.description; update
the AttachmentController method to accept the description as optional (e.g.,
`@RequestPart`(name="description", required=false) or nullable String) and
explicitly apply the DTO validation (use a BindingResult/Validator or construct
an AttachmentRequest and call javax.validation.Validator) so the
AttachmentRequest.description field's `@Size`(max=500) constraint is enforced
before proceeding; locate the controller method in AttachmentController and the
AttachmentRequest class to implement these changes.
🪄 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: e4b63545-f81f-40ae-b284-ccec549088ca

📥 Commits

Reviewing files that changed from the base of the PR and between 21ee3d3 and cb2f9bb.

📒 Files selected for processing (2)
  • src/main/java/org/example/vet1177/controller/AttachmentController.java
  • src/main/java/org/example/vet1177/services/AttachmentService.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/org/example/vet1177/services/AttachmentService.java

Copy link
Copy Markdown

@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.

Actionable comments posted: 1

🤖 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/controller/AttachmentController.java`:
- Around line 44-47: The controller currently throws
ConstraintViolationException from AttachmentController when
validator.validate(request) fails, which is not handled by
GlobalExceptionHandler and yields HTTP 500; fix by either adding a dedicated
handler for ConstraintViolationException in GlobalExceptionHandler (create a
method annotated with `@ExceptionHandler`(ConstraintViolationException.class) and
`@ResponseStatus`(HttpStatus.BAD_REQUEST) that converts
ex.getConstraintViolations() into your ErrorResponse structure and logs the
details) or modify AttachmentController to catch ConstraintViolationException
and rethrow a handled exception type (e.g., BusinessRuleException with
appropriate message/body) so GlobalExceptionHandler returns HTTP 400; reference
the symbols ConstraintViolationException, AttachmentController,
validator.validate(request), GlobalExceptionHandler, and ErrorResponse when
implementing the change.
🪄 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: dd368f49-0005-43a7-9ea1-b36d182ae3e3

📥 Commits

Reviewing files that changed from the base of the PR and between cb2f9bb and b6f58f4.

📒 Files selected for processing (1)
  • src/main/java/org/example/vet1177/controller/AttachmentController.java

@johanbriger
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 5, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@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 (2)
src/main/java/org/example/vet1177/exception/GlobalExceptionHandler.java (2)

96-100: Keep error-message language consistent across handlers.

Line 98 returns "Valideringsfel" while the rest of this class uses English messages. Standardizing this improves API consistency for clients.

Suggested small cleanup
         ErrorResponse error = new ErrorResponse(
                 HttpStatus.BAD_REQUEST.value(),
-                "Valideringsfel",
-                validationErrors // <--- Nu matchar vi Map<String, List<String>>
+                "Validation failed",
+                validationErrors
         );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/vet1177/exception/GlobalExceptionHandler.java`
around lines 96 - 100, In GlobalExceptionHandler, the ErrorResponse created in
the validation handler uses the Swedish string "Valideringsfel"; change this to
an English message consistent with the rest of the class (e.g., "Validation
error" or "Validation failed") so ErrorResponse(...) uses the same language as
other handlers; update the message passed where ErrorResponse is constructed
(around the validationErrors map creation) to match existing English wording
used elsewhere in GlobalExceptionHandler.

83-103: Add warning logging for constraint violations.

This handler is the only validation path without a log entry, which makes troubleshooting harder compared to the other handlers. Add a log.warn(...) before returning.

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

In `@src/main/java/org/example/vet1177/exception/GlobalExceptionHandler.java`
around lines 83 - 103, Add a warning log in
GlobalExceptionHandler.handleConstraintViolation to mirror other handlers:
before creating and returning the ResponseEntity, call log.warn with a concise
message that includes details about the ConstraintViolationException (e.g.,
ex.getMessage() or a summary like validationErrors) so you record the fact of a
validation failure and relevant context; ensure you reference the same
validationErrors map or ex when composing the log message and that the class has
a logger instance (e.g., log) available.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/main/java/org/example/vet1177/exception/GlobalExceptionHandler.java`:
- Around line 96-100: In GlobalExceptionHandler, the ErrorResponse created in
the validation handler uses the Swedish string "Valideringsfel"; change this to
an English message consistent with the rest of the class (e.g., "Validation
error" or "Validation failed") so ErrorResponse(...) uses the same language as
other handlers; update the message passed where ErrorResponse is constructed
(around the validationErrors map creation) to match existing English wording
used elsewhere in GlobalExceptionHandler.
- Around line 83-103: Add a warning log in
GlobalExceptionHandler.handleConstraintViolation to mirror other handlers:
before creating and returning the ResponseEntity, call log.warn with a concise
message that includes details about the ConstraintViolationException (e.g.,
ex.getMessage() or a summary like validationErrors) so you record the fact of a
validation failure and relevant context; ensure you reference the same
validationErrors map or ex when composing the log message and that the class has
a logger instance (e.g., log) available.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c3898cd7-3577-48ee-ab40-5f15f971ada9

📥 Commits

Reviewing files that changed from the base of the PR and between b6f58f4 and af29edb.

📒 Files selected for processing (1)
  • src/main/java/org/example/vet1177/exception/GlobalExceptionHandler.java

@johanbriger johanbriger merged commit 6522ee7 into main Apr 6, 2026
2 checks passed
@johanbriger johanbriger deleted the 44-feat-attachmentcontrollerjava branch April 6, 2026 08:01
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.

Feat: AttachmentController.java

1 participant