Skip to content

Added method to delete images that are broken (mismatch between minio…#107

Merged
SandraNelj merged 2 commits into
mainfrom
fix/removebrokenimages
Apr 24, 2026
Merged

Added method to delete images that are broken (mismatch between minio…#107
SandraNelj merged 2 commits into
mainfrom
fix/removebrokenimages

Conversation

@SandraNelj

@SandraNelj SandraNelj commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

… and database) and refactored test for DocumentController.

Summary by CodeRabbit

  • Bug Fixes
    • Improved error handling for missing files with consistent HTTP responses.
    • Broken images in incident details are now automatically removed from the page.
    • Enhanced reconciliation between file storage systems when inconsistencies are detected.

… and database) and refactored test for DocumentController.
@coderabbitai

coderabbitai Bot commented Apr 24, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@SandraNelj has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 43 minutes and 11 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 43 minutes and 11 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f5c26492-6800-4b5a-988b-8f4ba16dbc8a

📥 Commits

Reviewing files that changed from the base of the PR and between 2390b00 and 5d846c6.

📒 Files selected for processing (3)
  • src/main/java/org/example/team6backend/document/service/DocumentService.java
  • src/main/java/org/example/team6backend/document/service/MinioService.java
  • src/main/resources/static/viewincident.html
📝 Walkthrough

Walkthrough

The PR refactors the document download flow by delegating file retrieval responsibility from DocumentController to DocumentService. The service now includes missing-file error handling with database reconciliation logic. Additional changes add image error handling to the incident view and update tests to match the new delegation pattern.

Changes

Cohort / File(s) Summary
Backend Service & Repository
src/main/java/org/example/team6backend/document/service/DocumentService.java, src/main/java/org/example/team6backend/document/repository/DocumentRepository.java
DocumentService's downloadFile method now catches MinIO exceptions, logs missing files, and reconciles state via deleteByFileKey—new @Transactional annotation added. New repository method deleteByFileKey enables database cleanup of orphaned records.
Controller Delegation
src/main/java/org/example/team6backend/document/controller/DocumentController.java
getFile endpoint delegates file retrieval to documentService.downloadFile instead of calling minioService.getFile directly, maintaining existing response construction logic.
Frontend Error Handling
src/main/resources/static/viewincident.html
Image elements now use incident-img CSS class and receive onerror handlers to remove broken images from DOM. Console logging added for incident payload debug visibility.
Test Refactoring
src/test/java/org/example/team6backend/document/controller/DocumentControllerTest.java
Test setup shifted from global security context to per-request authentication injection. Download mocking updated from minioService.getFile to documentService.downloadFile. Content-Disposition verification removed.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Controller as DocumentController
    participant Service as DocumentService
    participant MinIO as MinIO Service
    participant DB as DocumentRepository
    
    Client->>Controller: GET /download/{fileKey}
    Controller->>Service: downloadFile(fileKey)
    Service->>MinIO: downloadFile(fileKey)
    alt File exists
        MinIO-->>Service: InputStream
        Service-->>Controller: InputStream
        Controller-->>Client: HTTP 200 + file content
    else File missing
        MinIO-->>Service: Exception
        Service->>DB: findByFileKey(fileKey)
        alt DB record exists
            DB-->>Service: Document
            Service->>DB: deleteByFileKey(fileKey)
            DB-->>Service: deleted
        else No DB record
            DB-->>Service: null
        end
        Service-->>Controller: ResponseStatusException (404)
        Controller-->>Client: HTTP 404 "File not found"
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A download that once was so fragile,
Now catches its stumbles with grace,
The Service steps up, cleaning up traces,
While images—broken—fade away,
And tests dance their new ballet. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main objective of the PR—adding functionality to handle broken images caused by mismatches between MinIO and the database.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/removebrokenimages

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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/test/java/org/example/team6backend/document/controller/DocumentControllerTest.java (1)

78-100: ⚠️ Potential issue | 🟠 Major

These two 404 tests will fail with 500 errors: @AuthenticationPrincipal resolves to null without authentication.

DocumentController.getFile unconditionally calls userDetails.getUser() at the start of the handler, before any 404 branches. Since the prior @BeforeEach security setup was removed and these two tests do not include .with(authentication(...)), the @AuthenticationPrincipal parameter resolves to null, causing a NullPointerException which MockMvc surfaces as a 500 error — not the expected 404. (The addFilters = false setting disables the security filter chain but does not inject a principal.)

