From 291f4498320b2325093fb92cc9fbd9b4cb815782 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Mon, 9 Sep 2024 19:46:47 +0300 Subject: Handle post errors --- src/main/assets/scripts.js | 10 +-- src/main/java/com/juick/www/api/Post.java | 72 ++++++++++----------- .../java/com/juick/www/controllers/Settings.java | 20 ++++-- src/main/resources/data-h2.sql | 1 + .../java/com/juick/server/tests/ServerTests.java | 21 ++++++ src/test/resources/sample1.dng | Bin 0 -> 6372698 bytes 6 files changed, 76 insertions(+), 48 deletions(-) create mode 100644 src/test/resources/sample1.dng diff --git a/src/main/assets/scripts.js b/src/main/assets/scripts.js index 1583cedc..12c4d9b2 100644 --- a/src/main/assets/scripts.js +++ b/src/main/assets/scripts.js @@ -251,6 +251,10 @@ function closeDialogListener(ev) { } } +/** + * + * @param {Response} response + */ function handleErrors(response) { if (!response.ok) { throw Error(response.statusText) @@ -310,8 +314,7 @@ function showCommentForm(mid, rid) { method: 'POST', body: formData, credentials: 'include' - }).then(handleErrors) - .then(response => response.json()) + }).then(response => response.json()) .then(result => { if (result.newMessage) { window.location.hash = `#${result.newMessage.rid}` @@ -663,8 +666,7 @@ ready(() => { method: 'POST', body: formData, credentials: 'include' - }).then(handleErrors) - .then(response => response.json()) + }).then(response => response.json()) .then(result => { if (result.newMessage) { window.location.href = new URL(`/m/${result.newMessage.mid}`, window.location.href).href diff --git a/src/main/java/com/juick/www/api/Post.java b/src/main/java/com/juick/www/api/Post.java index 18b02445..57c23703 100644 --- a/src/main/java/com/juick/www/api/Post.java +++ b/src/main/java/com/juick/www/api/Post.java @@ -48,7 +48,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationEventPublisher; import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -74,38 +76,36 @@ public class Post { @RequestMapping(value = "/api/post", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseStatus(value = HttpStatus.OK) - public CommandResult doPostMessage( + public ResponseEntity doPostMessage( @Parameter(hidden = true) User visitor, @RequestParam(required = false, defaultValue = StringUtils.EMPTY) String body, @RequestParam(required = false) String img, @RequestParam(required = false) MultipartFile attach) throws Exception { body = body.replace("\r", StringUtils.EMPTY); - - URI attachmentFName = HttpUtils.receiveMultiPartFile(attach, storageService.getTemporaryDirectory()); - - if (StringUtils.isBlank(attachmentFName.toString()) && img != null && img.length() > 10) { - URI juickUri = URI.create(img); - if (juickUri.getScheme().equals("juick")) { - attachmentFName = juickUri; - } else { - try { + try { + URI attachmentFName = HttpUtils.receiveMultiPartFile(attach, storageService.getTemporaryDirectory()); + if (StringUtils.isBlank(attachmentFName.toString()) && img != null && img.length() > 10) { + URI juickUri = URI.create(img); + if (juickUri.getScheme().equals("juick")) { + attachmentFName = juickUri; + } else { URL imgUrl = new URL(img); attachmentFName = HttpUtils.downloadImage(imgUrl, storageService.getTemporaryDirectory()); - } catch (Exception e) { - logger.error("DOWNLOAD ERROR", e); - throw new HttpBadRequestException(); } } + if (StringUtils.isBlank(body) && StringUtils.isBlank(attachmentFName.toString())) { + // Should be there for compatibility + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(CommandResult.fromString("Empty message")); + } + return ResponseEntity.ok(commandsManager.processCommand(visitor, body, attachmentFName)); + } catch (Exception e) { + logger.error("DOWNLOAD ERROR", e); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(CommandResult.fromString(e.getMessage())); } - if (StringUtils.isBlank(body) && StringUtils.isBlank(attachmentFName.toString())) { - // Should be there for compatibility - throw new HttpBadRequestException(); - } - return commandsManager.processCommand(visitor, body, attachmentFName); } @RequestMapping(value = "/api/comment", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) - public CommandResult doPostComment( + public ResponseEntity doPostComment( @Parameter(hidden = true) User visitor, @RequestParam(defaultValue = "0") int mid, @RequestParam(defaultValue = "0") int rid, @@ -114,11 +114,11 @@ public class Post { @RequestParam(required = false) MultipartFile attach) throws Exception { if (mid == 0) { - throw new HttpBadRequestException(); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(CommandResult.fromString("Invalid mid")); } Optional message = messagesService.getMessage(mid); if (message.isEmpty()) { - throw new HttpNotFoundException(); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(CommandResult.fromString("Message not found")); } Message msg = message.get(); @@ -127,7 +127,7 @@ public class Post { if (rid > 0) { reply = messagesService.getReply(mid, rid); if (reply == null) { - throw new HttpNotFoundException(); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(CommandResult.fromString("Reply not found")); } } @@ -135,25 +135,23 @@ public class Post { || userService.isInBL(visitor.getUid(), msg.getUser().getUid()) || (reply != null && userService.isInBL(visitor.getUid(), reply.getUser().getUid()))) { // TODO: validator - throw new HttpForbiddenException(); + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(CommandResult.fromString("Forbidden")); } - - URI attachmentFName = HttpUtils.receiveMultiPartFile(attach, storageService.getTemporaryDirectory()); - - if (StringUtils.isBlank(attachmentFName.toString()) && img != null && img.length() > 10) { - try { + try { + URI attachmentFName = HttpUtils.receiveMultiPartFile(attach, storageService.getTemporaryDirectory()); + if (StringUtils.isBlank(attachmentFName.toString()) && img != null && img.length() > 10) { attachmentFName = HttpUtils.downloadImage(new URL(img), storageService.getTemporaryDirectory()); - } catch (Exception e) { - logger.error("DOWNLOAD ERROR", e); - throw new HttpBadRequestException(); } + if (StringUtils.isBlank(body) && StringUtils.isBlank(attachmentFName.toString())) { + // Should be there for compatibility + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(CommandResult.fromString("Empty message")); + } + return ResponseEntity.ok(commandsManager.processCommand(visitor, String.format("#%d/%d %s", mid, rid, body), + attachmentFName)); + } catch (Exception e) { + logger.error("DOWNLOAD ERROR", e); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(CommandResult.fromString(e.getMessage())); } - if (StringUtils.isBlank(body) && StringUtils.isBlank(attachmentFName.toString())) { - // Should be there for compatibility - throw new HttpBadRequestException(); - } - return commandsManager.processCommand(visitor, String.format("#%d/%d %s", mid, rid, body), - attachmentFName); } @PostMapping("/api/like") diff --git a/src/main/java/com/juick/www/controllers/Settings.java b/src/main/java/com/juick/www/controllers/Settings.java index 8d66bd36..449275c3 100644 --- a/src/main/java/com/juick/www/controllers/Settings.java +++ b/src/main/java/com/juick/www/controllers/Settings.java @@ -150,14 +150,20 @@ public class Settings { visitor.setCountry(request.getParameter("country")); visitor.setUrl(request.getParameter("url")); visitor.setDescription(request.getParameter("descr")); - String avatarTmpPath = HttpUtils.receiveMultiPartFile(newAvatar, storageService.getTemporaryDirectory()).getHost(); - if (StringUtils.isNotEmpty(avatarTmpPath)) { - storageService.saveAvatar(avatarTmpPath, visitor); - } - if (userService.updateUserInfo(visitor)) { - result = String.format("

Your info is updated.

Back to blog.

", visitor.getName()); + try { + String avatarTmpPath = HttpUtils + .receiveMultiPartFile(newAvatar, storageService.getTemporaryDirectory()).getHost(); + if (StringUtils.isNotEmpty(avatarTmpPath)) { + storageService.saveAvatar(avatarTmpPath, visitor); + } + if (userService.updateUserInfo(visitor)) { + result = String.format("

Your info is updated.

Back to blog.

", + visitor.getName()); + } + applicationEventPublisher.publishEvent(new UpdateUserEvent(this, visitor)); + } catch (Exception e) { + result = "

" + e.getMessage() + ". Back.

"; } - applicationEventPublisher.publishEvent(new UpdateUserEvent(this, visitor)); break; case "jid-del": // FIXME: stop using ugnich-csv in parameters diff --git a/src/main/resources/data-h2.sql b/src/main/resources/data-h2.sql index 818575e9..72615485 100644 --- a/src/main/resources/data-h2.sql +++ b/src/main/resources/data-h2.sql @@ -1,6 +1,7 @@ INSERT INTO users(id, nick, passw) VALUES(0, 'Anonymous', 'password'); INSERT INTO users(id, nick, passw) VALUES(2, 'juick', 'password'); INSERT INTO users(id, nick, passw) VALUES(5, 'archive', 'password'); +INSERT INTO telegram(user_id, tg_id) VALUES(5, '1'); INSERT INTO reactions (like_id, description) VALUES (1, 'like'); INSERT INTO reactions (like_id, description) VALUES (2, 'love'); INSERT INTO reactions (like_id, description) VALUES (3, 'lol'); diff --git a/src/test/java/com/juick/server/tests/ServerTests.java b/src/test/java/com/juick/server/tests/ServerTests.java index 418526c7..e0abe136 100644 --- a/src/test/java/com/juick/server/tests/ServerTests.java +++ b/src/test/java/com/juick/server/tests/ServerTests.java @@ -2749,4 +2749,25 @@ public class ServerTests { var replies = message.getReplies(); assertThat(replies.size(), is(1)); } + @Test + @Transactional + public void unsupportedMediaShouldBeHandledCorrectly() throws Exception { + ClassPathResource newMedia = new ClassPathResource("sample1.dng"); + byte[] newMediaData = IOUtils.toByteArray(newMedia.getInputStream()); + var response = mockMvc.perform(MockMvcRequestBuilders.multipart("/api/post") + .file(new MockMultipartFile("attach", "sample1.dng", "image/dng", newMediaData)) + .param("body", "test") + .with(httpBasic(freefdName, freefdPassword))).andExpect(status().isBadRequest()).andReturn(); + var result = jsonMapper.readValue(response.getResponse().getContentAsString(), CommandResult.class); + assertThat(result.getText(), is("Wrong file type: tif")); + var r = commandsManager.processCommand(freefd, "tst", emptyUri); + response = mockMvc.perform(MockMvcRequestBuilders.multipart("/api/comment") + .file(new MockMultipartFile("attach", "sample1.dng", "image/dng", newMediaData)) + .param("body", "test") + .param("mid", String.valueOf(r.getNewMessage().get().getMid())) + .with(httpBasic(freefdName, freefdPassword))).andExpect(status().isBadRequest()).andReturn(); + result = jsonMapper.readValue(response.getResponse().getContentAsString(), CommandResult.class); + assertThat(result.getText(), is("Wrong file type: tif")); + + } } diff --git a/src/test/resources/sample1.dng b/src/test/resources/sample1.dng new file mode 100644 index 00000000..e732e009 Binary files /dev/null and b/src/test/resources/sample1.dng differ -- cgit v1.2.3