Feature/open file in UI#66
Conversation
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the 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 configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds an inline file preview flow: a new preview streaming endpoint, a fragment endpoint that returns an iframe, UI buttons and client-side toggle to load/unload the iframe, and a same-origin frame security header; download/preview media-type parsing is made resilient to invalid media type strings. Changes
Sequence Diagram(s)sequenceDiagram
participant User as Client (browser)
participant UI as Case file list (JS)
participant ViewCtrl as CaseFileViewController
participant IFrame as Browser iframe
participant PreviewCtrl as CaseFileController
participant Storage as File storage
User->>UI: click "Preview" button
UI->>ViewCtrl: GET /dashboard/.../preview-frame (fetch fragment)
ViewCtrl-->>UI: 200 HTML fragment (iframe src=.../preview)
UI-->>UI: insert fragment into DOM (iframe added)
IFrame->>PreviewCtrl: GET /api/cases/{caseId}/files/{fileId}/preview (navigation)
PreviewCtrl->>Storage: retrieve file bytes & metadata
PreviewCtrl-->>IFrame: 200 StreamingResponseBody (Content-Type, Content-Disposition:inline)
IFrame-->>User: browser renders streamed content inline
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (4)
src/main/resources/templates/fragments/case-management/case-file-list.html (1)
81-95: DuplicatetogglePreviewfunction exists inadmin-meetings.html.This function is nearly identical to the one in
admin-meetings.html(lines 359-372), differing only in the parent selector (.case-file-itemvs.agenda-document-row). Consider extracting to a shared JavaScript file with a configurable selector parameter.♻️ Example shared utility
// In a shared JS file, e.g., /js/file-preview.js function togglePreview(btn, parentSelector) { const item = btn.closest(parentSelector); const existing = item.querySelector('.file-preview-frame'); if (existing) { existing.remove(); return; } const url = btn.getAttribute('data-preview-url'); fetch(url) .then(res => { if (!res.ok) throw new Error('Preview failed'); return res.text(); }) .then(html => { item.insertAdjacentHTML('beforeend', html); }) .catch(err => console.error('Failed to load preview:', err)); }Then call with:
onclick="togglePreview(this, '.case-file-item')"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/resources/templates/fragments/case-management/case-file-list.html` around lines 81 - 95, Duplicate togglePreview implementations exist (one in this file and another in admin-meetings.html); extract to a shared JS utility (e.g., /js/file-preview.js) as a single function togglePreview(btn, parentSelector) that uses btn.closest(parentSelector), looks for '.file-preview-frame', reads 'data-preview-url', checks response.ok, handles fetch errors, and inserts the HTML; then replace the inline functions and update calls to onclick="togglePreview(this, '.case-file-item')" and onclick="togglePreview(this, '.agenda-document-row')" respectively.src/main/java/backendlab/team4you/casefile/ui/CaseFileViewController.java (1)
40-49: Consider adding authorization check for consistency.This endpoint serves the preview frame without verifying whether the user has permission to view the file. While the actual file content is protected by the
/api/cases/.../previewendpoint (which does check authorization), adding a check here would:
- Provide consistent authorization behavior across endpoints
- Fail fast with a proper error instead of rendering an iframe that will fail to load
- Prevent potential enumeration of valid caseId/fileId combinations
🛡️ Suggested authorization check
`@GetMapping`("/case-records/{caseId}/files/{fileId}/preview-frame") public String previewFrame( `@PathVariable` Long caseId, `@PathVariable` Long fileId, - Model model + Model model, + Principal principal ) { + UserEntity currentUser = userService.getCurrentUser(principal); + // Verify user can view this file before rendering the frame + caseFileService.getCaseFileForViewer(caseId, fileId, currentUser); + model.addAttribute("caseId", caseId); model.addAttribute("fileId", fileId); return "fragments/case-management/file-preview-frame :: frame"; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/backendlab/team4you/casefile/ui/CaseFileViewController.java` around lines 40 - 49, The previewFrame method currently renders the iframe without permission checks; update previewFrame in CaseFileViewController to validate access before adding attributes by calling your authorization utility (e.g., CasePermissionService.canViewFile(caseId, fileId) or SecurityService.hasAccessToCaseFile) and, on failure, throw AccessDeniedException or return a 403/forbidden view; ensure you reference previewFrame and the chosen auth helper (CasePermissionService or SecurityService) so the endpoint fails fast and prevents rendering the iframe when the user is not authorized.src/main/java/backendlab/team4you/casefile/CaseFileController.java (1)
89-119: Consider extracting shared logic withdownloadFilemethod.The
previewFileanddownloadFilemethods share nearly identical code (authorization, media type parsing, streaming body construction). The only difference isContentDisposition.inline()vsContentDisposition.attachment(). Consider extracting a helper method to reduce duplication.♻️ Suggested refactoring
private ResponseEntity<StreamingResponseBody> streamFile( Long caseRecordId, Long fileId, Principal principal, boolean inline) { UserEntity currentUser = userService.getCurrentUser(principal); CaseFile caseFile = caseFileService.getCaseFileForViewer(caseRecordId, fileId, currentUser); MediaType mediaType = MediaType.APPLICATION_OCTET_STREAM; if (caseFile.getContentType() != null && !caseFile.getContentType().isBlank()) { mediaType = MediaType.parseMediaType(caseFile.getContentType()); } StreamingResponseBody body = outputStream -> { try (InputStream stream = caseFileService.downloadFile(caseRecordId, fileId, currentUser)) { stream.transferTo(outputStream); } }; ContentDisposition disposition = inline ? ContentDisposition.inline().filename(caseFile.getOriginalFilename(), StandardCharsets.UTF_8).build() : ContentDisposition.attachment().filename(caseFile.getOriginalFilename(), StandardCharsets.UTF_8).build(); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, disposition.toString()) .contentType(mediaType) .body(body); }Then simplify both endpoints:
`@GetMapping`("/{fileId}") public ResponseEntity<StreamingResponseBody> downloadFile(...) { return streamFile(caseRecordId, fileId, principal, false); } `@GetMapping`("/{fileId}/preview") public ResponseEntity<StreamingResponseBody> previewFile(...) { return streamFile(caseRecordId, fileId, principal, true); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/backendlab/team4you/casefile/CaseFileController.java` around lines 89 - 119, Extract the duplicated streaming/authorization logic from previewFile and downloadFile into a new private helper (e.g., streamFile) that accepts (Long caseRecordId, Long fileId, Principal principal, boolean inline); inside it call userService.getCurrentUser(principal) and caseFileService.getCaseFileForViewer(...), compute MediaType once (using MediaType.parseMediaType when contentType present), build the StreamingResponseBody by calling caseFileService.downloadFile(...). Use the inline flag to choose ContentDisposition.inline() vs ContentDisposition.attachment() with caseFile.getOriginalFilename() and return the ResponseEntity; then simplify previewFile and downloadFile to delegate to streamFile with inline=true/false.src/main/resources/templates/fragments/case-management/file-preview-frame.html (1)
1-8: Addsandboxattribute to the iframe for defense-in-depth.The iframe loads user-uploaded files of any type via the preview endpoint, which uses
ContentDisposition.inline()to display them directly. Since users can upload HTML files with embedded scripts, adding a sandbox would prevent script execution while maintaining functionality for PDFs, images, and other content.🛡️ Suggested security improvement
<div th:fragment="frame" class="file-preview-frame"> <iframe th:src="@{/api/cases/{caseId}/files/{fileId}/preview(caseId=${caseId}, fileId=${fileId})}" width="100%" height="600px" - style="border: none;"> + style="border: none;" + sandbox="allow-same-origin"> </iframe> </div>The
sandbox="allow-same-origin"attribute restricts the iframe's capabilities (disables scripts, forms, plugins, etc.) while preserving same-origin access needed for the preview endpoint requests.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/resources/templates/fragments/case-management/file-preview-frame.html` around lines 1 - 8, The iframe in the "frame" fragment (class file-preview-frame) renders user-uploaded content via the /api/cases/{caseId}/files/{fileId}/preview endpoint and currently allows script execution; add a sandbox attribute to the iframe element (e.g., sandbox="allow-same-origin") to disable scripts, forms and plugins while preserving same-origin access for the preview endpoint to mitigate XSS from uploaded HTML files.
🤖 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/backendlab/team4you/casefile/CaseFileController.java`:
- Around line 98-101: CaseFileController currently calls
MediaType.parseMediaType(...) (in the block that sets mediaType and also in
downloadFile) which can throw InvalidMediaTypeException; wrap those
parseMediaType calls in a try-catch that catches InvalidMediaTypeException, log
a warning (including the bad content type and caseFile id) and fall back to
MediaType.APPLICATION_OCTET_STREAM so malformed content types do not propagate
an exception.
In `@src/main/resources/templates/fragments/admin-meetings.html`:
- Around line 358-372: The togglePreview function performs a fetch without any
error handling or response status checks, so preview failures are silent; update
togglePreview (the function that queries .agenda-document-row and inserts
.file-preview-frame) to check response.ok and throw on non-2xx, add a .catch
handler on the promise chain to handle network/parse errors, and on error either
insert a small error message element into the item (e.g., a .file-preview-error
node) or display an alert so users get visible feedback when the preview fails
to load.
In `@src/main/resources/templates/fragments/case-management/case-file-list.html`:
- Around line 81-95: The fetch in function togglePreview lacks error handling;
update togglePreview to check response.ok after fetch(url) and throw or handle
non-2xx statuses, and add a .catch handler for network or parsing errors that
injects a visible error node into the .case-file-item (or uses alert) so users
get feedback; keep the existing logic that removes existing .file-preview-frame,
ensure you reference the data-preview-url attribute and existing
.file-preview-frame element when inserting the error message.
---
Nitpick comments:
In `@src/main/java/backendlab/team4you/casefile/CaseFileController.java`:
- Around line 89-119: Extract the duplicated streaming/authorization logic from
previewFile and downloadFile into a new private helper (e.g., streamFile) that
accepts (Long caseRecordId, Long fileId, Principal principal, boolean inline);
inside it call userService.getCurrentUser(principal) and
caseFileService.getCaseFileForViewer(...), compute MediaType once (using
MediaType.parseMediaType when contentType present), build the
StreamingResponseBody by calling caseFileService.downloadFile(...). Use the
inline flag to choose ContentDisposition.inline() vs
ContentDisposition.attachment() with caseFile.getOriginalFilename() and return
the ResponseEntity; then simplify previewFile and downloadFile to delegate to
streamFile with inline=true/false.
In `@src/main/java/backendlab/team4you/casefile/ui/CaseFileViewController.java`:
- Around line 40-49: The previewFrame method currently renders the iframe
without permission checks; update previewFrame in CaseFileViewController to
validate access before adding attributes by calling your authorization utility
(e.g., CasePermissionService.canViewFile(caseId, fileId) or
SecurityService.hasAccessToCaseFile) and, on failure, throw
AccessDeniedException or return a 403/forbidden view; ensure you reference
previewFrame and the chosen auth helper (CasePermissionService or
SecurityService) so the endpoint fails fast and prevents rendering the iframe
when the user is not authorized.
In `@src/main/resources/templates/fragments/case-management/case-file-list.html`:
- Around line 81-95: Duplicate togglePreview implementations exist (one in this
file and another in admin-meetings.html); extract to a shared JS utility (e.g.,
/js/file-preview.js) as a single function togglePreview(btn, parentSelector)
that uses btn.closest(parentSelector), looks for '.file-preview-frame', reads
'data-preview-url', checks response.ok, handles fetch errors, and inserts the
HTML; then replace the inline functions and update calls to
onclick="togglePreview(this, '.case-file-item')" and
onclick="togglePreview(this, '.agenda-document-row')" respectively.
In
`@src/main/resources/templates/fragments/case-management/file-preview-frame.html`:
- Around line 1-8: The iframe in the "frame" fragment (class file-preview-frame)
renders user-uploaded content via the /api/cases/{caseId}/files/{fileId}/preview
endpoint and currently allows script execution; add a sandbox attribute to the
iframe element (e.g., sandbox="allow-same-origin") to disable scripts, forms and
plugins while preserving same-origin access for the preview endpoint to mitigate
XSS from uploaded HTML files.
🪄 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: 4c34a111-adda-4419-b221-962f181b634c
📒 Files selected for processing (6)
src/main/java/backendlab/team4you/casefile/CaseFileController.javasrc/main/java/backendlab/team4you/casefile/ui/CaseFileViewController.javasrc/main/java/backendlab/team4you/config/SecurityConfig.javasrc/main/resources/templates/fragments/admin-meetings.htmlsrc/main/resources/templates/fragments/case-management/case-file-list.htmlsrc/main/resources/templates/fragments/case-management/file-preview-frame.html
| <script> | ||
| function togglePreview(btn) { | ||
| const item = btn.closest('.case-file-item'); | ||
| const existing = item.querySelector('.file-preview-frame'); | ||
| if (existing) { | ||
| existing.remove(); | ||
| return; | ||
| } | ||
| const url = btn.getAttribute('data-preview-url'); | ||
| fetch(url) | ||
| .then(res => res.text()) | ||
| .then(html => { | ||
| item.insertAdjacentHTML('beforeend', html); | ||
| }); | ||
| } |
There was a problem hiding this comment.
Add error handling for the fetch request.
The togglePreview function doesn't handle fetch failures. If the network request fails or returns an error status, users won't receive feedback.
🐛 Proposed fix with error handling
<script>
function togglePreview(btn) {
const item = btn.closest('.case-file-item');
const existing = item.querySelector('.file-preview-frame');
if (existing) {
existing.remove();
return;
}
const url = btn.getAttribute('data-preview-url');
fetch(url)
- .then(res => res.text())
+ .then(res => {
+ if (!res.ok) throw new Error('Preview failed');
+ return res.text();
+ })
.then(html => {
item.insertAdjacentHTML('beforeend', html);
+ })
+ .catch(err => {
+ console.error('Failed to load preview:', err);
});
}
</script>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <script> | |
| function togglePreview(btn) { | |
| const item = btn.closest('.case-file-item'); | |
| const existing = item.querySelector('.file-preview-frame'); | |
| if (existing) { | |
| existing.remove(); | |
| return; | |
| } | |
| const url = btn.getAttribute('data-preview-url'); | |
| fetch(url) | |
| .then(res => res.text()) | |
| .then(html => { | |
| item.insertAdjacentHTML('beforeend', html); | |
| }); | |
| } | |
| <script> | |
| function togglePreview(btn) { | |
| const item = btn.closest('.case-file-item'); | |
| const existing = item.querySelector('.file-preview-frame'); | |
| if (existing) { | |
| existing.remove(); | |
| return; | |
| } | |
| const url = btn.getAttribute('data-preview-url'); | |
| fetch(url) | |
| .then(res => { | |
| if (!res.ok) throw new Error('Preview failed'); | |
| return res.text(); | |
| }) | |
| .then(html => { | |
| item.insertAdjacentHTML('beforeend', html); | |
| }) | |
| .catch(err => { | |
| console.error('Failed to load preview:', err); | |
| }); | |
| } | |
| </script> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/main/resources/templates/fragments/case-management/case-file-list.html`
around lines 81 - 95, The fetch in function togglePreview lacks error handling;
update togglePreview to check response.ok after fetch(url) and throw or handle
non-2xx statuses, and add a .catch handler for network or parsing errors that
injects a visible error node into the .case-file-item (or uses alert) so users
get feedback; keep the existing logic that removes existing .file-preview-frame,
ensure you reference the data-preview-url attribute and existing
.file-preview-frame element when inserting the error message.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/main/java/backendlab/team4you/casefile/CaseFileController.java (1)
70-73:⚠️ Potential issue | 🟡 MinorDon’t swallow
InvalidMediaTypeExceptionsilently.Line 72 and Line 107 catch and ignore invalid content types with no trace. Please log a warning (include case file id + bad value) before falling back, so malformed metadata is diagnosable.
🔧 Suggested patch
+import org.slf4j.Logger; +import org.slf4j.LoggerFactory; ... public class CaseFileController { + private static final Logger log = LoggerFactory.getLogger(CaseFileController.class); ... if (caseFile.getContentType() != null && !caseFile.getContentType().isBlank()) { try { mediaType = MediaType.parseMediaType(caseFile.getContentType()); } catch (InvalidMediaTypeException e) { + log.warn("Invalid content type '{}' for caseFileId={}; fallback to application/octet-stream", + caseFile.getContentType(), caseFile.getId()); } } ... if (caseFile.getContentType() != null && !caseFile.getContentType().isBlank()) { try { mediaType = MediaType.parseMediaType(caseFile.getContentType()); } catch (InvalidMediaTypeException e) { + log.warn("Invalid content type '{}' for caseFileId={}; fallback to application/octet-stream", + caseFile.getContentType(), caseFile.getId()); } }#!/bin/bash # Verify empty InvalidMediaTypeException catches and logging presence. rg -nPU 'catch\s*\(\s*InvalidMediaTypeException\s+\w+\s*\)\s*\{\s*\}' src/main/java rg -nP 'InvalidMediaTypeException|LoggerFactory|log\.warn' src/main/java/backendlab/team4you/casefile/CaseFileController.javaAlso applies to: 105-108
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/backendlab/team4you/casefile/CaseFileController.java` around lines 70 - 73, The code swallows InvalidMediaTypeException in the MediaType.parseMediaType call; update the catch blocks around MediaType.parseMediaType(caseFile.getContentType()) to log a warning including the case file id (caseFile.getId() or caseFile.getCaseFileId()) and the malformed contentType value before falling back to a default MediaType; use the existing logger (LoggerFactory/LOGGER) and include the exception message/stacktrace in the log so both the bad value and the exception are recorded (apply the same change to both occurrences near parseMediaType).
🧹 Nitpick comments (1)
src/main/java/backendlab/team4you/casefile/CaseFileController.java (1)
59-92: Extract shared stream-response logic used by download + preview.
downloadFileandpreviewFileduplicate media-type parsing and stream body construction. Pull this into one private helper and parameterize disposition (attachmentvsinline) to reduce drift and keep security fixes centralized.♻️ Refactor sketch
+ private ResponseEntity<StreamingResponseBody> buildFileResponse( + Long caseRecordId, + Long fileId, + UserEntity currentUser, + boolean inline + ) { + CaseFile caseFile = caseFileService.getCaseFileForViewer(caseRecordId, fileId, currentUser); + MediaType mediaType = MediaType.APPLICATION_OCTET_STREAM; + if (caseFile.getContentType() != null && !caseFile.getContentType().isBlank()) { + try { + mediaType = MediaType.parseMediaType(caseFile.getContentType()); + } catch (InvalidMediaTypeException e) { + // log fallback + } + } + StreamingResponseBody body = outputStream -> { + try (InputStream stream = caseFileService.downloadFile(caseRecordId, fileId, currentUser)) { + stream.transferTo(outputStream); + } + }; + ContentDisposition disposition = (inline ? ContentDisposition.inline() : ContentDisposition.attachment()) + .filename(caseFile.getOriginalFilename(), StandardCharsets.UTF_8) + .build(); + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, disposition.toString()) + .contentType(mediaType) + .body(body); + }Also applies to: 94-127
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/backendlab/team4you/casefile/CaseFileController.java` around lines 59 - 92, Refactor duplicated media-type parsing and stream-response construction used by downloadFile and previewFile into a single private helper (e.g., buildStreamResponse or createStreamResponse) that accepts caseRecordId, fileId, Principal/UserEntity (or currentUser), and a disposition type parameter ("attachment" vs "inline"); move the MediaType parsing logic (using caseFile.getContentType() and MediaType.parseMediaType with InvalidMediaTypeException handling) and the StreamingResponseBody creation (calling caseFileService.downloadFile and transferTo) into that helper, and have downloadFile and previewFile call the helper to build the ResponseEntity with appropriate ContentDisposition (attachment or inline) while preserving filename encoding via StandardCharsets.UTF_8 and existing headers.
🤖 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/backendlab/team4you/casefile/CaseFileController.java`:
- Around line 94-127: The previewFile handler currently serves arbitrary
uploaded Content-Type inline; restrict inline rendering by implementing a strict
allowlist (e.g., "application/pdf", "image/*", "text/plain") when reading
caseFile.getContentType() inside previewFile in CaseFileController.java: if the
detected media type is not in the allowlist, change the response to force a
download (Content-Disposition: attachment with original filename) or return
415/403 per policy; always add the header "X-Content-Type-Options: nosniff" to
the ResponseEntity; ensure MediaType parsing still falls back safely and that
ContentDisposition.inline() is only used for allowed types.
---
Duplicate comments:
In `@src/main/java/backendlab/team4you/casefile/CaseFileController.java`:
- Around line 70-73: The code swallows InvalidMediaTypeException in the
MediaType.parseMediaType call; update the catch blocks around
MediaType.parseMediaType(caseFile.getContentType()) to log a warning including
the case file id (caseFile.getId() or caseFile.getCaseFileId()) and the
malformed contentType value before falling back to a default MediaType; use the
existing logger (LoggerFactory/LOGGER) and include the exception
message/stacktrace in the log so both the bad value and the exception are
recorded (apply the same change to both occurrences near parseMediaType).
---
Nitpick comments:
In `@src/main/java/backendlab/team4you/casefile/CaseFileController.java`:
- Around line 59-92: Refactor duplicated media-type parsing and stream-response
construction used by downloadFile and previewFile into a single private helper
(e.g., buildStreamResponse or createStreamResponse) that accepts caseRecordId,
fileId, Principal/UserEntity (or currentUser), and a disposition type parameter
("attachment" vs "inline"); move the MediaType parsing logic (using
caseFile.getContentType() and MediaType.parseMediaType with
InvalidMediaTypeException handling) and the StreamingResponseBody creation
(calling caseFileService.downloadFile and transferTo) into that helper, and have
downloadFile and previewFile call the helper to build the ResponseEntity with
appropriate ContentDisposition (attachment or inline) while preserving filename
encoding via StandardCharsets.UTF_8 and existing headers.
🪄 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: 09e0c251-7b7f-4585-9f6a-bef3edcf5131
📒 Files selected for processing (4)
src/main/java/backendlab/team4you/casefile/CaseFileController.javasrc/main/java/backendlab/team4you/config/SecurityConfig.javasrc/main/resources/templates/fragments/admin-meetings.htmlsrc/main/resources/templates/fragments/case-management/case-file-list.html
🚧 Files skipped from review as they are similar to previous changes (3)
- src/main/java/backendlab/team4you/config/SecurityConfig.java
- src/main/resources/templates/fragments/case-management/case-file-list.html
- src/main/resources/templates/fragments/admin-meetings.html
…tent types (stored-XSS risk).
Summary by CodeRabbit
New Features
Bug Fixes
Security