1
2
3
4
5
6
7 package org.tailormap.api.controller;
8
9 import static org.springframework.http.HttpStatus.BAD_REQUEST;
10 import static org.springframework.http.HttpStatus.NOT_FOUND;
11 import static org.springframework.http.HttpStatus.NOT_MODIFIED;
12
13 import jakarta.servlet.http.HttpServletRequest;
14 import java.util.UUID;
15 import org.springframework.http.CacheControl;
16 import org.springframework.http.ResponseEntity;
17 import org.springframework.web.bind.annotation.GetMapping;
18 import org.springframework.web.bind.annotation.PathVariable;
19 import org.springframework.web.bind.annotation.RestController;
20 import org.springframework.web.server.ResponseStatusException;
21 import org.tailormap.api.persistence.Upload;
22 import org.tailormap.api.persistence.UploadCategory;
23 import org.tailormap.api.repository.UploadRepository;
24 import org.tailormap.api.service.UploadsService;
25
26 @RestController
27 public class UploadsController {
28 private final UploadRepository uploadRepository;
29 private final UploadsService uploadsService;
30
31 public UploadsController(UploadRepository uploadRepository, UploadsService uploadsService) {
32 this.uploadRepository = uploadRepository;
33 this.uploadsService = uploadsService;
34 }
35
36 @GetMapping(
37 path = {
38
39
40 "/api/uploads/{category}/{id}",
41 "/api/uploads/{category}/{id}/{filename}"
42 })
43 public ResponseEntity<byte[]> getUpload(
44 HttpServletRequest request,
45 @PathVariable UploadCategory category,
46 @PathVariable(name = "id") UUID id,
47 @PathVariable(required = false) String filename) {
48
49 if (UploadCategory.getRestrictedCategories().contains(category)) {
50 throw new ResponseStatusException(
51 BAD_REQUEST, "Uploads for category " + category + " are not accessible via this endpoint");
52 }
53
54 long ifModifiedSince = request.getDateHeader("If-Modified-Since");
55
56 if (!uploadsService.checkIfModifiedSince(id, ifModifiedSince)) {
57 return ResponseEntity.status(NOT_MODIFIED).build();
58 }
59
60 Upload upload = uploadRepository
61 .findWithContentByIdAndCategory(id, category)
62 .orElseThrow(() -> new ResponseStatusException(NOT_FOUND));
63
64 return ResponseEntity.ok()
65 .header("Content-Type", upload.getMimeType())
66 .header(UploadsService.DESCRIPTION_HEADER_NAME, upload.getDescription())
67 .lastModified(upload.getLastModified().toInstant())
68 .contentLength(upload.getContentLength())
69 .cacheControl(CacheControl.noCache().cachePublic())
70 .body(upload.getContent());
71 }
72
73
74
75
76
77 @GetMapping("/api/uploads/{category}/latest")
78 public ResponseEntity<byte[]> getLatestUpload(@PathVariable UploadCategory category) {
79 if (UploadCategory.getRestrictedCategories().contains(category)) {
80 throw new ResponseStatusException(
81 BAD_REQUEST, "Uploads for category " + category + " are not accessible via this endpoint");
82 }
83 return uploadRepository
84 .findFirstWithContentByCategoryOrderByLastModifiedDesc(category)
85 .map(upload -> ResponseEntity.ok()
86 .header("Content-Type", upload.getMimeType())
87 .header(UploadsService.DESCRIPTION_HEADER_NAME, upload.getDescription())
88 .lastModified(upload.getLastModified().toInstant())
89 .contentLength(upload.getContentLength())
90 .cacheControl(CacheControl.noCache().cachePublic())
91 .body(upload.getContent()))
92 .orElseThrow(() -> new ResponseStatusException(NOT_FOUND));
93 }
94 }