From d81a4a05883aae18aa730a52681baf45b1597be8 Mon Sep 17 00:00:00 2001 From: Bunthai Deng Date: Wed, 7 Feb 2024 17:56:24 -0600 Subject: [PATCH] Update Property --- .../pms/configuration/SecurityConfig.java | 1 - .../ExceptionControllerAdvice.java | 32 ++++++------- .../main/java/com/mini/pms/entity/Member.java | 2 + .../java/com/mini/pms/entity/Property.java | 1 + .../java/com/mini/pms/repo/PictureRepo.java | 2 + .../restcontroller/EmailRestController.java | 3 +- .../PropertyRestController.java | 13 ++++++ .../restcontroller/request/EmailRequest.java | 3 ++ .../com/mini/pms/service/PictureService.java | 6 ++- .../com/mini/pms/service/PropertyService.java | 2 + .../pms/service/impl/PictureServiceImpl.java | 43 +++++++++++++---- .../pms/service/impl/PropertyServiceImpl.java | 46 ++++++++++++++----- .../pms/src/main/resources/application.yml | 2 +- 13 files changed, 113 insertions(+), 43 deletions(-) diff --git a/backend/pms/src/main/java/com/mini/pms/configuration/SecurityConfig.java b/backend/pms/src/main/java/com/mini/pms/configuration/SecurityConfig.java index 4858ee0..b1aa04d 100644 --- a/backend/pms/src/main/java/com/mini/pms/configuration/SecurityConfig.java +++ b/backend/pms/src/main/java/com/mini/pms/configuration/SecurityConfig.java @@ -58,7 +58,6 @@ public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws String contextPath = "**/api/v1"; authorize .requestMatchers( - contextPath + "/public", contextPath + "/auth/**" ) .permitAll() diff --git a/backend/pms/src/main/java/com/mini/pms/customexception/ExceptionControllerAdvice.java b/backend/pms/src/main/java/com/mini/pms/customexception/ExceptionControllerAdvice.java index 5dc70b9..70e9995 100644 --- a/backend/pms/src/main/java/com/mini/pms/customexception/ExceptionControllerAdvice.java +++ b/backend/pms/src/main/java/com/mini/pms/customexception/ExceptionControllerAdvice.java @@ -1,10 +1,8 @@ package com.mini.pms.customexception; -import jakarta.servlet.ServletException; import jakarta.validation.ValidationException; import lombok.NonNull; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import lombok.extern.log4j.Log4j2; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode; @@ -13,33 +11,30 @@ import org.springframework.validation.FieldError; import org.springframework.validation.ObjectError; import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import org.springframework.web.servlet.resource.NoResourceFoundException; import java.util.HashMap; import java.util.List; -import java.util.Map; -@ControllerAdvice +@RestControllerAdvice +@Log4j2 public class ExceptionControllerAdvice extends ResponseEntityExceptionHandler { - private static final Logger logger = LogManager.getLogger(ExceptionControllerAdvice.class); - - @ExceptionHandler({RuntimeException.class, ServletException.class}) - public ResponseEntity handleException(Exception e) { - e.fillInStackTrace(); - logger.error(e.fillInStackTrace()); - if (e instanceof PlatformException platform) { + @ExceptionHandler({Exception.class}) + public ResponseEntity handleException(Exception ex) { + logger.error("Error: ", ex); + if (ex instanceof PlatformException platform) { return createResponseEntity(platform.getMessage(), platform.getHttpStatusCode()); - } else if (e instanceof AccessDeniedException) { + } else if (ex instanceof AccessDeniedException) { return createResponseEntity("Access Denied", HttpStatus.FORBIDDEN); - } else if (e instanceof NoResourceFoundException) { + } else if (ex instanceof NoResourceFoundException) { return createResponseEntity("Resource Not Found", HttpStatus.NOT_FOUND); - } else if(e instanceof ValidationException) { - return createResponseEntity(e.getMessage(), HttpStatus.BAD_REQUEST); + } else if(ex instanceof ValidationException) { + return createResponseEntity(ex.getMessage(), HttpStatus.BAD_REQUEST); } return createResponseEntity("General Error", HttpStatus.INTERNAL_SERVER_ERROR); } @@ -62,7 +57,8 @@ protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotV @NonNull HttpHeaders headers, @NonNull HttpStatusCode status, @NonNull WebRequest request) { - Map errors = new HashMap<>(); + logger.error("Error: ", ex); + var errors = new HashMap<>(); List errorList = ex.getBindingResult().getAllErrors(); errorList.forEach((error)-> { String fieldName = ((FieldError)error).getField(); diff --git a/backend/pms/src/main/java/com/mini/pms/entity/Member.java b/backend/pms/src/main/java/com/mini/pms/entity/Member.java index c364532..a1514fe 100644 --- a/backend/pms/src/main/java/com/mini/pms/entity/Member.java +++ b/backend/pms/src/main/java/com/mini/pms/entity/Member.java @@ -1,5 +1,6 @@ package com.mini.pms.entity; +import com.fasterxml.jackson.annotation.JsonBackReference; import com.mini.pms.entity.type.MemberStatus; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -74,6 +75,7 @@ public class Member { private MemberStatus status; @OneToMany(mappedBy = "owner") + @JsonBackReference private List properties; @OneToMany(fetch = FetchType.EAGER, mappedBy = "customer") diff --git a/backend/pms/src/main/java/com/mini/pms/entity/Property.java b/backend/pms/src/main/java/com/mini/pms/entity/Property.java index 9fa84b9..8817872 100644 --- a/backend/pms/src/main/java/com/mini/pms/entity/Property.java +++ b/backend/pms/src/main/java/com/mini/pms/entity/Property.java @@ -62,6 +62,7 @@ public class Property { private List offers; @ManyToOne(fetch = FetchType.EAGER) + @JsonManagedReference private Member owner; private String category; diff --git a/backend/pms/src/main/java/com/mini/pms/repo/PictureRepo.java b/backend/pms/src/main/java/com/mini/pms/repo/PictureRepo.java index 39aaa4c..ff48253 100644 --- a/backend/pms/src/main/java/com/mini/pms/repo/PictureRepo.java +++ b/backend/pms/src/main/java/com/mini/pms/repo/PictureRepo.java @@ -6,9 +6,11 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; @Repository public interface PictureRepo extends JpaRepository { // Optional findByKey(String key); + List findByKeyIn(List keys); } diff --git a/backend/pms/src/main/java/com/mini/pms/restcontroller/EmailRestController.java b/backend/pms/src/main/java/com/mini/pms/restcontroller/EmailRestController.java index abd26a9..59f7137 100644 --- a/backend/pms/src/main/java/com/mini/pms/restcontroller/EmailRestController.java +++ b/backend/pms/src/main/java/com/mini/pms/restcontroller/EmailRestController.java @@ -4,6 +4,7 @@ import com.mini.pms.service.EmailService; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -19,7 +20,7 @@ public class EmailRestController { @PostMapping("send") @ResponseStatus(HttpStatus.NO_CONTENT) - public void sendEmail(@RequestBody EmailRequest emailRequest) { + public void sendEmail(@RequestBody @Validated EmailRequest emailRequest) { emailService.sendSimpleMail( emailRequest.getTitle(), emailRequest.getContent(), emailRequest.getRecipient()); } diff --git a/backend/pms/src/main/java/com/mini/pms/restcontroller/PropertyRestController.java b/backend/pms/src/main/java/com/mini/pms/restcontroller/PropertyRestController.java index 6fec0d8..f0f1eb6 100644 --- a/backend/pms/src/main/java/com/mini/pms/restcontroller/PropertyRestController.java +++ b/backend/pms/src/main/java/com/mini/pms/restcontroller/PropertyRestController.java @@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -63,6 +64,7 @@ public ResponseEntity findAllProps( return ResponseEntity.ok(new PageResponse(props, PropertyResponse.class)); } + @GetMapping("/{id}") public ResponseEntity findById(@PathVariable("id") Long id) { Property prop = propService.findById(id); @@ -79,4 +81,15 @@ public ResponseEntity createProperty( ); } + @PutMapping("{id}") + public ResponseEntity updateProperty( + @PathVariable long id, + @RequestBody PropertyRequest propertyRequest, + Principal principal + ) { + return ResponseEntity.ok( + Util.mapObj(propService.updateProperty(id, propertyRequest, principal), PropertyResponse.class) + ); + } + } diff --git a/backend/pms/src/main/java/com/mini/pms/restcontroller/request/EmailRequest.java b/backend/pms/src/main/java/com/mini/pms/restcontroller/request/EmailRequest.java index 0fd4873..ed1453f 100644 --- a/backend/pms/src/main/java/com/mini/pms/restcontroller/request/EmailRequest.java +++ b/backend/pms/src/main/java/com/mini/pms/restcontroller/request/EmailRequest.java @@ -1,5 +1,6 @@ package com.mini.pms.restcontroller.request; +import jakarta.validation.constraints.NotNull; import lombok.Data; @Data @@ -7,6 +8,8 @@ public class EmailRequest { private String title; private String content; + + @NotNull private String recipient; } diff --git a/backend/pms/src/main/java/com/mini/pms/service/PictureService.java b/backend/pms/src/main/java/com/mini/pms/service/PictureService.java index 75c1235..386f5fd 100644 --- a/backend/pms/src/main/java/com/mini/pms/service/PictureService.java +++ b/backend/pms/src/main/java/com/mini/pms/service/PictureService.java @@ -1,6 +1,7 @@ package com.mini.pms.service; import com.mini.pms.entity.Picture; +import com.mini.pms.entity.Property; import com.mini.pms.restcontroller.response.DownloadFileInfo; import com.mini.pms.restcontroller.response.UploadFileInfo; import jakarta.transaction.Transactional; @@ -9,6 +10,7 @@ import java.io.IOException; import java.net.MalformedURLException; import java.security.Principal; +import java.util.List; public interface PictureService { UploadFileInfo upload(MultipartFile file, Principal principal) @@ -18,6 +20,8 @@ UploadFileInfo upload(MultipartFile file, Principal principal) Picture findByKey(String key); + List findByKey(List keys); + @Transactional - Picture update(Picture picture); + List updateByProperty(Property property, List pictures); } diff --git a/backend/pms/src/main/java/com/mini/pms/service/PropertyService.java b/backend/pms/src/main/java/com/mini/pms/service/PropertyService.java index 02a45f4..c1e277e 100644 --- a/backend/pms/src/main/java/com/mini/pms/service/PropertyService.java +++ b/backend/pms/src/main/java/com/mini/pms/service/PropertyService.java @@ -14,4 +14,6 @@ public interface PropertyService { Property findById(long id); Property createProperty(PropertyRequest propertyRequest, Principal principal); + + Property updateProperty(long id, PropertyRequest propertyRequest, Principal principal); } diff --git a/backend/pms/src/main/java/com/mini/pms/service/impl/PictureServiceImpl.java b/backend/pms/src/main/java/com/mini/pms/service/impl/PictureServiceImpl.java index 3ecee1f..a20a5fd 100644 --- a/backend/pms/src/main/java/com/mini/pms/service/impl/PictureServiceImpl.java +++ b/backend/pms/src/main/java/com/mini/pms/service/impl/PictureServiceImpl.java @@ -2,6 +2,7 @@ import com.mini.pms.customexception.PlatformException; import com.mini.pms.entity.Picture; +import com.mini.pms.entity.Property; import com.mini.pms.repo.PictureRepo; import com.mini.pms.restcontroller.FileRestController; import com.mini.pms.restcontroller.response.DownloadFileInfo; @@ -24,6 +25,8 @@ import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.security.Principal; +import java.util.List; +import java.util.Objects; import java.util.UUID; @Service @@ -49,12 +52,12 @@ public UploadFileInfo upload(MultipartFile file, Principal principal) .build() .toString(); - var pic = Picture.builder() - .key(key) - .name(name) - .size(size) - .url(url) - .build(); + var pic = Picture.builder() + .key(key) + .name(name) + .size(size) + .url(url) + .build(); var a = picRepo.save(pic); System.out.println(a); @@ -85,11 +88,33 @@ public Picture findByKey(String key) { return pic; } + @Override + public List findByKey(List keys) { + return picRepo.findByKeyIn(keys); + } + @Override @Transactional - public Picture update(Picture picture) { - findByKey(picture.getKey()); - return picRepo.save(picture); + public List updateByProperty(Property property, List keys) { + + List existingPics = findByKey(keys); + + var existingKeys = existingPics.stream().map(Picture::getKey).toList(); + if (existingPics.size() != keys.size()) { + var notFoundKeys = keys.stream().filter(k -> existingKeys.stream().noneMatch(f -> f.equals(k))).toList(); + throw new PlatformException("keys: " + notFoundKeys + " are not found", HttpStatus.BAD_REQUEST); + } + + var unMatchOwnerKeys = existingPics.stream() + .filter(f -> !(Objects.isNull(f.getProperty()) || f.getProperty().getId() == property.getId())) + .map(Picture::getKey) + .toList(); + if (!unMatchOwnerKeys.isEmpty()) { + throw new PlatformException("keys: " + unMatchOwnerKeys + " key already join to another property", HttpStatus.BAD_REQUEST); + } + + existingPics = existingPics.stream().peek(p -> p.setProperty(property)).toList(); + return picRepo.saveAll(existingPics); } private void writeFile(InputStream file, String key) throws IOException { diff --git a/backend/pms/src/main/java/com/mini/pms/service/impl/PropertyServiceImpl.java b/backend/pms/src/main/java/com/mini/pms/service/impl/PropertyServiceImpl.java index aa64661..da163b9 100644 --- a/backend/pms/src/main/java/com/mini/pms/service/impl/PropertyServiceImpl.java +++ b/backend/pms/src/main/java/com/mini/pms/service/impl/PropertyServiceImpl.java @@ -29,7 +29,7 @@ public class PropertyServiceImpl implements PropertyService { private final PictureRepo picRepo; @Override - public Page findAll(Long memberId ,String search, Double minPrice, Double maxPrice, String category, String type, String numberOfRoom, String location, Pageable pageable, Principal principal) { + public Page findAll(Long memberId, String search, Double minPrice, Double maxPrice, String category, String type, String numberOfRoom, String location, Pageable pageable, Principal principal) { Specification spec = Specification.allOf(); @@ -94,25 +94,47 @@ public Property findById(long id) { @Override public Property createProperty(PropertyRequest propertyRequest, Principal principal) { - var owner = memberService.findByEmail(principal.getName()); + if (owner.getRoles().stream().noneMatch(r -> Objects.equals(r.getName(), "Owner"))) { + throw new PlatformException("Only owner role is allowed to create a property", HttpStatus.BAD_REQUEST); + } + var requestProp = Util.mapObj(propertyRequest, Property.class); requestProp.setOwner(owner); var prop = propertyRepo.save(requestProp); - var keys = propertyRequest.getPictures(); - if (!keys.isEmpty()) { - var pics = keys.stream().map(key -> { - var pic = picService.findByKey(key); - pic.setProperty(prop); - return pic; - }).toList(); - picRepo.saveAll(pics); - prop.setPictures(pics); - } + var pics = picService.updateByProperty(prop, propertyRequest.getPictures()); + prop.setPictures(pics); return prop; } + + @Override + + public Property updateProperty(long id, PropertyRequest propertyRequest, Principal principal) { + var prop = findById(id); + + if (!prop.getOwner().getEmail().equals(principal.getName())) { + throw new PlatformException("Invalid Property's Owner", HttpStatus.BAD_REQUEST); + } + + prop.setTitle(propertyRequest.getTitle()); + prop.setPrice(propertyRequest.getPrice()); + prop.setLocation(propertyRequest.getLocation()); + prop.setDescription(propertyRequest.getDescription()); + prop.setCategory(propertyRequest.getCategory()); + prop.setSubCategory(propertyRequest.getSubCategory()); + prop.setType(propertyRequest.getType()); + prop.setNumberOfRoom(propertyRequest.getNumberOfRoom()); + prop.setLatitude(propertyRequest.getLatitude()); + prop.setLongitude(propertyRequest.getLongitude()); + + + var pics = picService.updateByProperty(prop, propertyRequest.getPictures()); + prop.setPictures(pics); + + return propertyRepo.save(prop); + } } diff --git a/backend/pms/src/main/resources/application.yml b/backend/pms/src/main/resources/application.yml index 0ccbea8..ff8732b 100644 --- a/backend/pms/src/main/resources/application.yml +++ b/backend/pms/src/main/resources/application.yml @@ -46,4 +46,4 @@ management: jwt: secret: ${JWT_SECRET:1234} mail: - enabled: ${ENABLED:true} \ No newline at end of file + enabled: ${ENABLED:false} \ No newline at end of file