Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,102 +1,115 @@
package com.cadac.stone_inscription.exception;

import org.springframework.validation.BindException;

import java.nio.file.AccessDeniedException;

import java.util.HashMap;
import java.util.Map;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authorization.AuthorizationDeniedException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class ExceptionController {

// Custom Exception
@ExceptionHandler(StoneInscriptionException.class)
public ResponseEntity<Map<String, Object>> handleStoneInscriptionException(StoneInscriptionException exception) {
Map<String, Object> errorResp = new HashMap<String, Object>();
errorResp.put("error_message", exception.getMessage());
errorResp.put("http_status", exception.getHttpStatus());
errorResp.put("http_status_code", exception.getHttpStatus().value());
return new ResponseEntity<Map<String, Object>>(errorResp, exception.getHttpStatus());
}

// Request Body
@ExceptionHandler(MethodArgumentNotValidException.class)

public ResponseEntity<Map<String, Object>> handleMethodArgumentNotValidException(
MethodArgumentNotValidException exeption) {

Map<String, Object> errorResp = new HashMap<String, Object>();

exeption.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String message = error.getDefaultMessage();
// errorResp.put(fieldName, message);
errorResp.put("error_message", fieldName + " --> " + message);
});

errorResp.put("http_status", HttpStatus.UNPROCESSABLE_ENTITY.value());
return new ResponseEntity<Map<String, Object>>(errorResp, HttpStatus.UNPROCESSABLE_ENTITY);

}

// Model Attribute
@ExceptionHandler(BindException.class)

public ResponseEntity<Map<String, Object>> handleBindException(
BindException exeption) {

Map<String, Object> errorResp = new HashMap<String, Object>();
errorResp.put("http_status", HttpStatus.UNPROCESSABLE_ENTITY.value());
exeption.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String message = error.getDefaultMessage();
errorResp.put("error_message", fieldName + " : " + message);
});

return new ResponseEntity<Map<String, Object>>(errorResp, HttpStatus.UNPROCESSABLE_ENTITY);

}

@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<Map<String, Object>> handleHttpMessageNotReadableException(
HttpMessageNotReadableException exception) {

Map<String, Object> errorResp = new HashMap<String, Object>();
errorResp.put("error_message", exception.getMessage());
errorResp.put("http_status", HttpStatus.BAD_REQUEST);
errorResp.put("http_status_code", HttpStatus.BAD_REQUEST.value());
return new ResponseEntity<Map<String, Object>>(errorResp, HttpStatus.BAD_REQUEST);
}


// // 🔹 500 Internal Server Error (catch all)
@ExceptionHandler(Exception.class)
public ResponseEntity<Map<String, Object>> handleGeneralException(Exception ex) {
Map<String, Object> errorResp = new HashMap<String, Object>();
errorResp.put("error_message", ex.getMessage());
errorResp.put("http_status", HttpStatus.BAD_REQUEST);
errorResp.put("http_status_code", HttpStatus.BAD_REQUEST.value());
return new ResponseEntity<Map<String, Object>>(errorResp, HttpStatus.INTERNAL_SERVER_ERROR);

}

// // Any kind of Exception
// @ExceptionHandler(Exception.class)
// public ResponseEntity<String> handleUnknownException(Exception ex) {

// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
// .body("An unknown error occurred. Please try again later.");
// }

}
package com.cadac.stone_inscription.exception;

import org.springframework.validation.BindException;

import java.nio.file.AccessDeniedException;

import java.util.HashMap;
import java.util.Map;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authorization.AuthorizationDeniedException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class ExceptionController {

// Custom Exception
@ExceptionHandler(StoneInscriptionException.class)
public ResponseEntity<Map<String, Object>> handleStoneInscriptionException(StoneInscriptionException exception) {
Map<String, Object> errorResp = new HashMap<String, Object>();
errorResp.put("error_message", exception.getMessage());
errorResp.put("http_status", exception.getHttpStatus());
errorResp.put("http_status_code", exception.getHttpStatus().value());
return new ResponseEntity<Map<String, Object>>(errorResp, exception.getHttpStatus());
}

// Request Body
@ExceptionHandler(MethodArgumentNotValidException.class)

public ResponseEntity<Map<String, Object>> handleMethodArgumentNotValidException(
MethodArgumentNotValidException exeption) {

Map<String, Object> errorResp = new HashMap<String, Object>();

exeption.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String message = error.getDefaultMessage();
// errorResp.put(fieldName, message);
errorResp.put("error_message", fieldName + " --> " + message);
});