Add the same authentication post-processor you used in getFile_shouldReturnDocument:

Diff
-		mockMvc.perform(get("/documents/abc")).andExpect(status().isNotFound());
+		mockMvc.perform(get("/documents/abc").with(authentication(auth)))
+				.andExpect(status().isNotFound());

Apply this to both tests at lines 82 and 99.

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

In
`@src/test/java/org/example/team6backend/document/controller/DocumentControllerTest.java`
around lines 78 - 100, Both failing tests call DocumentController.getFile which
dereferences the `@AuthenticationPrincipal` user (userDetails.getUser()) before
any 404 logic, so the MockMvc requests need an authentication principal; update
the two tests getFile_shouldReturn404_whenDocumentNotFound and
getFile_shouldReturn404_whenIncidentNotFound to add the same authentication
post-processor used in getFile_shouldReturnDocument (i.e., chain the
.with(authentication(...)) post-processor on the
mockMvc.perform(get("/documents/abc")) calls) so the principal is injected and
the controller can proceed to return 404 instead of throwing a
NullPointerException.
🧹 Nitpick comments (2)
src/test/java/org/example/team6backend/document/controller/DocumentControllerTest.java (1)

75-75: Consider keeping the Content-Disposition assertion.

Only asserting status().isOk() no longer verifies that the controller still sets the filename header and content type after delegating to DocumentService.downloadFile. A quick header().string(HttpHeaders.CONTENT_DISPOSITION, containsString("test.pdf")) (and content().contentType(MediaType.APPLICATION_PDF)) would catch future regressions in the response-assembly code that is still controller-owned.

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

In
`@src/test/java/org/example/team6backend/document/controller/DocumentControllerTest.java`
at line 75, The test currently only asserts status().isOk() for the mockMvc call
and should also verify the controller still sets response headers after
delegating to DocumentService.downloadFile; update the
mockMvc.perform(get("/documents/abc").with(authentication(auth))) assertion to
include header().string(HttpHeaders.CONTENT_DISPOSITION,
containsString("test.pdf")) and content().contentType(MediaType.APPLICATION_PDF)
so the test checks the Content-Disposition filename and PDF content type that
the controller is responsible for.
src/main/java/org/example/team6backend/document/repository/DocumentRepository.java (1)

18-18: deleteByFileKey is added but never called.

DocumentService.downloadFile performs reconciliation with findByFileKey(...) followed by documentRepository.delete(docOpt.get()), so this new derived-delete method is currently dead code. Either switch the service to call deleteByFileKey(objectKey) directly (avoids the extra SELECT + managed-entity round-trip) or remove the declaration.

Note: Spring Data derived deleteBy... methods must run inside a transaction; since DocumentService.downloadFile is @Transactional, that's fine if you choose to use it.

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

