You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

438 lines
16 KiB

  1. /*******************************************************************************
  2. * Copyright 2Fi Business Solutions Ltd.
  3. *
  4. * This code is copyrighted. Under no circumstances should any party, people,
  5. * or organization should redistribute any portions of this code in any form,
  6. * either verbatim or through electronic media, to any third parties, unless
  7. * under explicit written permission by 2Fi Business Solutions Ltd.
  8. ******************************************************************************/
  9. package com.ffii.tbms.api.web;
  10. import java.awt.image.BufferedImage;
  11. import java.io.ByteArrayInputStream;
  12. import java.io.ByteArrayOutputStream;
  13. import java.io.IOException;
  14. import java.util.Date;
  15. import java.util.HashMap;
  16. import java.util.List;
  17. import java.util.Map;
  18. import javax.imageio.ImageIO;
  19. import javax.servlet.ServletOutputStream;
  20. import javax.servlet.http.HttpServletRequest;
  21. import javax.servlet.http.HttpServletResponse;
  22. import com.fasterxml.jackson.databind.ObjectMapper;
  23. import com.ffii.core.setting.service.SettingsService;
  24. import com.ffii.core.utils.FileUtils;
  25. import com.ffii.core.utils.MapUtils;
  26. import com.ffii.core.utils.NumberUtils;
  27. import com.ffii.core.utils.Params;
  28. import com.ffii.core.utils.StringUtils;
  29. import com.ffii.core.utils.web.ServletRequestUtils;
  30. import com.ffii.core.web.AbstractController;
  31. import com.ffii.core.web.view.AbstractView;
  32. import com.ffii.core.web.view.json.JsonView;
  33. import com.ffii.tbms.api.service.AuthenticationService;
  34. import com.ffii.tbms.api.service.OrderApiService;
  35. import com.ffii.tbms.file.File;
  36. import com.ffii.tbms.file.FileBlob;
  37. import com.ffii.tbms.file.FileRef;
  38. import com.ffii.tbms.file.FileRefType;
  39. import com.ffii.tbms.file.service.FileService;
  40. import com.ffii.tbms.log.LogUtils;
  41. import com.ffii.tbms.log.service.AuditLogService;
  42. import com.ffii.tbms.order.Order;
  43. import com.ffii.tbms.order.service.OrderService;
  44. import org.apache.commons.lang3.RandomStringUtils;
  45. import org.springframework.beans.factory.annotation.Autowired;
  46. import org.springframework.stereotype.Controller;
  47. import org.springframework.ui.Model;
  48. import org.springframework.web.bind.annotation.PathVariable;
  49. import org.springframework.web.bind.annotation.RequestMapping;
  50. import org.springframework.web.bind.annotation.RequestMethod;
  51. import org.springframework.web.bind.annotation.RequestParam;
  52. import org.springframework.web.multipart.MultipartFile;
  53. @Controller
  54. @RequestMapping(value = "/api/file")
  55. public class FileApiController extends AbstractController {
  56. @Autowired
  57. private AuthenticationService authenticationService;
  58. @Autowired
  59. OrderApiService orderApiService;
  60. @Autowired
  61. private FileService fileService;
  62. @Autowired
  63. private SettingsService settingsService;
  64. @Autowired
  65. private AuditLogService auditLogService;
  66. private static final long MAX_FILE_UPLOAD_SIZE = 25 * 1024 * 1024; // 25 MB
  67. private static final boolean OVERWRITE_SAME_FILENAME = false;
  68. private static final int DEFAULT_UPLOAD_MAX_FILE_SIZE_MB = 50;
  69. @RequestMapping(value = "/list.json", method = { RequestMethod.GET, RequestMethod.POST })
  70. public String listJson(Model model, @RequestParam String deviceId, @RequestParam String token,
  71. @RequestParam String refType, @RequestParam Integer refId) {
  72. Map<String, Object> data = authenticationService.findUserByAccessToken(deviceId, token);
  73. if (data == null) {
  74. model.addAllAttributes(authenticationService.getNoUserFoundMap());
  75. return JsonView.NAME;
  76. }
  77. Map<String, Object> args = new HashMap<String, Object>();
  78. args.put(Params.REF_TYPE, refType);
  79. args.put(Params.REF_ID, refId);
  80. List<Map<String, Object>> records = fileService.searchFiles(args);
  81. model.addAttribute(Params.RECORDS, records);
  82. model.addAttribute(Params.SUCCESS, Boolean.TRUE);
  83. return JsonView.NAME;
  84. }
  85. @RequestMapping(value = "/measurement-sheet/ul", method = RequestMethod.POST)
  86. public String uploadMeasurementSheetFile(HttpServletRequest request, Model model, @RequestParam String deviceId, @RequestParam String token,
  87. @RequestParam int orderId, @RequestParam MultipartFile multipartFile) throws Exception {
  88. Map<String, Object> userData = authenticationService.findUserByAccessToken(deviceId, token);
  89. if (userData == null) {
  90. model.addAllAttributes(authenticationService.getNoUserFoundMap());
  91. return JsonView.NAME;
  92. }
  93. logger.info("upload file start");
  94. Order order = orderApiService.find(orderId);
  95. String refType = FileRefType.MEASUREMENT_SHEET;
  96. String refCode = order.getCustId() + "";
  97. Integer refId = orderId;
  98. // get file upload max file size setting
  99. int uploadMaxFileSize = settingsService.getInt("FILE.upload.maxFileSize", DEFAULT_UPLOAD_MAX_FILE_SIZE_MB) * 1024 * 1024;
  100. Boolean success = Boolean.TRUE;
  101. // only proceed if multipartFile is not null, and has file size
  102. if (multipartFile != null && multipartFile.getSize() > 0 && multipartFile.getSize() <= uploadMaxFileSize) {
  103. // DEBUG LOG
  104. logger.info("multipartFile.getSize() = " + multipartFile.getSize());
  105. File file = new File();
  106. file.setSysGroupId(NumberUtils.toInt(userData.get("sysGroupId"),0));
  107. file.setFilename(multipartFile.getOriginalFilename());
  108. // file.setMimetype(multipartFile.getContentType());
  109. file.setMimetype(FileUtils.guessMimetype(file.getFilename()));
  110. file.setFilesize(multipartFile.getSize());
  111. file.setDescription(ServletRequestUtils.getTrimmedStringParameter(request, "description"));
  112. FileBlob fileBlob = new FileBlob();
  113. fileBlob.setBytes(multipartFile.getBytes());
  114. fileBlob.setSysGroupId(NumberUtils.toInt(userData.get("sysGroupId"),0));
  115. FileRef fileRef = new FileRef();
  116. fileRef.setRefId(refId);
  117. fileRef.setRefType(refType);
  118. fileRef.setRefCode(refCode);
  119. fileRef.setSysGroupId(NumberUtils.toInt(userData.get("sysGroupId"),0));
  120. // get height and width if mimetype is png or jpeg
  121. if (AbstractView.CONTENT_TYPE_PNG.equals(file.getMimetype()) || AbstractView.CONTENT_TYPE_JPEG.equals(file.getMimetype())) {
  122. BufferedImage image = ImageIO.read(new ByteArrayInputStream(fileBlob.getBytes()));
  123. if (image != null) {
  124. file.setImageHeight(image.getHeight());
  125. file.setImageWidth(image.getWidth());
  126. }
  127. }
  128. if (OVERWRITE_SAME_FILENAME) {
  129. // search for existing file(s) with the same refType, refId, and filename
  130. List<Map<String, Object>> existingFiles = fileService.searchFiles(
  131. MapUtils.toHashMap("refType", refType, "refId", refId, "filename", file.getFilename()));
  132. // delete them if found
  133. for (Map<String, Object> existingFile : existingFiles) {
  134. fileService.deleteFile((Integer) existingFile.get("id"), (Integer) existingFile.get("refId"),
  135. (String) existingFile.get("refType"), (String) existingFile.get("skey"));
  136. }
  137. }
  138. // create UserFile
  139. file.setSkey(RandomStringUtils.randomAlphanumeric(16));
  140. fileService.saveFile(file);
  141. // create UserFileBlob
  142. fileBlob.setFileId(file.getId());
  143. fileService.saveFileBlob(fileBlob);
  144. // create UserFileRef
  145. fileRef.setFileId(file.getId());
  146. fileService.saveFileRef(fileRef);
  147. order.setFileId(file.getId());
  148. orderApiService.saveOrUpdate(order);
  149. } else {
  150. success = Boolean.FALSE;
  151. // if not success, return msg to client
  152. model.addAttribute(Params.MSG, getMessageSourceAccessor().getMessage("Upload Failed"));
  153. }
  154. model.addAttribute(Params.SUCCESS, success);
  155. return JsonView.NAME;
  156. }
  157. @RequestMapping(value = "/ul", method = RequestMethod.POST)
  158. public String uploadFile(HttpServletRequest request, Model model, @RequestParam String deviceId,
  159. @RequestParam String token, @RequestParam int refId, @RequestParam String refType,
  160. @RequestParam(defaultValue = StringUtils.EMPTY) String refCode, @RequestParam MultipartFile multipartFile)
  161. throws IOException {
  162. Map<String, Object> userData = authenticationService.findUserByAccessToken(deviceId, token);
  163. if (userData == null) {
  164. model.addAllAttributes(authenticationService.getNoUserFoundMap());
  165. return JsonView.NAME;
  166. }
  167. // only proceed if multipartFile is not null, and has file size
  168. if(multipartFile == null || multipartFile.getSize() <= 0 || multipartFile.getSize() > MAX_FILE_UPLOAD_SIZE){
  169. model.addAttribute(Params.MSG, getMessageSourceAccessor().getMessage("FILE.msg.uploadFailed"));
  170. model.addAttribute(Params.SUCCESS, Boolean.FALSE);
  171. return JsonView.NAME;
  172. }
  173. // DEBUG LOG
  174. logger.info("multipartFile.getSize() = " + multipartFile.getSize());
  175. File file = new File();
  176. file.setSysGroupId(NumberUtils.toInt(userData.get("sysGroupId"),0));
  177. file.setFilename(multipartFile.getOriginalFilename());
  178. // file.setMimetype(multipartFile.getContentType());
  179. file.setMimetype(FileUtils.guessMimetype(file.getFilename()));
  180. file.setFilesize(multipartFile.getSize());
  181. FileBlob fileBlob = new FileBlob();
  182. fileBlob.setSysGroupId(NumberUtils.toInt(userData.get("sysGroupId"),0));
  183. fileBlob.setBytes(multipartFile.getBytes());
  184. FileRef fileRef = new FileRef();
  185. fileRef.setSysGroupId(NumberUtils.toInt(userData.get("sysGroupId"),0));
  186. fileRef.setRefId(refId);
  187. fileRef.setRefType(refType);
  188. fileRef.setRefCode(refCode);
  189. // get height and width if mimetype is png or jpeg
  190. if (AbstractView.CONTENT_TYPE_PNG.equals(file.getMimetype())
  191. || AbstractView.CONTENT_TYPE_JPEG.equals(file.getMimetype())) {
  192. BufferedImage image = ImageIO.read(new ByteArrayInputStream(fileBlob.getBytes()));
  193. if (image != null) {
  194. file.setImageHeight(image.getHeight());
  195. file.setImageWidth(image.getWidth());
  196. }
  197. }
  198. // search for existing file(s) with the same refType, refId, and filename
  199. List<Map<String, Object>> existingFiles = fileService.searchFiles(
  200. MapUtils.toHashMap("refType", refType, "refId", refId, "filename", file.getFilename()));
  201. // delete them if found
  202. for (Map<String, Object> existingFile : existingFiles) {
  203. fileService.deleteFile((Integer) existingFile.get("id"), (Integer) existingFile.get("refId"),
  204. (String) existingFile.get("refType"), (String) existingFile.get("skey"));
  205. }
  206. // create UserFile
  207. file.setSkey(RandomStringUtils.randomAlphanumeric(16));
  208. fileService.saveFile(file);
  209. // create UserFileBlob
  210. fileBlob.setFileId(file.getId());
  211. fileService.saveFileBlob(fileBlob);
  212. // create UserFileRef
  213. fileRef.setFileId(file.getId());
  214. fileService.saveFileRef(fileRef);
  215. Map<String, Object> map = new HashMap<>();
  216. map.put("skey", file.getSkey());
  217. map.put("fileId", file.getId());
  218. map.put("filename", file.getFilename());
  219. map.put("filesize", file.getFilesize());
  220. map.put("refType", fileRef.getRefType());
  221. map.put("refId", fileRef.getRefId());
  222. map.put("mimetype", file.getMimetype());
  223. model.addAttribute(Params.DATA, map);
  224. if(refType.equals(FileRefType.ORDER)){
  225. ObjectMapper mapper = new ObjectMapper();
  226. auditLogService.save("orders",
  227. refId,
  228. NumberUtils.intValue(userData.get("id")),
  229. new Date(),
  230. LogUtils.ACTION_CREATE,
  231. mapper.writeValueAsString(MapUtils.toHashMap("photoFileId", file.getId(), "filename",file.getFilename())));
  232. }
  233. model.addAttribute(Params.AUTH, Boolean.TRUE);
  234. model.addAttribute(Params.SUCCESS, Boolean.TRUE);
  235. return JsonView.NAME;
  236. }
  237. @RequestMapping(value = "/dl/{id}/{skey}/{filename}", method = RequestMethod.GET)
  238. public void download(HttpServletResponse response, Model model, @RequestParam(defaultValue = "false") boolean dl,
  239. @PathVariable int id, @PathVariable String skey) throws IOException {
  240. File file = fileService.findFileByIdAndKey(id, skey);
  241. if (file != null) {
  242. FileBlob fileBlob = fileService.findFileBlobByFileId(id);
  243. response.reset();
  244. response.setContentType(file.getMimetype());
  245. response.setContentLength((int) file.getFilesize());
  246. response.setHeader("Content-Transfer-Encoding", "binary");
  247. response.setHeader("Content-Disposition", String.format("%s; filename=\"%s\"", dl ? "attachment" : "inline",
  248. response.encodeURL(file.getFilename())));
  249. ServletOutputStream out = response.getOutputStream();
  250. try {
  251. out.write(fileBlob.getBytes());
  252. out.flush();
  253. out.close();
  254. } catch (IOException e) {
  255. logger.warn(e.getMessage());
  256. } finally {
  257. out.close();
  258. model.addAttribute(Params.SUCCESS, Boolean.TRUE);
  259. }
  260. } else {
  261. logger.info("*** 400 BAD REQUEST ***");
  262. response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
  263. model.addAttribute(Params.SUCCESS, Boolean.FALSE);
  264. }
  265. }
  266. @RequestMapping(value = "/delete", method = RequestMethod.POST)
  267. public String delete(HttpServletResponse response, Model model, @RequestParam String deviceId,
  268. @RequestParam String token, @RequestParam Integer fileId, @RequestParam Integer refId,
  269. @RequestParam String refType, @RequestParam String skey) throws IOException {
  270. Map<String, Object> userData = authenticationService.findUserByAccessToken(deviceId, token);
  271. if (userData == null) {
  272. model.addAllAttributes(authenticationService.getNoUserFoundMap());
  273. return JsonView.NAME;
  274. }
  275. fileService.deleteFile(fileId, refId, refType, skey);
  276. if(refType.equals(FileRefType.MEASUREMENT_SHEET)){
  277. ObjectMapper mapper = new ObjectMapper();
  278. auditLogService.save("orders",
  279. refId,
  280. NumberUtils.intValue(userData.get("id")),
  281. new Date(),
  282. LogUtils.ACTION_DELETE,
  283. mapper.writeValueAsString(MapUtils.toHashMap("fileId", fileId)));
  284. }else if(refType.equals(FileRefType.ORDER)){
  285. ObjectMapper mapper = new ObjectMapper();
  286. auditLogService.save("orders",
  287. refId,
  288. NumberUtils.intValue(userData.get("id")),
  289. new Date(),
  290. LogUtils.ACTION_DELETE,
  291. mapper.writeValueAsString(MapUtils.toHashMap("photoFileId", fileId)));
  292. }
  293. model.addAttribute(Params.SUCCESS, Boolean.TRUE);
  294. return JsonView.NAME;
  295. }
  296. @RequestMapping(value = "/thumbnail/{id}/{skey}/{filename}", method = RequestMethod.GET)
  297. public void thumbnail(HttpServletResponse response, Model model, @RequestParam(defaultValue = "false") boolean dl,
  298. @PathVariable int id, @PathVariable String skey) throws IOException {
  299. File file = fileService.findFileByIdAndKey(id, skey);
  300. if (file != null) {
  301. FileBlob fileBlob = fileService.findFileBlobByFileId(id);
  302. response.reset();
  303. response.setContentType(file.getMimetype());
  304. // response.setContentLength((int) file.getFilesize());
  305. response.setHeader("Content-Transfer-Encoding", "binary");
  306. response.setHeader("Content-Disposition", String.format("%s; filename=\"%s\"", dl ? "attachment" : "inline",
  307. response.encodeURL(file.getFilename())));
  308. int limit = 500;
  309. BufferedImage image = ImageIO.read(new ByteArrayInputStream(fileBlob.getBytes()));
  310. int width = image.getWidth();
  311. int height = image.getHeight();
  312. if (width > height) {
  313. if (width > limit) {
  314. height = height * limit / width;
  315. width = limit;
  316. }
  317. } else {
  318. if (height > limit) {
  319. width = width * limit / height;
  320. height = limit;
  321. }
  322. }
  323. image = scale(image, width, height);
  324. ByteArrayOutputStream tmp = new ByteArrayOutputStream();
  325. ImageIO.write(image, "jpg", tmp);
  326. tmp.close();
  327. response.setContentLength((int) tmp.size());
  328. ServletOutputStream out = response.getOutputStream();
  329. try {
  330. out.write(tmp.toByteArray());
  331. out.flush();
  332. out.close();
  333. } catch (IOException e) {
  334. logger.warn(e.getMessage());
  335. } finally {
  336. out.close();
  337. model.addAttribute(Params.SUCCESS, Boolean.TRUE);
  338. }
  339. } else {
  340. logger.info("*** 400 BAD REQUEST ***");
  341. response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
  342. model.addAttribute(Params.SUCCESS, Boolean.FALSE);
  343. }
  344. }
  345. static BufferedImage scale(BufferedImage originalImage, int w, int h) {
  346. BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
  347. int x, y;
  348. int ww = originalImage.getWidth();
  349. int hh = originalImage.getHeight();
  350. for (x = 0; x < w; x++) {
  351. for (y = 0; y < h; y++) {
  352. int col = originalImage.getRGB(x * ww / w, y * hh / h);
  353. img.setRGB(x, y, col);
  354. }
  355. }
  356. return img;
  357. }
  358. }