errorResp.put("http_status", HttpStatus.UNPROCESSABLE_ENTITY.value());
return new ResponseEntity<Map<String, Object>>(errorResp, HttpStatus.UNPROCESSABLE_ENTITY);

}

// Model Attribute
@ExceptionHandler(BindException.class)

public ResponseEntity<Map<String, Object>> handleBindException(
BindException exeption) {

Map<String, Object> errorResp = new HashMap<String, Object>();
errorResp.put("http_status", HttpStatus.UNPROCESSABLE_ENTITY.value());
exeption.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String message = error.getDefaultMessage();
errorResp.put("error_message", fieldName + " : " + message);
});

return new ResponseEntity<Map<String, Object>>(errorResp, HttpStatus.UNPROCESSABLE_ENTITY);

}

@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<Map<String, Object>> handleHttpMessageNotReadableException(
HttpMessageNotReadableException exception) {

Map<String, Object> errorResp = new HashMap<String, Object>();
errorResp.put("error_message", exception.getMessage());
errorResp.put("http_status", HttpStatus.BAD_REQUEST);
errorResp.put("http_status_code", HttpStatus.BAD_REQUEST.value());
return new ResponseEntity<Map<String, Object>>(errorResp, HttpStatus.BAD_REQUEST);
}



@ExceptionHandler(MaxUploadSizeExceededException.class)
public ResponseEntity<Map<String, Object>> handleMaxUploadSizeExceededException(
MaxUploadSizeExceededException exception) {

Map<String, Object> errorResp = new HashMap<String, Object>();
errorResp.put("error_message", "Upload size exceeded the allowed limit. Each image must be 75 MB or less and a post can contain at most 16 images.");
errorResp.put("http_status", HttpStatus.BAD_REQUEST);
errorResp.put("http_status_code", HttpStatus.BAD_REQUEST.value());
return new ResponseEntity<Map<String, Object>>(errorResp, HttpStatus.BAD_REQUEST);
}

// // 🔹 500 Internal Server Error (catch all)
@ExceptionHandler(Exception.class)
public ResponseEntity<Map<String, Object>> handleGeneralException(Exception ex) {
Map<String, Object> errorResp = new HashMap<String, Object>();
errorResp.put("error_message", ex.getMessage());
errorResp.put("http_status", HttpStatus.BAD_REQUEST);
errorResp.put("http_status_code", HttpStatus.BAD_REQUEST.value());
return new ResponseEntity<Map<String, Object>>(errorResp, HttpStatus.INTERNAL_SERVER_ERROR);

}

// // Any kind of Exception
// @ExceptionHandler(Exception.class)
// public ResponseEntity<String> handleUnknownException(Exception ex) {

// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
// .body("An unknown error occurred. Please try again later.");
// }

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
@RequestMapping("/post")
public class PostController {

private static final int MAX_IMAGES_PER_POST = 16;
private static final long MAX_IMAGE_SIZE_BYTES = 75L * 1024 * 1024;

@Autowired
private PostService postService;

Expand All @@ -52,7 +55,7 @@ public ResponseEntity<?> addPostWithFile(
throw new StoneInscriptionException("No File Uploaded", HttpStatus.BAD_REQUEST);
}

validateFiles(files);
validateFiles(files, MAX_IMAGES_PER_POST);
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7);
Expand Down Expand Up @@ -208,7 +211,7 @@ public ResponseEntity<?> updatePost(HttpServletRequest request,
@RequestPart(value = "files", required = false) MultipartFile... files) {

files = getNonEmptyFiles(files);
validateFiles(files);
validateFiles(files, MAX_IMAGES_PER_POST);

String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
Expand All @@ -232,7 +235,7 @@ public ResponseEntity<?> addImagesToPost(HttpServletRequest request,
throw new StoneInscriptionException("No File Uploaded", HttpStatus.BAD_REQUEST);
}

validateFiles(files);
validateFiles(files, MAX_IMAGES_PER_POST);

String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
Expand Down Expand Up @@ -261,7 +264,7 @@ public ResponseEntity<?> deleteImagesFromPost(HttpServletRequest request,
// TODO: Remove these methods when testing is done to restore normal behavior.
// ============================

// @PostMapping("/test/updatePost/{email}")
// // @PostMapping("/test/updatePost/{email}")
// public ResponseEntity<?> updatePostForTest(
// @PathVariable String email,
// @RequestPart(value = "post", required = false) InscriptionPostDto InscriptionPostDto,
Expand All @@ -270,7 +273,7 @@ public ResponseEntity<?> deleteImagesFromPost(HttpServletRequest request,
// @RequestPart(value = "files", required = false) MultipartFile... files) {

// files = getNonEmptyFiles(files);
// validateFiles(files);
// validateFiles(files, MAX_IMAGES_PER_POST);

// return postService.updatePost(email, InscriptionPostDto, postId, deletedImageIds, files);
// }
Expand All @@ -287,7 +290,7 @@ public ResponseEntity<?> deleteImagesFromPost(HttpServletRequest request,
// throw new StoneInscriptionException("No File Uploaded", HttpStatus.BAD_REQUEST);
// }

// validateFiles(files);
// validateFiles(files, MAX_IMAGES_PER_POST);

// return postService.addPostWithFile(InscriptionPostDto, files, email);
// }
Expand All @@ -304,7 +307,7 @@ public ResponseEntity<?> deleteImagesFromPost(HttpServletRequest request,
// throw new StoneInscriptionException("No File Uploaded", HttpStatus.BAD_REQUEST);
// }

// validateFiles(files);
// validateFiles(files, MAX_IMAGES_PER_POST);

// return postService.addImagesToPost(email, postId, files);
// }
Expand Down Expand Up @@ -338,7 +341,12 @@ private MultipartFile[] getNonEmptyFiles(MultipartFile[] files) {
.toArray(MultipartFile[]::new);
}

private void validateFiles(MultipartFile[] files) {
private void validateFiles(MultipartFile[] files, int maxFilesAllowed) {
if (files.length > maxFilesAllowed) {
throw new StoneInscriptionException("Maximum " + maxFilesAllowed + " images are allowed per post",
HttpStatus.BAD_REQUEST);
}

Arrays.stream(files).forEach(file -> {
String originalFilename = file.getOriginalFilename();
if (originalFilename == null || Arrays.stream(fileExt)
Expand All @@ -347,6 +355,11 @@ private void validateFiles(MultipartFile[] files) {
throw new StoneInscriptionException("Invalid File format only allowed" + Arrays.toString(fileExt),
HttpStatus.BAD_REQUEST);
}

if (file.getSize() > MAX_IMAGE_SIZE_BYTES) {
throw new StoneInscriptionException("Each image size should be less than or equal to 75 MB",
HttpStatus.BAD_REQUEST);
}
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
@Service
public class PostServiceImp implements PostService {

private static final int MAX_IMAGES_PER_POST = 16;

@Autowired
private UserRepository userRepository;

Expand Down Expand Up @@ -111,6 +113,7 @@ public ResponseEntity<?> addPostWithFile(InscriptionPostDto inscriptionPostDto,
}
inscriptionPost.getDescription().setModeration(moderation);

ensureMaximumImageCount(0, 0, ls.size());
adjustUserImagesUploaded(user, ls.size());
userRepository.save(user);

Expand Down Expand Up @@ -400,6 +403,7 @@ public ResponseEntity<?> updatePost(String usernameFromToken, InscriptionPostDto
List<ImageMetaAndInfo> newImages = validateAndExtractImages(files, user.getId(), deletableImageIds, false);

ensureMinimumImageCount(existingImageIds.size(), deletableImageIds.size(), newImages.size());
ensureMaximumImageCount(existingImageIds.size(), deletableImageIds.size(), newImages.size());

if (inscriptionPostDto != null) {
ContentModeration moderation = moderatePostContent(
Expand Down Expand Up @@ -441,6 +445,7 @@ public ResponseEntity<?> addImagesToPost(String usernameFromToken, String postId
List<ImageMetaAndInfo> newImages = validateAndExtractImages(files, user.getId(), Collections.emptySet(), true);

List<String> updatedImageIds = getExistingImageIds(post);
ensureMaximumImageCount(updatedImageIds.size(), 0, newImages.size());
updatedImageIds.addAll(saveImages(post.getId(), newImages));

updatePostImages(post, updatedImageIds, Collections.emptySet());
Expand Down Expand Up @@ -708,6 +713,15 @@ private void ensureMinimumImageCount(int existingImageCount, int deletedImageCou
}
}

private void ensureMaximumImageCount(int existingImageCount, int deletedImageCount, int newImageCount) {
int finalImageCount = existingImageCount - deletedImageCount + newImageCount;

if (finalImageCount > MAX_IMAGES_PER_POST) {
throw new StoneInscriptionException("Maximum " + MAX_IMAGES_PER_POST + " images are allowed per post",
HttpStatus.BAD_REQUEST);
}
}

private List<String> removeDeletedImageIds(List<String> existingImageIds, Set<String> deletableImageIds) {
return existingImageIds.stream()
.filter(imageId -> !deletableImageIds.contains(imageId))
Expand Down
Loading
Loading