In
`@src/main/java/org/example/team6backend/document/repository/DocumentRepository.java`
at line 18, The new repository method deleteByFileKey(String fileKey) is never
used; update DocumentService.downloadFile to replace the findByFileKey(...) +
documentRepository.delete(docOpt.get()) sequence with a single
documentRepository.deleteByFileKey(objectKey) call to avoid the extra SELECT and
managed-entity round-trip (DocumentService.downloadFile is already
`@Transactional` so the derived delete will run correctly), or if you prefer not
to change service logic, remove the unused deleteByFileKey declaration from
DocumentRepository to avoid dead code.
🤖 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/team6backend/document/service/DocumentService.java`:
- Around line 63-64: In DocumentService inside the catch (Exception e) block
that currently calls log.warn("Missing file in Minio: {}", objectKey), change
the logging to include the caught exception so the stack trace and root cause
are preserved; update the log.warn invocation that references objectKey to also
pass the exception (e) as the throwable parameter so logs show both the message
and the exception details.
- Around line 61-75: MinioService.downloadFile currently wraps all errors into a
generic RuntimeException which makes DocumentService's catch(Exception) delete
DB rows on transient failures; change MinioService.downloadFile to catch MinIO
client ErrorResponseException (check errorCode == "NoSuchKey" or HTTP 404) and
rethrow a specific checked/unchecked FileNotFoundException (or custom
ObjectNotFoundException), leaving other exceptions unchanged, then update
DocumentService to catch only that FileNotFoundException around
minioService.downloadFile(objectKey) and perform the
documentRepository.findByFileKey(...) + delete only in that branch; for all
other exceptions let them propagate as 5xx (or rethrow as
ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, ...)) and include the
caught exception in the log.warn(...) calls so root causes are preserved.

In `@src/main/resources/static/viewincident.html`:
- Around line 101-105: The race comes from assigning img.onerror after inserting
HTML (where images start loading); instead set the error handler before the
browser can fetch or attach it inline when creating the markup rather than via a
separate querySelector pass. Update the code that builds the images (the
innerHTML insertion that produces elements with class ".incident-img") so each
<img> includes the onerror handler inline (or create elements via
document.createElement('img'), set img.onerror = (...) and then set img.src)
instead of relying on the later document.querySelectorAll(...).forEach(...)
block that currently assigns img.onerror.
- Line 87: Remove the debug console.log that prints the full incident payload:
delete the statement console.log("INCIDENT DATA: ", i) in viewincident.html (the
one referencing variable i) so PII is not exposed to the browser console; if you
need runtime tracing instead, replace it with a gated debug/logging mechanism or
a sanitized log that omits subject/description/comments/documents.

---

Outside diff comments:
In
`@src/test/java/org/example/team6backend/document/controller/DocumentControllerTest.java`:
- Around line 78-100: Both failing tests call DocumentController.getFile which
dereferences the `@AuthenticationPrincipal` user (userDetails.getUser()) before
any 404 logic, so the MockMvc requests need an authentication principal; update
the two tests getFile_shouldReturn404_whenDocumentNotFound and
getFile_shouldReturn404_whenIncidentNotFound to add the same authentication
post-processor used in getFile_shouldReturnDocument (i.e., chain the
.with(authentication(...)) post-processor on the
mockMvc.perform(get("/documents/abc")) calls) so the principal is injected and
the controller can proceed to return 404 instead of throwing a
NullPointerException.

---

Nitpick comments:
In
`@src/main/java/org/example/team6backend/document/repository/DocumentRepository.java`:
- Line 18: The new repository method deleteByFileKey(String fileKey) is never
used; update DocumentService.downloadFile to replace the findByFileKey(...) +
documentRepository.delete(docOpt.get()) sequence with a single
documentRepository.deleteByFileKey(objectKey) call to avoid the extra SELECT and
managed-entity round-trip (DocumentService.downloadFile is already
`@Transactional` so the derived delete will run correctly), or if you prefer not
to change service logic, remove the unused deleteByFileKey declaration from
DocumentRepository to avoid dead code.

In
`@src/test/java/org/example/team6backend/document/controller/DocumentControllerTest.java`:
- Line 75: The test currently only asserts status().isOk() for the mockMvc call
and should also verify the controller still sets response headers after
delegating to DocumentService.downloadFile; update the
mockMvc.perform(get("/documents/abc").with(authentication(auth))) assertion to
include header().string(HttpHeaders.CONTENT_DISPOSITION,
containsString("test.pdf")) and content().contentType(MediaType.APPLICATION_PDF)
so the test checks the Content-Disposition filename and PDF content type that
the controller is responsible for.
🪄 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: b20c5c0d-9354-4c1b-977c-ab5c6f0999f3

📥 Commits

Reviewing files that changed from the base of the PR and between b094e94 and 2390b00.

📒 Files selected for processing (5)
  • src/main/java/org/example/team6backend/document/controller/DocumentController.java
  • src/main/java/org/example/team6backend/document/repository/DocumentRepository.java
  • src/main/java/org/example/team6backend/document/service/DocumentService.java
  • src/main/resources/static/viewincident.html
  • src/test/java/org/example/team6backend/document/controller/DocumentControllerTest.java

Comment thread src/main/java/org/example/team6backend/document/service/DocumentService.java Outdated
Comment thread src/main/resources/static/viewincident.html Outdated
Comment thread src/main/resources/static/viewincident.html Outdated
…ent race conditions

-improve MinIO download handling to avoid deleting DB records on transient failures

-only remove document records when file is confirmed missing in MinIO (NoSuchKey)

-return proper 500 response for temporary MinIO errors instead of false 404 cleanup

-improve logging for missing and failed file downloads
@SandraNelj
SandraNelj merged commit 03b2e74 into main Apr 24, 2026
3 checks passed
@SandraNelj
SandraNelj deleted the fix/removebrokenimages branch April 24, 2026 07:29
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