CELDEV-1304 - add PageAttachmentController as backend for PageAttachments app script#291
CELDEV-1304 - add PageAttachmentController as backend for PageAttachments app script#291fpichler wants to merge 2 commits into
Conversation
ac67a3d to
4da789d
Compare
| org.springframework.web.bind.MissingServletRequestParameterException.class, | ||
| org.springframework.web.multipart.support.MissingServletRequestPartException.class |
There was a problem hiding this comment.
please import classes (already commented this issue in recent PR's)
| if (request instanceof org.springframework.web.multipart.MultipartHttpServletRequest) { | ||
| org.springframework.web.multipart.MultipartHttpServletRequest multipartRequest = | ||
| (org.springframework.web.multipart.MultipartHttpServletRequest) request; |
There was a problem hiding this comment.
| if (request instanceof org.springframework.web.multipart.MultipartHttpServletRequest) { | |
| org.springframework.web.multipart.MultipartHttpServletRequest multipartRequest = | |
| (org.springframework.web.multipart.MultipartHttpServletRequest) request; | |
| if (request instanceof MultipartHttpServletRequest multipartRequest) { |
use modern language features, possible since java 16 and we moved to 21
| import com.xpn.xwiki.doc.XWikiDocument; | ||
|
|
||
| @RestController | ||
| @RestControllerAdvice |
There was a problem hiding this comment.
| @RestControllerAdvice |
this annotation looks wrong to me. it makes the @ExceptionHandler methods global REST advice, not local to the controller. same paplies to MediaLibController, i think the @RestControllerAdvice should also be removed there.
if these handlers are only for this endpoint @RestController is enough, otherwise the shared error handling should be moved to a dedicated class.
| private String normalizeDirPath(String spaceName, String docName, String path) { | ||
| String expectedPrefix = STORAGE + "://" + spaceName + "/" + docName; | ||
| String p = StringUtils.hasText(path) ? path.trim() : expectedPrefix; | ||
| if (!p.startsWith(STORAGE + "://")) { | ||
| p = expectedPrefix + "/" + p; | ||
| } | ||
| if (p.endsWith("/") && !p.equals(expectedPrefix)) { | ||
| p = p.substring(0, p.length() - 1); | ||
| } | ||
| return p; | ||
| } | ||
|
|
||
| String normalizeFileName(String path) { | ||
| String p = StringUtils.hasText(path) ? path.trim() : ""; | ||
| int lastSlash = p.lastIndexOf('/'); | ||
| if (lastSlash >= 0) { | ||
| return p.substring(lastSlash + 1); | ||
| } | ||
| return p; | ||
| } | ||
|
|
||
| private FileItem toFileItem(String dirPath, XWikiAttachment att) { | ||
| String name = att.getFilename(); | ||
| AttachmentReference attachmentRef = RefBuilder.from(att.getDoc().getDocumentReference()) | ||
| .att(name).build(AttachmentReference.class); | ||
| String query = "celwidth=" + MAX_WIDTH + "&celheight=" + MAX_HEIGHT; | ||
| return new FileItem( | ||
| dirPath, | ||
| name, | ||
| extensionOf(name), | ||
| dirPath.endsWith("/") ? (dirPath + name) : (dirPath + "/" + name), | ||
| urlService.getURL(attachmentRef, "download"), | ||
| urlService.getURL(attachmentRef, "download", query), | ||
| STORAGE, | ||
| "file", | ||
| (long) att.getFilesize(), | ||
| toUnixSeconds(att.getDate()), | ||
| guessMimeType(name), | ||
| "public"); | ||
| } | ||
|
|
||
| private String guessMimeType(String filename) { | ||
| String mime = URLConnection.guessContentTypeFromName(filename); | ||
| return (mime != null) ? mime : "application/octet-stream"; | ||
| } | ||
|
|
||
| private String extensionOf(String name) { | ||
| int i = name.lastIndexOf('.'); | ||
| return ((i > 0) && (i < (name.length() - 1))) ? name.substring(i + 1).toLowerCase(Locale.ROOT) | ||
| : ""; | ||
| } | ||
|
|
||
| private long toUnixSeconds(Date date) { | ||
| if (date == null) { | ||
| return Instant.now().getEpochSecond(); | ||
| } | ||
| return date.toInstant().getEpochSecond(); | ||
| } |
There was a problem hiding this comment.
DRY, this duplicates quite a bit of MediaLibController behavior. can you extract the shared parts?
| java.util.Enumeration<String> headerNames = request.getHeaderNames(); | ||
| while (headerNames.hasMoreElements()) { | ||
| String headerName = headerNames.nextElement(); | ||
| LOGGER.warn("Header {}: {}", headerName, request.getHeader(headerName)); |
There was a problem hiding this comment.
logging all request headers is risky because it can expose credentials or session data. this looks like temporary debugging code, can we remove it or at least avoid logging raw headers?
Summary
Adds the backend controller for the new Page Attachments app.
This introduces
/attachments/{spaceName}/{docName}endpoints for listing, searching, uploading, and deleting attachments on a specific page, with authentication, document reference resolution, path normalization, and per-action rights checks.Details
PageAttachmentsControllerfor the Page Attachments VueFinder backend.AttachmentRequest,DeleteRequest, andDeleteItem.