Skip to content

Commit

Permalink
Lectures: Use attachment name for file downloads (#9775)
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonEntholzer authored Nov 16, 2024
1 parent 0db5cc1 commit 0ffa44f
Showing 1 changed file with 31 additions and 19 deletions.
50 changes: 31 additions & 19 deletions src/main/java/de/tum/cit/aet/artemis/core/web/FileResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ public ResponseEntity<byte[]> getMarkdownFileForConversation(@PathVariable Long
public ResponseEntity<byte[]> getMarkdownFile(@PathVariable String filename) {
log.debug("REST request to get file : {}", filename);
sanitizeFilenameElseThrow(filename);
return buildFileResponse(FilePathService.getMarkdownFilePath(), filename);
return buildFileResponse(FilePathService.getMarkdownFilePath(), filename, false);
}

/**
Expand Down Expand Up @@ -431,7 +431,7 @@ public ResponseEntity<byte[]> getLectureAttachment(@PathVariable Long lectureId,
// check if the user is authorized to access the requested attachment unit
checkAttachmentAuthorizationOrThrow(course, attachment);

return buildFileResponse(getActualPathFromPublicPathString(attachment.getLink()), false);
return buildFileResponse(getActualPathFromPublicPathString(attachment.getLink()), Optional.of(attachment.getName()));
}

/**
Expand Down Expand Up @@ -470,13 +470,13 @@ public ResponseEntity<byte[]> getLecturePdfAttachmentsMerged(@PathVariable Long

/**
* GET files/attachments/attachment-unit/:attachmentUnitId/:filename : Get the lecture unit attachment
* Accesses to this endpoint are created by the server itself in the FilePathService
*
* @param attachmentUnitId ID of the attachment unit, the attachment belongs to
* @return The requested file, 403 if the logged-in user is not allowed to access it, or 404 if the file doesn't exist
*/
@GetMapping("files/attachments/attachment-unit/{attachmentUnitId}/*")
@EnforceAtLeastStudent
// TODO: this method is kind of redundant to the method getAttachmentFile below, double check if both are actually needed
public ResponseEntity<byte[]> getAttachmentUnitAttachment(@PathVariable Long attachmentUnitId) {
log.debug("REST request to get the file for attachment unit {} for students", attachmentUnitId);
AttachmentUnit attachmentUnit = attachmentUnitRepository.findByIdElseThrow(attachmentUnitId);
Expand All @@ -487,8 +487,7 @@ public ResponseEntity<byte[]> getAttachmentUnitAttachment(@PathVariable Long att

// check if the user is authorized to access the requested attachment unit
checkAttachmentAuthorizationOrThrow(course, attachment);

return buildFileResponse(getActualPathFromPublicPathString(attachment.getLink()), false);
return buildFileResponse(getActualPathFromPublicPathString(attachment.getLink()), Optional.of(attachment.getName()));
}

/**
Expand Down Expand Up @@ -567,36 +566,49 @@ public ResponseEntity<byte[]> getAttachmentUnitAttachmentSlide(@PathVariable Lon
}

/**
* Builds the response with headers, body and content type for specified path and file name
* Builds the response with headers, body and content type for specified path containing the file name
*
* @param path to the file
* @param filename the name of the file
* @param path to the file including the file name
* @param cache true if the response should contain a header that allows caching; false otherwise
* @return response entity
*/
private ResponseEntity<byte[]> buildFileResponse(Path path, String filename) {
return buildFileResponse(path, filename, false);
private ResponseEntity<byte[]> buildFileResponse(Path path, boolean cache) {
return buildFileResponse(path.getParent(), path.getFileName().toString(), Optional.empty(), cache);
}

/**
* Builds the response with headers, body and content type for specified path containing the file name
*
* @param path to the file including the file name
* @param cache true if the response should contain a header that allows caching; false otherwise
* @param path to the file including the file name
* @param filename the name of the file
* @param cache true if the response should contain a header that allows caching; false otherwise
* @return response entity
*/
private ResponseEntity<byte[]> buildFileResponse(Path path, boolean cache) {
return buildFileResponse(path.getParent(), path.getFileName().toString(), cache);
private ResponseEntity<byte[]> buildFileResponse(Path path, String filename, boolean cache) {
return buildFileResponse(path, filename, Optional.empty(), cache);
}

/**
* Builds the response with headers, body and content type for specified path and file name
*
* @param path to the file
* @param filename the name of the file
* @param cache true if the response should contain a header that allows caching; false otherwise
* @param path to the file
* @param replaceFilename replaces the downloaded file's name, if provided
* @return response entity
*/
private ResponseEntity<byte[]> buildFileResponse(Path path, String filename, boolean cache) {
private ResponseEntity<byte[]> buildFileResponse(Path path, Optional<String> replaceFilename) {
return buildFileResponse(path.getParent(), path.getFileName().toString(), replaceFilename, false);
}

/**
* Builds the response with headers, body and content type for specified path and file name
*
* @param path to the file
* @param filename the name of the file
* @param replaceFilename replaces the downloaded file's name, if provided
* @param cache true if the response should contain a header that allows caching; false otherwise
* @return response entity
*/
private ResponseEntity<byte[]> buildFileResponse(Path path, String filename, Optional<String> replaceFilename, boolean cache) {
try {
Path actualPath = path.resolve(filename);
byte[] file = fileService.getFileForPath(actualPath);
Expand All @@ -611,7 +623,7 @@ private ResponseEntity<byte[]> buildFileResponse(Path path, String filename, boo
String contentType = lowerCaseFilename.endsWith("htm") || lowerCaseFilename.endsWith("html") || lowerCaseFilename.endsWith("svg") || lowerCaseFilename.endsWith("svgz")
? "attachment"
: "inline";
headers.setContentDisposition(ContentDisposition.builder(contentType).filename(filename).build());
headers.setContentDisposition(ContentDisposition.builder(contentType).filename(replaceFilename.orElse(filename)).build());

var response = ResponseEntity.ok().headers(headers).contentType(getMediaTypeFromFilename(filename)).header("filename", filename);
if (cache) {
Expand Down

0 comments on commit 0ffa44f

Please sign in to comment.