1
2
3
4
5
6 package org.tailormap.api.service;
7
8 import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
9 import static org.springframework.http.HttpHeaders.CONTENT_DISPOSITION;
10
11 import java.time.temporal.ChronoField;
12 import java.util.UUID;
13 import java.util.regex.Pattern;
14 import org.springframework.http.CacheControl;
15 import org.springframework.http.ContentDisposition;
16 import org.springframework.http.ResponseEntity;
17 import org.springframework.stereotype.Service;
18 import org.tailormap.api.controller.LayerAttachedUploadsController;
19 import org.tailormap.api.controller.UploadsController;
20 import org.tailormap.api.persistence.Application;
21 import org.tailormap.api.persistence.Upload;
22 import org.tailormap.api.persistence.UploadCategory;
23 import org.tailormap.api.repository.UploadRepository;
24
25 @Service
26 public class UploadsService {
27 private final UploadRepository uploadRepository;
28 public static final String DESCRIPTION_HEADER_NAME = "TM-Description";
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 public boolean checkIfModifiedSince(UUID id, long ifModifiedSince) {
48 if (ifModifiedSince == -1) {
49 return true;
50 }
51
52 return uploadRepository
53 .findLastModifiedById(id)
54 .map(uploadLastModified -> ifModifiedSince
55 < uploadLastModified
56 .with(ChronoField.MILLI_OF_SECOND, 0)
57 .toInstant()
58 .toEpochMilli())
59 .orElse(true);
60 }
61
62 public String getUrlForImage(String imageId, UploadCategory category) {
63 if (imageId == null) {
64 return null;
65 }
66 try {
67 UUID uuid = UUID.fromString(imageId);
68 return getUrlForImage(uuid, category);
69 } catch (IllegalArgumentException e) {
70
71 return null;
72 }
73 }
74
75 public String getUrlForImage(UUID imageId, UploadCategory category) {
76 if (imageId == null) {
77 return null;
78 }
79 if (category.isRestricted()) {
80 throw new IllegalArgumentException(
81 "Access to restricted category is not allowed without application and layer context");
82 }
83 return uploadRepository
84 .findByIdAndCategory(imageId, category)
85 .map(upload -> linkTo(UploadsController.class)
86 .slash("api")
87 .slash("uploads")
88 .slash(category)
89 .slash(imageId.toString())
90 .slash(upload.getFilename())
91 .toString())
92 .orElse(null);
93 }
94
95
96
97
98
99
100
101
102
103
104 public String getUrlForLayerAttachedImage(
105 UUID imageId, UploadCategory category, Application application, String layerId) {
106 if (imageId == null) {
107 return null;
108 }
109 if (category.isRestricted()) {
110 return uploadRepository
111 .findByIdAndCategory(imageId, category)
112 .map(upload -> linkTo(LayerAttachedUploadsController.class)
113 .slash("api")
114 .slash("app")
115 .slash(application.getName())
116 .slash("layer")
117 .slash(layerId)
118 .slash("uploads")
119 .slash(category)
120 .slash(imageId.toString())
121 .slash(upload.getFilename())
122 .toString())
123 .orElse(null);
124 } else {
125 return getUrlForImage(imageId, category);
126 }
127 }
128
129 public String replaceUploadLinks(Application application, String appLayerId, String description) {
130 if (description == null) {
131 return null;
132 }
133
134 return UPLOAD_REPLACE_PATTERN.matcher(description).replaceAll(matchResult -> {
135 try {
136 UUID uploadId = UUID.fromString(matchResult.group(1));
137 Upload upload = uploadRepository.findById(uploadId).orElse(null);
138 if (upload == null) {
139 return "";
140 }
141 return linkTo(LayerAttachedUploadsController.class)
142 .slash("api")
143 .slash("app")
144 .slash(application.getName())
145 .slash("layer")
146 .slash(appLayerId)
147 .slash("uploads")
148 .slash(upload.getCategory().toString())
149 .slash(uploadId.toString())
150 .slash(upload.getFilename())
151 .toString();
152 } catch (Exception _ignored) {
153 return "";
154 }
155 });
156 }
157
158 public static ResponseEntity<byte[]> createUploadResponseEntity(Upload upload) {
159 return ResponseEntity.ok()
160 .header("Content-Type", upload.getMimeType())
161 .header(UploadsService.DESCRIPTION_HEADER_NAME, upload.getDescription())
162 .header(
163 CONTENT_DISPOSITION,
164 ContentDisposition.inline()
165 .filename(upload.getFilename())
166 .build()
167 .toString())
168 .lastModified(upload.getLastModified().toInstant())
169 .contentLength(upload.getContentLength())
170 .cacheControl(CacheControl.noCache().cachePublic())
171 .body(upload.getContent());
172 }
173 }