1   package org.imageconverter.controller;
2   
3   import static java.util.stream.Collectors.joining;
4   import static org.apache.commons.lang3.StringUtils.EMPTY;
5   import static org.imageconverter.util.controllers.imageconverter.ImageConverterConst.REST_URL;
6   import static org.springframework.http.HttpHeaders.CONTENT_DISPOSITION;
7   import static org.springframework.http.HttpStatus.CREATED;
8   import static org.springframework.http.HttpStatus.NO_CONTENT;
9   import static org.springframework.http.HttpStatus.OK;
10  import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
11  import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
12  
13  import java.io.ByteArrayInputStream;
14  import java.io.IOException;
15  import java.util.ArrayList;
16  import java.util.List;
17  import java.util.Optional;
18  
19  import javax.servlet.http.HttpServletRequest;
20  import javax.servlet.http.HttpServletResponse;
21  
22  import org.imageconverter.application.ImageConversionService;
23  import org.imageconverter.domain.conversion.ExecutionType;
24  import org.imageconverter.domain.conversion.ImageConversion;
25  import org.imageconverter.util.controllers.imageconverter.ImageConversionPostResponse;
26  import org.imageconverter.util.controllers.imageconverter.ImageConversionResponse;
27  import org.imageconverter.util.controllers.imageconverter.ImageConverterRequest;
28  import org.imageconverter.util.controllers.imageconverter.ImageConverterRequestArea;
29  import org.imageconverter.util.controllers.imageconverter.ImageConverterRequestInterface;
30  import org.imageconverter.util.logging.Loggable;
31  import org.imageconverter.util.openapi.imageconverter.ImageConverterRestGetByIdOpenApi;
32  import org.imageconverter.util.openapi.imageconverter.ImageConverterRestGetOpenApi;
33  import org.imageconverter.util.openapi.imageconverter.ImageConverterRestPostAreaOpenApi;
34  import org.imageconverter.util.openapi.imageconverter.ImageConverterRestPostOpenApi;
35  import org.imageconverter.util.openapi.imagetype.ImageTypeRestDeleteOpenApi;
36  import org.springdoc.core.converters.models.PageableAsQueryParam;
37  import org.springframework.context.annotation.Description;
38  import org.springframework.core.io.InputStreamResource;
39  import org.springframework.data.domain.Page;
40  import org.springframework.data.domain.Pageable;
41  import org.springframework.data.jpa.domain.Specification;
42  import org.springframework.data.web.PageableDefault;
43  import org.springframework.http.MediaType;
44  import org.springframework.http.ResponseEntity;
45  import org.springframework.web.bind.annotation.DeleteMapping;
46  import org.springframework.web.bind.annotation.GetMapping;
47  import org.springframework.web.bind.annotation.PathVariable;
48  import org.springframework.web.bind.annotation.PostMapping;
49  import org.springframework.web.bind.annotation.RequestMapping;
50  import org.springframework.web.bind.annotation.RequestParam;
51  import org.springframework.web.bind.annotation.RequestPart;
52  import org.springframework.web.bind.annotation.ResponseStatus;
53  import org.springframework.web.bind.annotation.RestController;
54  import org.springframework.web.multipart.MultipartFile;
55  
56  import com.turkraft.springfilter.boot.Filter;
57  
58  import io.swagger.v3.oas.annotations.Parameter;
59  import io.swagger.v3.oas.annotations.media.Content;
60  import io.swagger.v3.oas.annotations.security.SecurityRequirement;
61  import io.swagger.v3.oas.annotations.tags.Tag;
62  
63  
64  
65  
66  
67  
68  @SecurityRequirement(name = "BASIC")
69  @Tag( 
70  		name = "Image Convert", 
71  		description = """
72  				Image Convert API - If something went wrong, please put 'trace' (for all Http methods)
73  				at the end of the call to receive the stackStrace.
74  				Ex: http:
75  				     """ 
76  )
77  
78  @Loggable
79  @RestController
80  @Description("Controller for image converstion API")
81  @RequestMapping(REST_URL)
82  public class ImageConversionRestController {
83  
84      private final ImageConversionService imageConversionService;
85  
86      
87  
88  
89  
90  
91      ImageConversionRestController(final ImageConversionService imageConversionService) {
92  	super();
93  	this.imageConversionService = imageConversionService;
94      }
95  
96      
97  
98  
99  
100 
101 
102 
103     @ImageConverterRestGetByIdOpenApi
104     
105     @ResponseStatus(OK)
106     @GetMapping(value = "/{id:[\\d]*}", produces = APPLICATION_JSON_VALUE)
107     public ImageConversionResponse getById( 
108 		    @Parameter(name = "id", description = "The image conversion id's", required = true, example = "3") 
109 		    @PathVariable(name = "id", required = true) 
110 		    final Long id) {
111 
112 	return imageConversionService.findById(id);
113     }
114 
115     
116 
117 
118 
119 
120 
121 
122     @PageableAsQueryParam
123     @ImageConverterRestGetOpenApi
124     
125     @ResponseStatus(OK)
126     @GetMapping(produces = APPLICATION_JSON_VALUE)
127     public Page<ImageConversionResponse> getByFilter( 
128 		    @Parameter(name = "filter", description = "Search's filter", required = true, example = "?filter=fileName:'image.png'") 
129 		    @Filter 
130 		    final Specification<ImageConversion> filter, 
131 		    
132 		    @PageableDefault(value = 10, page = 0) 
133 		    final Pageable page) {
134 
135 	return imageConversionService.findBySpecification(filter, page);
136     }
137 
138     
139 
140 
141 
142 
143 
144     @ImageConverterRestPostOpenApi
145     
146     @ResponseStatus(CREATED)
147     @PostMapping(consumes = { MULTIPART_FORM_DATA_VALUE }, produces = APPLICATION_JSON_VALUE)
148     public ImageConversionPostResponse convert( 
149 		    @Parameter(description = "The Image to be uploaded", content = @Content(mediaType = MULTIPART_FORM_DATA_VALUE), required = true, example = "image.bmp") 
150 		    @RequestPart(name = "file", required = true) 
151 		    final MultipartFile file,
152 		    
153 		    final HttpServletRequest request, final HttpServletResponse response) {
154 
155 	final var bytes = extractBytes(file);
156 
157 	final var executionType = extractExecutionType(request);
158 
159 	final var result = imageConversionService.convert(new ImageConverterRequest(file.getOriginalFilename(), bytes, executionType));
160 
161 	response.addHeader("Location", REST_URL + "/" + result.id());
162 
163 	return new ImageConversionPostResponse(result.text());
164     }
165 
166     
167 
168 
169 
170 
171 
172 
173 
174 
175 
176     @ImageConverterRestPostAreaOpenApi
177     
178     @ResponseStatus(CREATED)
179     @PostMapping(value = "/area", consumes = { MULTIPART_FORM_DATA_VALUE }, produces = APPLICATION_JSON_VALUE)
180     public ImageConversionPostResponse convertWithArea( 
181 		    @Parameter(description = "The Image to be uploaded", content = @Content(mediaType = MULTIPART_FORM_DATA_VALUE), required = true, example = "image.bmp") 
182 		    @RequestPart(name = "file", required = true) 
183 		    final MultipartFile file, 
184 		    
185 		    @Parameter(description = "The vertical position", required = true, example = "3") 
186 		    @RequestParam(required = true) 
187 		    final Integer xAxis, 
188 		    
189 		    @Parameter(description = "The horizontal position", required = true, example = "4") 
190 		    @RequestParam(required = true) 
191 		    final Integer yAxis, 
192 		    
193 		    @Parameter(description = "The width size's area", required = true, example = "56") 
194 		    @RequestParam(required = true) 
195 		    final Integer width, 
196 		    
197 		    @Parameter(description = "The height's size area ", required = true, example = "345") 
198 		    @RequestParam(required = true) 
199 		    final Integer height,
200 		    
201 		    final HttpServletRequest request, final HttpServletResponse response) {
202 
203 	final var executionType = extractExecutionType(request);
204 
205 	final byte[] bytes = extractBytes(file);
206 
207 	final var result = imageConversionService.convert(new ImageConverterRequestArea(file.getOriginalFilename(), bytes, executionType, xAxis, yAxis, width, height));
208 
209 	response.addHeader("Location", REST_URL + "/" + result.id());
210 
211 	return new ImageConversionPostResponse(result.text());
212     }
213 
214     
215 
216 
217 
218 
219 
220     @ImageConverterRestPostOpenApi
221     
222     @ResponseStatus(CREATED)
223     @PostMapping(value = "/multiple", consumes = { MULTIPART_FORM_DATA_VALUE }, produces = APPLICATION_JSON_VALUE)
224     public List<ImageConversionPostResponse> convert( 
225 		    @Parameter(description = "The Images to be uploaded", content = @Content(mediaType = MULTIPART_FORM_DATA_VALUE), required = true, example = "image1.bmp, image2.png") 
226 		    @RequestPart(name = "files", required = true) 
227 		    final MultipartFile[] files, 
228 		    
229 		    final HttpServletRequest request, 
230 		    final HttpServletResponse response) {
231 
232 	final var executionType = extractExecutionType(request);
233 
234 	final var listRequest = new ArrayList<ImageConverterRequestInterface>();
235 
236 	for (final var file : files) {
237 	    listRequest.add(new ImageConverterRequest(file.getOriginalFilename(), extractBytes(file), executionType));
238 	}
239 
240 	final var result = imageConversionService.convert(listRequest);
241 
242 	response.addHeader("Location", result.stream().map(rst -> REST_URL + "/" + rst.id()).collect(joining(";")));
243 
244 	return result.stream().map(rst -> new ImageConversionPostResponse(rst.text())).toList();
245     }
246 
247     
248 
249 
250 
251 
252     @ImageTypeRestDeleteOpenApi
253     
254     @ResponseStatus(NO_CONTENT)
255     @DeleteMapping("/{id:[\\d]*}")
256     public void delete( 
257 		    
258 		    @Parameter(description = "The conversion id's", example = "1000") 
259 		    @PathVariable(name = "id", required = true) 
260 		    final Long id) {
261 
262 	imageConversionService.deleteImageConversion(id);
263     }
264     
265     
266     
267 
268 
269 
270 
271 
272     @ResponseStatus(OK)
273     @GetMapping(value = "/export", produces = "txt/csv")
274     public ResponseEntity<InputStreamResource> downloadImageConversionCsv( 
275 		    @Parameter(name = "filter", description = "Search's filter", required = true, example = "?filter=fileName:'image.png'") 
276 		    @Filter 
277 		    final Specification<ImageConversion> filter ) {
278 	
279 	final var bytes = imageConversionService.findBySpecificationToCsv(filter);
280 	
281 	final var body = new InputStreamResource(new ByteArrayInputStream(bytes));
282 	
283 	return ResponseEntity.ok()
284 			.header(CONTENT_DISPOSITION, "attachment; filename=convertions.csv")
285 			.contentType(MediaType.parseMediaType("txt/csv"))
286 			.body(body);
287     }
288     
289 
290     private byte[] extractBytes(final MultipartFile file) {
291 	byte[] bytes;
292 	try {
293 	    bytes = file.getBytes();
294 	} catch (final IOException e) {
295 	    bytes = new byte[0];
296 	}
297 	return bytes;
298     }
299 
300     private ExecutionType extractExecutionType(final HttpServletRequest request) {
301 	final var executionTypeHeader = Optional.ofNullable(request.getHeader("Execution-Type")).orElse(EMPTY);
302 
303 	return ExecutionType.from(executionTypeHeader);
304     }
305 }