From 0a63381bed786e32c7fe7bd7cb98f7f2f8493d20 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Fri, 28 Jun 2024 15:32:19 +0900 Subject: [PATCH 01/21] =?UTF-8?q?feat(session):=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=EC=82=AC=EC=A7=84=20=EA=B0=AF=EC=88=98=20=EC=A6=9D=EA=B0=80?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SessionPhoto 테이블을 Session과 양방향 매핑으로 구축 --- .../domain/generation/entity/Session.java | 6 +++ .../generation/entity/SessionPhoto.java | 46 +++++++++++++++++++ .../repository/SessionPhotoRepository.java | 13 ++++++ 3 files changed, 65 insertions(+) create mode 100644 src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java create mode 100644 src/main/java/org/cotato/csquiz/domain/generation/repository/SessionPhotoRepository.java diff --git a/src/main/java/org/cotato/csquiz/domain/generation/entity/Session.java b/src/main/java/org/cotato/csquiz/domain/generation/entity/Session.java index 847563d1..68a9aa65 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/entity/Session.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/entity/Session.java @@ -12,6 +12,9 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import java.util.ArrayList; +import java.util.List; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -38,6 +41,9 @@ public class Session extends BaseTimeEntity { @Column(name = "session_title", length = 100) private String title; + @OneToMany(mappedBy = "session", orphanRemoval = true) + private List sessionPhotos = new ArrayList<>(); + @Embedded private S3Info photoS3Info; diff --git a/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java b/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java new file mode 100644 index 00000000..53c77927 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java @@ -0,0 +1,46 @@ +package org.cotato.csquiz.domain.generation.entity; + +import static jakarta.persistence.FetchType.LAZY; + +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.cotato.csquiz.common.entity.BaseTimeEntity; +import org.cotato.csquiz.common.entity.S3Info; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class SessionPhoto extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "session_image_id") + private Long id; + + @Embedded + private S3Info s3Info; + + @Column(name = "session_image_order") + private Integer order; + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "session_id") + private Session session; + + @Builder + public SessionPhoto(Session session, Integer order, S3Info s3Info) { + this.session = session; + this.order = order; + this.s3Info = s3Info; + } +} diff --git a/src/main/java/org/cotato/csquiz/domain/generation/repository/SessionPhotoRepository.java b/src/main/java/org/cotato/csquiz/domain/generation/repository/SessionPhotoRepository.java new file mode 100644 index 00000000..c14d607d --- /dev/null +++ b/src/main/java/org/cotato/csquiz/domain/generation/repository/SessionPhotoRepository.java @@ -0,0 +1,13 @@ +package org.cotato.csquiz.domain.generation.repository; + +import java.util.List; +import java.util.Optional; +import org.cotato.csquiz.domain.generation.entity.Session; +import org.cotato.csquiz.domain.generation.entity.SessionPhoto; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface SessionPhotoRepository extends JpaRepository { + List findAllBySession(Session session); + + Optional findFirstBySessionOrderByOrderDesc(Session session); +} From 3ac6c2455c8508b860fb987efa0f37bfb5239a28 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Fri, 28 Jun 2024 15:34:15 +0900 Subject: [PATCH 02/21] =?UTF-8?q?feat(session):=20=EC=84=B8=EC=85=98?= =?UTF-8?q?=EC=97=90=20=EC=B6=94=EA=B0=80=EB=A1=9C=20=EC=82=AC=EC=A7=84?= =?UTF-8?q?=EC=9D=84=20=EC=A0=80=EC=9E=A5=ED=95=98=EB=8A=94=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../session/controller/SessionController.java | 9 ++++++ .../session/dto/AddSessionPhotoRequest.java | 13 +++++++++ .../session/dto/AddSessionPhotoResponse.java | 14 +++++++++ .../generation/service/SessionService.java | 29 +++++++++++++++++++ 4 files changed, 65 insertions(+) create mode 100644 src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoRequest.java create mode 100644 src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoResponse.java diff --git a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java index 7b7bfdac..0768aa8d 100644 --- a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java +++ b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java @@ -4,6 +4,8 @@ import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.cotato.csquiz.api.session.dto.AddSessionPhotoRequest; +import org.cotato.csquiz.api.session.dto.AddSessionPhotoResponse; import org.cotato.csquiz.api.session.dto.AddSessionRequest; import org.cotato.csquiz.api.session.dto.AddSessionResponse; import org.cotato.csquiz.api.session.dto.CsEducationOnSessionNumberResponse; @@ -70,6 +72,13 @@ public ResponseEntity updateSessionPhoto(@ModelAttribute @Valid UpdateSess return ResponseEntity.noContent().build(); } + @PostMapping(value = "/add/photo", consumes = "multipart/form-data") + public ResponseEntity additionalSessionPhoto(@ModelAttribute @Valid AddSessionPhotoRequest request) + throws ImageException { + + return ResponseEntity.status(HttpStatus.CREATED).body(sessionService.additionalSessionPhoto(request)); + } + @GetMapping("/cs-on") public ResponseEntity> findAllCsOnSessionsByGenerationId( @RequestParam Long generationId) { diff --git a/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoRequest.java b/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoRequest.java new file mode 100644 index 00000000..4f6f8c2d --- /dev/null +++ b/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoRequest.java @@ -0,0 +1,13 @@ +package org.cotato.csquiz.api.session.dto; + +import jakarta.validation.constraints.NotNull; +import org.springframework.web.multipart.MultipartFile; + +public record AddSessionPhotoRequest( + + @NotNull + Long sessionId, + @NotNull + MultipartFile sessionImage +) { +} diff --git a/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoResponse.java b/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoResponse.java new file mode 100644 index 00000000..3e694fb1 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoResponse.java @@ -0,0 +1,14 @@ +package org.cotato.csquiz.api.session.dto; + +import jakarta.validation.constraints.NotNull; +import org.cotato.csquiz.domain.generation.entity.SessionPhoto; +import org.springframework.web.multipart.MultipartFile; + +public record AddSessionPhotoResponse( + @NotNull + Long photoId +) { + public static AddSessionPhotoResponse from(SessionPhoto sessionPhoto) { + return new AddSessionPhotoResponse(sessionPhoto.getId()); + } +} diff --git a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java index f6525bfe..4a42b41f 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java @@ -4,6 +4,9 @@ import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.cotato.csquiz.api.session.dto.AddSessionPhotoResponse; +import org.cotato.csquiz.api.session.dto.UpdateSessionPhotoOrderRequest; +import org.cotato.csquiz.api.session.dto.AddSessionPhotoRequest; import org.cotato.csquiz.api.session.dto.AddSessionRequest; import org.cotato.csquiz.api.session.dto.AddSessionResponse; import org.cotato.csquiz.api.session.dto.CsEducationOnSessionNumberResponse; @@ -16,12 +19,14 @@ import org.cotato.csquiz.domain.education.entity.Education; import org.cotato.csquiz.domain.education.service.EducationService; import org.cotato.csquiz.domain.generation.embedded.SessionContents; +import org.cotato.csquiz.domain.generation.entity.SessionPhoto; import org.cotato.csquiz.domain.generation.enums.CSEducation; import org.cotato.csquiz.domain.generation.entity.Generation; import org.cotato.csquiz.domain.generation.entity.Session; import org.cotato.csquiz.common.error.exception.ImageException; import org.cotato.csquiz.common.S3.S3Uploader; import org.cotato.csquiz.domain.generation.repository.GenerationRepository; +import org.cotato.csquiz.domain.generation.repository.SessionPhotoRepository; import org.cotato.csquiz.domain.generation.repository.SessionRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -36,6 +41,7 @@ public class SessionService { private static final String SESSION_BUCKET_DIRECTORY = "session"; private final SessionRepository sessionRepository; private final GenerationRepository generationRepository; + private final SessionPhotoRepository sessionPhotoRepository; private final EducationService educationService; private final S3Uploader s3Uploader; @@ -112,6 +118,29 @@ public void updateSessionPhoto(UpdateSessionPhotoRequest request) throws ImageEx updatePhoto(session, request.sessionImage()); } + @Transactional + public AddSessionPhotoResponse additionalSessionPhoto(AddSessionPhotoRequest request) throws ImageException { + Session session = findSessionById(request.sessionId()); + + S3Info imageInfo = s3Uploader.uploadFiles(request.sessionImage(), "session"); + + Integer imageOrder = sessionPhotoRepository.findFirstBySessionOrderByOrderDesc(session) + .map(sessionPhoto -> sessionPhoto.getOrder() + 1).orElse(1); + + SessionPhoto sessionPhoto = SessionPhoto.builder() + .session(session) + .s3Info(imageInfo) + .order(imageOrder) + .build(); + + return AddSessionPhotoResponse.from(sessionPhotoRepository.save(sessionPhoto)); + } + + @Transactional + public void updateSessionPhotoOrder(UpdateSessionPhotoOrderRequest request) { + + } + private void updatePhoto(Session session, MultipartFile sessionImage) throws ImageException { if (isImageExist(sessionImage)) { S3Info s3Info = s3Uploader.uploadFiles(sessionImage, SESSION_BUCKET_DIRECTORY); From 5c71ca3cb8c14ee882b2f541265b583c400c3883 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Fri, 28 Jun 2024 15:34:51 +0900 Subject: [PATCH 03/21] =?UTF-8?q?feat(session):=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=EC=82=AC=EC=A7=84=20=EC=88=9C=EC=84=9C=EC=9D=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 진행중 --- .../api/session/controller/SessionController.java | 1 + .../session/dto/UpdateSessionPhotoOrderRequest.java | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionPhotoOrderRequest.java diff --git a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java index 0768aa8d..ffe32912 100644 --- a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java +++ b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java @@ -12,6 +12,7 @@ import org.cotato.csquiz.api.session.dto.SessionListResponse; import org.cotato.csquiz.api.session.dto.UpdateSessionDescriptionRequest; import org.cotato.csquiz.api.session.dto.UpdateSessionNumberRequest; +import org.cotato.csquiz.api.session.dto.UpdateSessionPhotoOrderRequest; import org.cotato.csquiz.api.session.dto.UpdateSessionPhotoRequest; import org.cotato.csquiz.api.session.dto.UpdateSessionRequest; import org.cotato.csquiz.domain.generation.service.SessionService; diff --git a/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionPhotoOrderRequest.java b/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionPhotoOrderRequest.java new file mode 100644 index 00000000..bcf18581 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionPhotoOrderRequest.java @@ -0,0 +1,11 @@ +package org.cotato.csquiz.api.session.dto; + +import jakarta.validation.constraints.NotNull; + +public record UpdateSessionPhotoOrderRequest( + @NotNull + Long photoId, + @NotNull + Integer order +) { +} From 9f43414d62e16604ada5307f664c3a317001b270 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Fri, 28 Jun 2024 16:39:02 +0900 Subject: [PATCH 04/21] =?UTF-8?q?feat:=20=EC=84=B8=EC=85=98=20=EB=82=B4=20?= =?UTF-8?q?=EC=82=AC=EC=A7=84=EC=9D=98=20=EC=88=9C=EC=84=9C=EB=A5=BC=20?= =?UTF-8?q?=EB=B0=94=EA=BE=B8=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../session/controller/SessionController.java | 7 ++++- .../UpdateSessionPhotoOrderInfoRequest.java | 11 +++++++ .../dto/UpdateSessionPhotoOrderRequest.java | 8 ++--- .../cotato/csquiz/common/error/ErrorCode.java | 2 ++ .../generation/entity/SessionPhoto.java | 4 +++ .../generation/service/SessionService.java | 29 +++++++++++++++++++ 6 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionPhotoOrderInfoRequest.java diff --git a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java index ffe32912..271bff7f 100644 --- a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java +++ b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java @@ -73,10 +73,15 @@ public ResponseEntity updateSessionPhoto(@ModelAttribute @Valid UpdateSess return ResponseEntity.noContent().build(); } + @PatchMapping("/update/photo/order") + public ResponseEntity updateSessionPhotoOrder(UpdateSessionPhotoOrderRequest request) { + sessionService.updateSessionPhotoOrder(request); + return ResponseEntity.noContent().build(); + } + @PostMapping(value = "/add/photo", consumes = "multipart/form-data") public ResponseEntity additionalSessionPhoto(@ModelAttribute @Valid AddSessionPhotoRequest request) throws ImageException { - return ResponseEntity.status(HttpStatus.CREATED).body(sessionService.additionalSessionPhoto(request)); } diff --git a/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionPhotoOrderInfoRequest.java b/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionPhotoOrderInfoRequest.java new file mode 100644 index 00000000..a0554184 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionPhotoOrderInfoRequest.java @@ -0,0 +1,11 @@ +package org.cotato.csquiz.api.session.dto; + +import jakarta.validation.constraints.NotNull; + +public record UpdateSessionPhotoOrderInfoRequest( + @NotNull + Long photoId, + @NotNull + Integer order +) { +} diff --git a/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionPhotoOrderRequest.java b/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionPhotoOrderRequest.java index bcf18581..73d487d9 100644 --- a/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionPhotoOrderRequest.java +++ b/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionPhotoOrderRequest.java @@ -1,11 +1,9 @@ package org.cotato.csquiz.api.session.dto; -import jakarta.validation.constraints.NotNull; +import java.util.List; public record UpdateSessionPhotoOrderRequest( - @NotNull - Long photoId, - @NotNull - Integer order + Long sessionId, + List orderInfos ) { } diff --git a/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java b/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java index c1258a05..3fbe64ff 100644 --- a/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java +++ b/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java @@ -69,6 +69,8 @@ public enum ErrorCode { IMAGE_DELETE_FAIL(HttpStatus.INTERNAL_SERVER_ERROR, "S-003", "s3 이미지 삭제처리를 실패했습니다"), INTERNAL_SQL_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "S-004", "SQL 관련 에러 발생"), ENUM_NOT_RESOLVED(HttpStatus.BAD_REQUEST, "S-005", "입력한 Enum이 존재하지 않습니다."), + SESSION_PHOTO_COUNT_MISMATCH(HttpStatus.BAD_REQUEST, "S-006", "저장된 사진 수와 요청 사진 수가 다릅니다."), + SESSION_PHOTO_NOT_EXIST(HttpStatus.BAD_REQUEST, "S-007", "저장되지 않은 사진에 대한 요청이 있습니다") ; private final HttpStatus httpStatus; diff --git a/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java b/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java index 53c77927..d08fb454 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java @@ -43,4 +43,8 @@ public SessionPhoto(Session session, Integer order, S3Info s3Info) { this.order = order; this.s3Info = s3Info; } + + public void updateOrder(Integer order) { + this.order = order; + } } diff --git a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java index 4a42b41f..07d85150 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java @@ -2,9 +2,13 @@ import jakarta.persistence.EntityNotFoundException; import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.cotato.csquiz.api.session.dto.AddSessionPhotoResponse; +import org.cotato.csquiz.api.session.dto.UpdateSessionPhotoOrderInfoRequest; import org.cotato.csquiz.api.session.dto.UpdateSessionPhotoOrderRequest; import org.cotato.csquiz.api.session.dto.AddSessionPhotoRequest; import org.cotato.csquiz.api.session.dto.AddSessionRequest; @@ -16,6 +20,8 @@ import org.cotato.csquiz.api.session.dto.UpdateSessionPhotoRequest; import org.cotato.csquiz.api.session.dto.UpdateSessionRequest; import org.cotato.csquiz.common.entity.S3Info; +import org.cotato.csquiz.common.error.ErrorCode; +import org.cotato.csquiz.common.error.exception.AppException; import org.cotato.csquiz.domain.education.entity.Education; import org.cotato.csquiz.domain.education.service.EducationService; import org.cotato.csquiz.domain.generation.embedded.SessionContents; @@ -138,7 +144,30 @@ public AddSessionPhotoResponse additionalSessionPhoto(AddSessionPhotoRequest req @Transactional public void updateSessionPhotoOrder(UpdateSessionPhotoOrderRequest request) { + Session session = findSessionById(request.sessionId()); + List orderList = request.orderInfos(); + + List savedPhotos = sessionPhotoRepository.findAllBySession(session); + + if (savedPhotos.size() != orderList.size()) { + throw new AppException(ErrorCode.SESSION_PHOTO_COUNT_MISMATCH); + } + + Map orderMap = orderList.stream() + .collect(Collectors.toMap(UpdateSessionPhotoOrderInfoRequest::photoId, Function.identity())); + savedPhotos.forEach(sessionPhoto -> { + updatePhotoOrder(sessionPhoto, orderMap); + }); + } + + private static void updatePhotoOrder(SessionPhoto sessionPhoto, Map orderMap) { + UpdateSessionPhotoOrderInfoRequest orderInfo = orderMap.get(sessionPhoto.getId()); + + if (orderInfo == null) { + throw new AppException(ErrorCode.SESSION_PHOTO_NOT_EXIST); + } + sessionPhoto.updateOrder(orderInfo.order()); } private void updatePhoto(Session session, MultipartFile sessionImage) throws ImageException { From d724646473be258bf6b1324078a00469072d382f Mon Sep 17 00:00:00 2001 From: gikhoon Date: Fri, 28 Jun 2024 17:10:26 +0900 Subject: [PATCH 05/21] =?UTF-8?q?feat:=20=EC=84=B8=EC=85=98=20=EC=82=AC?= =?UTF-8?q?=EC=A7=84=20=EC=88=9C=EC=84=9C=20=EC=88=98=EC=A0=95=20=EC=8B=9C?= =?UTF-8?q?=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 순서가 0 이하거나 총 저장 사진보다 클 경우 예외 발생 --- .../csquiz/api/session/controller/SessionController.java | 2 +- .../java/org/cotato/csquiz/common/error/ErrorCode.java | 3 ++- .../csquiz/domain/generation/service/SessionService.java | 8 ++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java index 271bff7f..e02361b1 100644 --- a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java +++ b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java @@ -74,7 +74,7 @@ public ResponseEntity updateSessionPhoto(@ModelAttribute @Valid UpdateSess } @PatchMapping("/update/photo/order") - public ResponseEntity updateSessionPhotoOrder(UpdateSessionPhotoOrderRequest request) { + public ResponseEntity updateSessionPhotoOrder(@RequestBody UpdateSessionPhotoOrderRequest request) { sessionService.updateSessionPhotoOrder(request); return ResponseEntity.noContent().build(); } diff --git a/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java b/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java index 3fbe64ff..3349b362 100644 --- a/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java +++ b/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java @@ -70,7 +70,8 @@ public enum ErrorCode { INTERNAL_SQL_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "S-004", "SQL 관련 에러 발생"), ENUM_NOT_RESOLVED(HttpStatus.BAD_REQUEST, "S-005", "입력한 Enum이 존재하지 않습니다."), SESSION_PHOTO_COUNT_MISMATCH(HttpStatus.BAD_REQUEST, "S-006", "저장된 사진 수와 요청 사진 수가 다릅니다."), - SESSION_PHOTO_NOT_EXIST(HttpStatus.BAD_REQUEST, "S-007", "저장되지 않은 사진에 대한 요청이 있습니다") + SESSION_PHOTO_NOT_EXIST(HttpStatus.BAD_REQUEST, "S-007", "저장되지 않은 사진에 대한 요청이 있습니다."), + SESSION_ORDER_INVALID(HttpStatus.BAD_REQUEST, "S-008", "입력한 순서는 유효하지 않습니다."), ; private final HttpStatus httpStatus; diff --git a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java index 07d85150..50e23a96 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java @@ -154,6 +154,7 @@ public void updateSessionPhotoOrder(UpdateSessionPhotoOrderRequest request) { } Map orderMap = orderList.stream() + .filter(orderInfo -> isOrderValid(orderInfo,savedPhotos.size())) .collect(Collectors.toMap(UpdateSessionPhotoOrderInfoRequest::photoId, Function.identity())); savedPhotos.forEach(sessionPhoto -> { @@ -161,6 +162,13 @@ public void updateSessionPhotoOrder(UpdateSessionPhotoOrderRequest request) { }); } + private boolean isOrderValid(UpdateSessionPhotoOrderInfoRequest orderInfo, int totalSize) { + if (orderInfo.order() < 1 || orderInfo.order() > totalSize) { + throw new AppException(ErrorCode.SESSION_ORDER_INVALID); + } + return true; + } + private static void updatePhotoOrder(SessionPhoto sessionPhoto, Map orderMap) { UpdateSessionPhotoOrderInfoRequest orderInfo = orderMap.get(sessionPhoto.getId()); From 27ae182ab428bed3af3ab6e8ff63f51574da1227 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Wed, 3 Jul 2024 17:41:43 +0900 Subject: [PATCH 06/21] =?UTF-8?q?feat:=20=EC=82=AC=EC=A7=84=20=ED=95=9C?= =?UTF-8?q?=EC=9E=A5=20=EC=82=AD=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../csquiz/api/session/controller/SessionController.java | 8 ++++++++ .../api/session/dto/DeleteSessionPhotoRequest.java | 9 +++++++++ .../csquiz/domain/generation/service/SessionService.java | 9 +++++++++ 3 files changed, 26 insertions(+) create mode 100644 src/main/java/org/cotato/csquiz/api/session/dto/DeleteSessionPhotoRequest.java diff --git a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java index e02361b1..7d303937 100644 --- a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java +++ b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java @@ -9,6 +9,7 @@ import org.cotato.csquiz.api.session.dto.AddSessionRequest; import org.cotato.csquiz.api.session.dto.AddSessionResponse; import org.cotato.csquiz.api.session.dto.CsEducationOnSessionNumberResponse; +import org.cotato.csquiz.api.session.dto.DeleteSessionPhotoRequest; import org.cotato.csquiz.api.session.dto.SessionListResponse; import org.cotato.csquiz.api.session.dto.UpdateSessionDescriptionRequest; import org.cotato.csquiz.api.session.dto.UpdateSessionNumberRequest; @@ -19,6 +20,7 @@ import org.cotato.csquiz.common.error.exception.ImageException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PatchMapping; @@ -85,6 +87,12 @@ public ResponseEntity additionalSessionPhoto(@ModelAttr return ResponseEntity.status(HttpStatus.CREATED).body(sessionService.additionalSessionPhoto(request)); } + @DeleteMapping(value = "/delete/photo") + public ResponseEntity deleteSessionPhoto(@RequestBody DeleteSessionPhotoRequest request) { + sessionService.deleteSessionPhoto(request); + return ResponseEntity.noContent().build(); + } + @GetMapping("/cs-on") public ResponseEntity> findAllCsOnSessionsByGenerationId( @RequestParam Long generationId) { diff --git a/src/main/java/org/cotato/csquiz/api/session/dto/DeleteSessionPhotoRequest.java b/src/main/java/org/cotato/csquiz/api/session/dto/DeleteSessionPhotoRequest.java new file mode 100644 index 00000000..aa254a1c --- /dev/null +++ b/src/main/java/org/cotato/csquiz/api/session/dto/DeleteSessionPhotoRequest.java @@ -0,0 +1,9 @@ +package org.cotato.csquiz.api.session.dto; + +import jakarta.validation.constraints.NotNull; + +public record DeleteSessionPhotoRequest( + @NotNull + Long photoId +) { +} diff --git a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java index 50e23a96..fdec1c06 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java @@ -8,6 +8,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.cotato.csquiz.api.session.dto.AddSessionPhotoResponse; +import org.cotato.csquiz.api.session.dto.DeleteSessionPhotoRequest; import org.cotato.csquiz.api.session.dto.UpdateSessionPhotoOrderInfoRequest; import org.cotato.csquiz.api.session.dto.UpdateSessionPhotoOrderRequest; import org.cotato.csquiz.api.session.dto.AddSessionPhotoRequest; @@ -142,6 +143,14 @@ public AddSessionPhotoResponse additionalSessionPhoto(AddSessionPhotoRequest req return AddSessionPhotoResponse.from(sessionPhotoRepository.save(sessionPhoto)); } + @Transactional + public void deleteSessionPhoto(DeleteSessionPhotoRequest request) { + SessionPhoto sessionPhoto = sessionPhotoRepository.findById(request.photoId()) + .orElseThrow(() -> new EntityNotFoundException("해당 사진을 찾을 수 없습니다.")); + s3Uploader.deleteFile(sessionPhoto.getS3Info()); + sessionPhotoRepository.delete(sessionPhoto); + } + @Transactional public void updateSessionPhotoOrder(UpdateSessionPhotoOrderRequest request) { Session session = findSessionById(request.sessionId()); From 62e80b53f978d9d26b1c194bfca0ffe9a9c5854d Mon Sep 17 00:00:00 2001 From: gikhoon Date: Wed, 3 Jul 2024 18:10:06 +0900 Subject: [PATCH 07/21] =?UTF-8?q?feat:=20=EC=84=B8=EC=85=98=20=EC=82=AC?= =?UTF-8?q?=EC=A7=84=20=EC=A6=9D=EA=B0=80=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=EC=84=B8=EC=85=98=EC=B6=94=EA=B0=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/session/dto/AddSessionRequest.java | 3 +- .../generation/service/SessionService.java | 32 +++++++++++++++---- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionRequest.java b/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionRequest.java index a8f10f0d..019e88de 100644 --- a/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionRequest.java +++ b/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionRequest.java @@ -1,5 +1,6 @@ package org.cotato.csquiz.api.session.dto; +import java.util.List; import org.cotato.csquiz.domain.generation.enums.CSEducation; import org.cotato.csquiz.domain.generation.enums.DevTalk; import org.cotato.csquiz.domain.generation.enums.ItIssue; @@ -10,7 +11,7 @@ public record AddSessionRequest( @NotNull Long generationId, - MultipartFile sessionImage, + List sessionImages, @NotNull String title, @NotNull diff --git a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java index fdec1c06..1056917e 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java @@ -3,6 +3,8 @@ import jakarta.persistence.EntityNotFoundException; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; @@ -53,11 +55,7 @@ public class SessionService { private final S3Uploader s3Uploader; @Transactional - public AddSessionResponse addSession(AddSessionRequest request) throws ImageException { - S3Info s3Info = null; - if (isImageExist(request.sessionImage())) { - s3Info = s3Uploader.uploadFiles(request.sessionImage(), SESSION_BUCKET_DIRECTORY); - } + public AddSessionResponse addSession(AddSessionRequest request) { Generation findGeneration = generationRepository.findById(request.generationId()) .orElseThrow(() -> new EntityNotFoundException("해당 기수를 찾을 수 없습니다.")); @@ -65,7 +63,6 @@ public AddSessionResponse addSession(AddSessionRequest request) throws ImageExce log.info("해당 기수에 추가된 마지막 세션 : {}", sessionNumber); Session session = Session.builder() .number(sessionNumber + 1) - .s3Info(s3Info) .description(request.description()) .generation(findGeneration) .title(request.title()) @@ -79,9 +76,32 @@ public AddSessionResponse addSession(AddSessionRequest request) throws ImageExce Session savedSession = sessionRepository.save(session); log.info("세션 생성 완료"); + AtomicInteger index = new AtomicInteger(1); + List sessionPhotos = request.sessionImages().stream() + .map(this::uploadFile) + .filter(Objects::nonNull) + .map(s3Info -> SessionPhoto.builder() + .session(savedSession) + .s3Info(s3Info) + .order(index.getAndIncrement()) + .build()) + .toList(); + + sessionPhotoRepository.saveAll(sessionPhotos); + log.info("세션 이미지 생성 완료"); + return AddSessionResponse.from(savedSession); } + private S3Info uploadFile(MultipartFile file) { + try { + return s3Uploader.uploadFiles(file, SESSION_BUCKET_DIRECTORY); + } catch (ImageException e) { + log.error("이미지 업로드 문제 발생" + e.getMessage()); + } + return null; + } + private int calculateLastSessionNumber(Generation generation) { List allSession = sessionRepository.findAllByGeneration(generation); return allSession.stream().mapToInt(Session::getNumber).max() From eb4a984a6e4bc6d043225bdb65ae832ef4e37764 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Wed, 3 Jul 2024 21:42:51 +0900 Subject: [PATCH 08/21] =?UTF-8?q?feat(Session):=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=EC=82=AC=EC=A7=84=20=EC=82=AD=EC=A0=9C=EC=8B=9C=20=EC=88=9C?= =?UTF-8?q?=EC=84=9C=20=EC=9E=AC=EC=A0=95=EB=A0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/session/controller/SessionController.java | 9 +++++++-- .../csquiz/domain/generation/entity/SessionPhoto.java | 4 ++++ .../domain/generation/service/SessionService.java | 10 +++++++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java index 7d303937..e593b942 100644 --- a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java +++ b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java @@ -1,5 +1,7 @@ package org.cotato.csquiz.api.session.controller; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import java.util.List; import lombok.RequiredArgsConstructor; @@ -43,9 +45,9 @@ public ResponseEntity> findSessionsByGenerationId(@Req return ResponseEntity.status(HttpStatus.OK).body(sessionService.findSessionsByGenerationId(generationId)); } + @Operation(summary = "Session 추가하기", description = "세션 추가하기") @PostMapping(value = "/add", consumes = "multipart/form-data") - public ResponseEntity addSession(@ModelAttribute @Valid AddSessionRequest request) - throws ImageException { + public ResponseEntity addSession(@ModelAttribute @Valid AddSessionRequest request) { return ResponseEntity.status(HttpStatus.CREATED).body(sessionService.addSession(request)); } @@ -75,18 +77,21 @@ public ResponseEntity updateSessionPhoto(@ModelAttribute @Valid UpdateSess return ResponseEntity.noContent().build(); } + @Operation(summary = "Session 사진 순서 수정", description = "세션 사진 순서 바꾸기") @PatchMapping("/update/photo/order") public ResponseEntity updateSessionPhotoOrder(@RequestBody UpdateSessionPhotoOrderRequest request) { sessionService.updateSessionPhotoOrder(request); return ResponseEntity.noContent().build(); } + @Operation(summary = "Session 수정 - 사진 추가하기", description = "세션 수정 시 사진 추가하기, photoId 반환") @PostMapping(value = "/add/photo", consumes = "multipart/form-data") public ResponseEntity additionalSessionPhoto(@ModelAttribute @Valid AddSessionPhotoRequest request) throws ImageException { return ResponseEntity.status(HttpStatus.CREATED).body(sessionService.additionalSessionPhoto(request)); } + @Operation(summary = "Session 수정 - 사진 삭제하기", description = "사진 삭제하기") @DeleteMapping(value = "/delete/photo") public ResponseEntity deleteSessionPhoto(@RequestBody DeleteSessionPhotoRequest request) { sessionService.deleteSessionPhoto(request); diff --git a/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java b/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java index d08fb454..31228191 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java @@ -47,4 +47,8 @@ public SessionPhoto(Session session, Integer order, S3Info s3Info) { public void updateOrder(Integer order) { this.order = order; } + + public void decreaseOrder() { + this.order--; + } } diff --git a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java index 1056917e..45c5c238 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java @@ -165,10 +165,14 @@ public AddSessionPhotoResponse additionalSessionPhoto(AddSessionPhotoRequest req @Transactional public void deleteSessionPhoto(DeleteSessionPhotoRequest request) { - SessionPhoto sessionPhoto = sessionPhotoRepository.findById(request.photoId()) + SessionPhoto deletePhoto = sessionPhotoRepository.findById(request.photoId()) .orElseThrow(() -> new EntityNotFoundException("해당 사진을 찾을 수 없습니다.")); - s3Uploader.deleteFile(sessionPhoto.getS3Info()); - sessionPhotoRepository.delete(sessionPhoto); + s3Uploader.deleteFile(deletePhoto.getS3Info()); + sessionPhotoRepository.delete(deletePhoto); + + sessionPhotoRepository.findAllBySession(deletePhoto.getSession()).stream() + .filter(photo -> photo.getOrder() > deletePhoto.getOrder()) + .forEach(SessionPhoto::decreaseOrder); } @Transactional From a8b91b212dc067b5fcf5102575ea31b2fed18591 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Wed, 3 Jul 2024 21:50:43 +0900 Subject: [PATCH 09/21] =?UTF-8?q?feat(Session):=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20-=20=EC=82=AC=EC=A7=84=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EC=8B=9C=20=EC=9D=91=EB=8B=B5=20=ED=95=AD=EB=AA=A9?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - url, 순서 추가 --- .../api/session/controller/SessionController.java | 2 +- .../api/session/dto/AddSessionPhotoResponse.java | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java index e593b942..931f7f69 100644 --- a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java +++ b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java @@ -77,7 +77,7 @@ public ResponseEntity updateSessionPhoto(@ModelAttribute @Valid UpdateSess return ResponseEntity.noContent().build(); } - @Operation(summary = "Session 사진 순서 수정", description = "세션 사진 순서 바꾸기") + @Operation(summary = "Session 수정 - 사진 순서", description = "세션 사진 순서 바꾸기") @PatchMapping("/update/photo/order") public ResponseEntity updateSessionPhotoOrder(@RequestBody UpdateSessionPhotoOrderRequest request) { sessionService.updateSessionPhotoOrder(request); diff --git a/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoResponse.java b/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoResponse.java index 3e694fb1..5910f5b1 100644 --- a/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoResponse.java +++ b/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoResponse.java @@ -6,9 +6,15 @@ public record AddSessionPhotoResponse( @NotNull - Long photoId + Long photoId, + @NotNull + String photoUrl, + @NotNull + Integer order ) { public static AddSessionPhotoResponse from(SessionPhoto sessionPhoto) { - return new AddSessionPhotoResponse(sessionPhoto.getId()); + return new AddSessionPhotoResponse(sessionPhoto.getId(), + sessionPhoto.getS3Info().getUrl(), + sessionPhoto.getOrder()); } } From e51336ca71e52e3fce95c7667b44940d412879cc Mon Sep 17 00:00:00 2001 From: gikhoon Date: Wed, 3 Jul 2024 22:10:13 +0900 Subject: [PATCH 10/21] =?UTF-8?q?feat(Session):=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=EC=82=AC=EC=A7=84=20=EA=B0=AF=EC=88=98=20=EC=A6=9D=EA=B0=80?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=84=B8=EC=85=98=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=A0=95=EB=B3=B4=20=EB=B0=98=ED=99=98=20?= =?UTF-8?q?=ED=95=AD=EB=AA=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../session/controller/SessionController.java | 1 + .../dto/SessionListPhotoInfoResponse.java | 26 +++++++++++++++++++ .../api/session/dto/SessionListResponse.java | 5 ++-- .../generation/entity/SessionPhoto.java | 2 ++ 4 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/cotato/csquiz/api/session/dto/SessionListPhotoInfoResponse.java diff --git a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java index 931f7f69..4c777ab5 100644 --- a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java +++ b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java @@ -40,6 +40,7 @@ public class SessionController { private final SessionService sessionService; + @Operation(summary = "Session 리스트 정보 얻기", description = "Get Session Infos") @GetMapping("") public ResponseEntity> findSessionsByGenerationId(@RequestParam Long generationId) { return ResponseEntity.status(HttpStatus.OK).body(sessionService.findSessionsByGenerationId(generationId)); diff --git a/src/main/java/org/cotato/csquiz/api/session/dto/SessionListPhotoInfoResponse.java b/src/main/java/org/cotato/csquiz/api/session/dto/SessionListPhotoInfoResponse.java new file mode 100644 index 00000000..cea982e4 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/api/session/dto/SessionListPhotoInfoResponse.java @@ -0,0 +1,26 @@ +package org.cotato.csquiz.api.session.dto; + +import jakarta.validation.constraints.NotNull; +import java.util.List; +import org.cotato.csquiz.domain.generation.entity.SessionPhoto; + +public record SessionListPhotoInfoResponse( + @NotNull + Long photoId, + @NotNull + String photoUrl, + @NotNull + Integer order +) { + public static SessionListPhotoInfoResponse from(SessionPhoto sessionPhoto) { + return new SessionListPhotoInfoResponse(sessionPhoto.getId(), + sessionPhoto.getS3Info().getUrl(), + sessionPhoto.getOrder()); + } + + public static List from(List sessionPhotos) { + return sessionPhotos.stream() + .map(SessionListPhotoInfoResponse::from) + .toList(); + } +} diff --git a/src/main/java/org/cotato/csquiz/api/session/dto/SessionListResponse.java b/src/main/java/org/cotato/csquiz/api/session/dto/SessionListResponse.java index 987ecb8c..a8f0317e 100644 --- a/src/main/java/org/cotato/csquiz/api/session/dto/SessionListResponse.java +++ b/src/main/java/org/cotato/csquiz/api/session/dto/SessionListResponse.java @@ -1,5 +1,6 @@ package org.cotato.csquiz.api.session.dto; +import java.util.List; import org.cotato.csquiz.domain.generation.embedded.SessionContents; import org.cotato.csquiz.domain.generation.entity.Session; @@ -7,7 +8,7 @@ public record SessionListResponse( Long sessionId, Integer sessionNumber, String title, - String photoUrl, + List photoInfos, String description, Long generationId, SessionContents sessionContents @@ -17,7 +18,7 @@ public static SessionListResponse from(Session session) { session.getId(), session.getNumber(), session.getTitle(), - (session.getPhotoS3Info() != null) ? session.getPhotoS3Info().getUrl() : null, + SessionListPhotoInfoResponse.from(session.getSessionPhotos()), session.getDescription(), session.getGeneration().getId(), session.getSessionContents() diff --git a/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java b/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java index 31228191..f533e4ff 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java @@ -10,10 +10,12 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; +import java.util.List; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.cotato.csquiz.api.session.dto.SessionListPhotoInfoResponse; import org.cotato.csquiz.common.entity.BaseTimeEntity; import org.cotato.csquiz.common.entity.S3Info; From 89f3fadac6a785240826c10426edb849c363c834 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Wed, 3 Jul 2024 23:06:42 +0900 Subject: [PATCH 11/21] =?UTF-8?q?feat(Session):=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 사진 수정 로직 삭제 --- .../cotato/csquiz/api/session/dto/UpdateSessionRequest.java | 5 ----- .../csquiz/domain/generation/service/SessionService.java | 5 +---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionRequest.java b/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionRequest.java index 7044b43b..995566ec 100644 --- a/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionRequest.java +++ b/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionRequest.java @@ -5,14 +5,10 @@ import org.cotato.csquiz.domain.generation.enums.ItIssue; import org.cotato.csquiz.domain.generation.enums.Networking; import jakarta.validation.constraints.NotNull; -import org.springframework.web.multipart.MultipartFile; public record UpdateSessionRequest( @NotNull Long sessionId, - MultipartFile sessionImage, - @NotNull - Boolean isPhotoUpdated, String title, String description, @NotNull @@ -21,7 +17,6 @@ public record UpdateSessionRequest( Networking networking, @NotNull CSEducation csEducation, - @NotNull DevTalk devTalk ) { diff --git a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java index 45c5c238..c1c0a843 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java @@ -121,7 +121,7 @@ public void updateSessionDescription(UpdateSessionDescriptionRequest request) { } @Transactional - public void updateSession(UpdateSessionRequest request) throws ImageException { + public void updateSession(UpdateSessionRequest request) { Session session = findSessionById(request.sessionId()); session.updateDescription(request.description()); @@ -132,9 +132,6 @@ public void updateSession(UpdateSessionRequest request) throws ImageException { .itIssue(request.itIssue()) .networking(request.networking()) .build()); - if (request.isPhotoUpdated()) { - updatePhoto(session, request.sessionImage()); - } sessionRepository.save(session); } From 5bd360a320cb0da9d1ef38ef83ef87a8e3bc92bc Mon Sep 17 00:00:00 2001 From: gikhoon Date: Thu, 4 Jul 2024 00:14:56 +0900 Subject: [PATCH 12/21] =?UTF-8?q?feat(Session):=20=EC=9D=91=EB=8B=B5?= =?UTF-8?q?=EC=9D=98=20=EC=A0=9C=EC=95=BD=EC=A1=B0=EA=B1=B4=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cotato/csquiz/api/session/dto/AddSessionPhotoResponse.java | 3 --- .../csquiz/api/session/dto/SessionListPhotoInfoResponse.java | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoResponse.java b/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoResponse.java index 5910f5b1..6da92af3 100644 --- a/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoResponse.java +++ b/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoResponse.java @@ -5,11 +5,8 @@ import org.springframework.web.multipart.MultipartFile; public record AddSessionPhotoResponse( - @NotNull Long photoId, - @NotNull String photoUrl, - @NotNull Integer order ) { public static AddSessionPhotoResponse from(SessionPhoto sessionPhoto) { diff --git a/src/main/java/org/cotato/csquiz/api/session/dto/SessionListPhotoInfoResponse.java b/src/main/java/org/cotato/csquiz/api/session/dto/SessionListPhotoInfoResponse.java index cea982e4..4841e3ca 100644 --- a/src/main/java/org/cotato/csquiz/api/session/dto/SessionListPhotoInfoResponse.java +++ b/src/main/java/org/cotato/csquiz/api/session/dto/SessionListPhotoInfoResponse.java @@ -5,11 +5,8 @@ import org.cotato.csquiz.domain.generation.entity.SessionPhoto; public record SessionListPhotoInfoResponse( - @NotNull Long photoId, - @NotNull String photoUrl, - @NotNull Integer order ) { public static SessionListPhotoInfoResponse from(SessionPhoto sessionPhoto) { From a7a196863458ce3d9d81e30d9c574d52717e8ec5 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Thu, 4 Jul 2024 14:19:07 +0900 Subject: [PATCH 13/21] =?UTF-8?q?refactor:=20=EC=82=AC=EC=A7=84=20?= =?UTF-8?q?=EA=B0=AF=EC=88=98=20=EC=A6=9D=EA=B0=80=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EA=B8=B0=EC=A1=B4=20API=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - /description -> /update로 통합 - /update/photo -> POST DELETE /photo로 분화 --- .../api/session/controller/SessionController.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java index 4c777ab5..d5fea3c1 100644 --- a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java +++ b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java @@ -65,19 +65,6 @@ public ResponseEntity updateSessionNumber(@RequestBody @Valid UpdateSessio return ResponseEntity.noContent().build(); } - @PatchMapping("/description") - public ResponseEntity updateSessionDescription(@RequestBody @Valid UpdateSessionDescriptionRequest request) { - sessionService.updateSessionDescription(request); - return ResponseEntity.noContent().build(); - } - - @PatchMapping(value = "/update/photo", consumes = "multipart/form-data") - public ResponseEntity updateSessionPhoto(@ModelAttribute @Valid UpdateSessionPhotoRequest request) - throws ImageException { - sessionService.updateSessionPhoto(request); - return ResponseEntity.noContent().build(); - } - @Operation(summary = "Session 수정 - 사진 순서", description = "세션 사진 순서 바꾸기") @PatchMapping("/update/photo/order") public ResponseEntity updateSessionPhotoOrder(@RequestBody UpdateSessionPhotoOrderRequest request) { From e1e91fdf65643ba8596ccd5523fe3c9cef7831ad Mon Sep 17 00:00:00 2001 From: gikhoon Date: Thu, 4 Jul 2024 15:37:04 +0900 Subject: [PATCH 14/21] =?UTF-8?q?feat:=20=EC=BD=94=EB=93=9C=20=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=EB=A5=BC=20=EB=B0=94=ED=83=95=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../session/controller/SessionController.java | 9 ++- .../session/dto/AddSessionPhotoRequest.java | 2 +- .../api/session/dto/AddSessionRequest.java | 2 +- .../dto/UpdateSessionPhotoRequest.java | 2 +- .../generation/entity/SessionPhoto.java | 4 +- .../generation/service/SessionService.java | 69 +++++++++---------- 6 files changed, 41 insertions(+), 47 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java index d5fea3c1..f3fa2f75 100644 --- a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java +++ b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java @@ -53,8 +53,7 @@ public ResponseEntity addSession(@ModelAttribute @Valid AddS } @PatchMapping(value = "/update", consumes = "multipart/form-data") - public ResponseEntity updateSession(@ModelAttribute @Valid UpdateSessionRequest request) - throws ImageException { + public ResponseEntity updateSession(@RequestBody @Valid UpdateSessionRequest request) { sessionService.updateSession(request); return ResponseEntity.noContent().build(); } @@ -66,21 +65,21 @@ public ResponseEntity updateSessionNumber(@RequestBody @Valid UpdateSessio } @Operation(summary = "Session 수정 - 사진 순서", description = "세션 사진 순서 바꾸기") - @PatchMapping("/update/photo/order") + @PatchMapping("/photo/order") public ResponseEntity updateSessionPhotoOrder(@RequestBody UpdateSessionPhotoOrderRequest request) { sessionService.updateSessionPhotoOrder(request); return ResponseEntity.noContent().build(); } @Operation(summary = "Session 수정 - 사진 추가하기", description = "세션 수정 시 사진 추가하기, photoId 반환") - @PostMapping(value = "/add/photo", consumes = "multipart/form-data") + @PostMapping(value = "/photo", consumes = "multipart/form-data") public ResponseEntity additionalSessionPhoto(@ModelAttribute @Valid AddSessionPhotoRequest request) throws ImageException { return ResponseEntity.status(HttpStatus.CREATED).body(sessionService.additionalSessionPhoto(request)); } @Operation(summary = "Session 수정 - 사진 삭제하기", description = "사진 삭제하기") - @DeleteMapping(value = "/delete/photo") + @DeleteMapping(value = "/photo") public ResponseEntity deleteSessionPhoto(@RequestBody DeleteSessionPhotoRequest request) { sessionService.deleteSessionPhoto(request); return ResponseEntity.noContent().build(); diff --git a/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoRequest.java b/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoRequest.java index 4f6f8c2d..7fe1ee71 100644 --- a/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoRequest.java +++ b/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionPhotoRequest.java @@ -8,6 +8,6 @@ public record AddSessionPhotoRequest( @NotNull Long sessionId, @NotNull - MultipartFile sessionImage + MultipartFile photo ) { } diff --git a/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionRequest.java b/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionRequest.java index 019e88de..b266462f 100644 --- a/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionRequest.java +++ b/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionRequest.java @@ -11,7 +11,7 @@ public record AddSessionRequest( @NotNull Long generationId, - List sessionImages, + List photos, @NotNull String title, @NotNull diff --git a/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionPhotoRequest.java b/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionPhotoRequest.java index e11f7d15..4cddfcb3 100644 --- a/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionPhotoRequest.java +++ b/src/main/java/org/cotato/csquiz/api/session/dto/UpdateSessionPhotoRequest.java @@ -8,6 +8,6 @@ public record UpdateSessionPhotoRequest( @NotNull Long sessionId, - MultipartFile sessionImage + MultipartFile photo ) { } diff --git a/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java b/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java index f533e4ff..3f56179d 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java @@ -26,13 +26,13 @@ public class SessionPhoto extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "session_image_id") + @Column(name = "session_photo_id") private Long id; @Embedded private S3Info s3Info; - @Column(name = "session_image_order") + @Column(name = "session_photo_order") private Integer order; @ManyToOne(fetch = LAZY) diff --git a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java index c1c0a843..06b5c81b 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java @@ -1,9 +1,9 @@ package org.cotato.csquiz.domain.generation.service; import jakarta.persistence.EntityNotFoundException; +import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; @@ -18,9 +18,7 @@ import org.cotato.csquiz.api.session.dto.AddSessionResponse; import org.cotato.csquiz.api.session.dto.CsEducationOnSessionNumberResponse; import org.cotato.csquiz.api.session.dto.SessionListResponse; -import org.cotato.csquiz.api.session.dto.UpdateSessionDescriptionRequest; import org.cotato.csquiz.api.session.dto.UpdateSessionNumberRequest; -import org.cotato.csquiz.api.session.dto.UpdateSessionPhotoRequest; import org.cotato.csquiz.api.session.dto.UpdateSessionRequest; import org.cotato.csquiz.common.entity.S3Info; import org.cotato.csquiz.common.error.ErrorCode; @@ -61,6 +59,7 @@ public AddSessionResponse addSession(AddSessionRequest request) { int sessionNumber = calculateLastSessionNumber(findGeneration); log.info("해당 기수에 추가된 마지막 세션 : {}", sessionNumber); + Session session = Session.builder() .number(sessionNumber + 1) .description(request.description()) @@ -76,16 +75,20 @@ public AddSessionResponse addSession(AddSessionRequest request) { Session savedSession = sessionRepository.save(session); log.info("세션 생성 완료"); - AtomicInteger index = new AtomicInteger(1); - List sessionPhotos = request.sessionImages().stream() - .map(this::uploadFile) - .filter(Objects::nonNull) - .map(s3Info -> SessionPhoto.builder() + AtomicInteger index = new AtomicInteger(0); + List sessionPhotos = new ArrayList<>(); + for (MultipartFile photoFile : request.photos()) { + S3Info s3Info = uploadFile(photoFile); + if (s3Info != null) { + SessionPhoto sessionPhoto = SessionPhoto.builder() .session(savedSession) .s3Info(s3Info) .order(index.getAndIncrement()) - .build()) - .toList(); + .build(); + + sessionPhotos.add(sessionPhoto); + } + } sessionPhotoRepository.saveAll(sessionPhotos); log.info("세션 이미지 생성 완료"); @@ -114,12 +117,6 @@ public void updateSessionNumber(UpdateSessionNumberRequest request) { session.changeSessionNumber(session.getNumber()); } - @Transactional - public void updateSessionDescription(UpdateSessionDescriptionRequest request) { - Session session = findSessionById(request.sessionId()); - session.updateDescription(request.description()); - } - @Transactional public void updateSession(UpdateSessionRequest request) { Session session = findSessionById(request.sessionId()); @@ -136,20 +133,14 @@ public void updateSession(UpdateSessionRequest request) { sessionRepository.save(session); } - @Transactional - public void updateSessionPhoto(UpdateSessionPhotoRequest request) throws ImageException { - Session session = findSessionById(request.sessionId()); - updatePhoto(session, request.sessionImage()); - } - @Transactional public AddSessionPhotoResponse additionalSessionPhoto(AddSessionPhotoRequest request) throws ImageException { Session session = findSessionById(request.sessionId()); - S3Info imageInfo = s3Uploader.uploadFiles(request.sessionImage(), "session"); + S3Info imageInfo = s3Uploader.uploadFiles(request.photo(), "session"); Integer imageOrder = sessionPhotoRepository.findFirstBySessionOrderByOrderDesc(session) - .map(sessionPhoto -> sessionPhoto.getOrder() + 1).orElse(1); + .map(sessionPhoto -> sessionPhoto.getOrder() + 1).orElse(0); SessionPhoto sessionPhoto = SessionPhoto.builder() .session(session) @@ -167,39 +158,43 @@ public void deleteSessionPhoto(DeleteSessionPhotoRequest request) { s3Uploader.deleteFile(deletePhoto.getS3Info()); sessionPhotoRepository.delete(deletePhoto); - sessionPhotoRepository.findAllBySession(deletePhoto.getSession()).stream() + List reOrderPhotos = sessionPhotoRepository.findAllBySession(deletePhoto.getSession()).stream() .filter(photo -> photo.getOrder() > deletePhoto.getOrder()) - .forEach(SessionPhoto::decreaseOrder); + .toList(); + + for (SessionPhoto sessionPhoto : reOrderPhotos) { + sessionPhoto.decreaseOrder(); + } } @Transactional public void updateSessionPhotoOrder(UpdateSessionPhotoOrderRequest request) { - Session session = findSessionById(request.sessionId()); + Session sessionById = findSessionById(request.sessionId()); List orderList = request.orderInfos(); - List savedPhotos = sessionPhotoRepository.findAllBySession(session); + List savedPhotos = sessionPhotoRepository.findAllBySession(sessionById); if (savedPhotos.size() != orderList.size()) { throw new AppException(ErrorCode.SESSION_PHOTO_COUNT_MISMATCH); } + if (orderList.stream().anyMatch(orderInfo -> !isOrderValid(orderInfo, savedPhotos.size()))) { + throw new AppException(ErrorCode.SESSION_ORDER_INVALID); + } + Map orderMap = orderList.stream() - .filter(orderInfo -> isOrderValid(orderInfo,savedPhotos.size())) .collect(Collectors.toMap(UpdateSessionPhotoOrderInfoRequest::photoId, Function.identity())); - savedPhotos.forEach(sessionPhoto -> { - updatePhotoOrder(sessionPhoto, orderMap); - }); + for (SessionPhoto savePhoto : savedPhotos) { + updatePhotoOrder(savePhoto, orderMap); + } } private boolean isOrderValid(UpdateSessionPhotoOrderInfoRequest orderInfo, int totalSize) { - if (orderInfo.order() < 1 || orderInfo.order() > totalSize) { - throw new AppException(ErrorCode.SESSION_ORDER_INVALID); - } - return true; + return orderInfo.order() >= 0 && orderInfo.order() < totalSize; } - private static void updatePhotoOrder(SessionPhoto sessionPhoto, Map orderMap) { + private void updatePhotoOrder(SessionPhoto sessionPhoto, Map orderMap) { UpdateSessionPhotoOrderInfoRequest orderInfo = orderMap.get(sessionPhoto.getId()); if (orderInfo == null) { From 9c61967fc436399d7a7eb9a012b09980dfeaa44b Mon Sep 17 00:00:00 2001 From: gikhoon Date: Thu, 4 Jul 2024 16:08:11 +0900 Subject: [PATCH 15/21] =?UTF-8?q?feat:=20=EC=84=B8=EC=85=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=EC=8B=9C=20=EC=82=AC=EC=A7=84=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - null, empty인지 판단하는 로직 추가 --- .../generation/service/SessionService.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java index 06b5c81b..823f2615 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java @@ -77,19 +77,22 @@ public AddSessionResponse addSession(AddSessionRequest request) { AtomicInteger index = new AtomicInteger(0); List sessionPhotos = new ArrayList<>(); - for (MultipartFile photoFile : request.photos()) { - S3Info s3Info = uploadFile(photoFile); - if (s3Info != null) { - SessionPhoto sessionPhoto = SessionPhoto.builder() - .session(savedSession) - .s3Info(s3Info) - .order(index.getAndIncrement()) - .build(); - - sessionPhotos.add(sessionPhoto); + if (request.photos() != null && !request.photos().isEmpty()) { + for (MultipartFile photoFile : request.photos()) { + S3Info s3Info = uploadFile(photoFile); + if (s3Info != null) { + SessionPhoto sessionPhoto = SessionPhoto.builder() + .session(savedSession) + .s3Info(s3Info) + .order(index.getAndIncrement()) + .build(); + + sessionPhotos.add(sessionPhoto); + } } } + sessionPhotoRepository.saveAll(sessionPhotos); log.info("세션 이미지 생성 완료"); From 2419d03db1aa2ff95dff018501e7dc3f758b4936 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Thu, 4 Jul 2024 16:08:27 +0900 Subject: [PATCH 16/21] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=A9=94=EC=86=8C=EB=93=9C=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../generation/service/SessionService.java | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java index 823f2615..08f88dbf 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java @@ -206,24 +206,6 @@ private void updatePhotoOrder(SessionPhoto sessionPhoto, Map findSessionsByGenerationId(Long generationId) { Generation generation = generationRepository.findById(generationId) .orElseThrow(() -> new EntityNotFoundException("해당 기수를 찾을 수 없습니다.")); @@ -254,8 +236,4 @@ public List findAllNotLinkedCsOnSessionsByGe .map(CsEducationOnSessionNumberResponse::from) .toList(); } - - private boolean isImageExist(MultipartFile sessionImage) { - return sessionImage != null && !sessionImage.isEmpty(); - } } From 433f077fbbfaea61803e40bb6d34478a767483ff Mon Sep 17 00:00:00 2001 From: gikhoon Date: Thu, 4 Jul 2024 16:17:21 +0900 Subject: [PATCH 17/21] =?UTF-8?q?feat:=20=EC=82=AC=EC=A7=84=20=EC=88=9C?= =?UTF-8?q?=EC=84=9C=20=EB=B3=80=EA=B2=BD=20=EC=8B=9C=20=EA=B2=80=EC=A6=9D?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 중복된 순서가 있는지 확인 --- .../domain/generation/service/SessionService.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java index 08f88dbf..e0c8dd6d 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java @@ -2,8 +2,10 @@ import jakarta.persistence.EntityNotFoundException; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; @@ -185,6 +187,8 @@ public void updateSessionPhotoOrder(UpdateSessionPhotoOrderRequest request) { throw new AppException(ErrorCode.SESSION_ORDER_INVALID); } + checkOrderUnique(orderList); + Map orderMap = orderList.stream() .collect(Collectors.toMap(UpdateSessionPhotoOrderInfoRequest::photoId, Function.identity())); @@ -193,6 +197,15 @@ public void updateSessionPhotoOrder(UpdateSessionPhotoOrderRequest request) { } } + private void checkOrderUnique(List orderList) { + Set uniqueOrders = new HashSet<>(); + for (UpdateSessionPhotoOrderInfoRequest orderInfo : orderList) { + if (!uniqueOrders.add(orderInfo.order())) { + throw new AppException(ErrorCode.SESSION_ORDER_INVALID); + } + } + } + private boolean isOrderValid(UpdateSessionPhotoOrderInfoRequest orderInfo, int totalSize) { return orderInfo.order() >= 0 && orderInfo.order() < totalSize; } From 89d402ba811bca86f77c37efc3fcd6c30972aab4 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Thu, 4 Jul 2024 16:55:24 +0900 Subject: [PATCH 18/21] =?UTF-8?q?feat:=20=EC=BD=94=EB=93=9C=20=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=EB=A5=BC=20=EA=B8=B0=EB=B0=98=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../session/controller/SessionController.java | 3 +- .../generation/entity/SessionPhoto.java | 4 +- .../generation/service/SessionService.java | 50 +++++++------------ 3 files changed, 22 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java index f3fa2f75..8cbd7682 100644 --- a/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java +++ b/src/main/java/org/cotato/csquiz/api/session/controller/SessionController.java @@ -48,7 +48,8 @@ public ResponseEntity> findSessionsByGenerationId(@Req @Operation(summary = "Session 추가하기", description = "세션 추가하기") @PostMapping(value = "/add", consumes = "multipart/form-data") - public ResponseEntity addSession(@ModelAttribute @Valid AddSessionRequest request) { + public ResponseEntity addSession(@ModelAttribute @Valid AddSessionRequest request) + throws ImageException { return ResponseEntity.status(HttpStatus.CREATED).body(sessionService.addSession(request)); } diff --git a/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java b/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java index 3f56179d..6903ca63 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/entity/SessionPhoto.java @@ -51,6 +51,8 @@ public void updateOrder(Integer order) { } public void decreaseOrder() { - this.order--; + if (order > 0) { + order--; + } } } diff --git a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java index e0c8dd6d..b31d5894 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java @@ -55,7 +55,7 @@ public class SessionService { private final S3Uploader s3Uploader; @Transactional - public AddSessionResponse addSession(AddSessionRequest request) { + public AddSessionResponse addSession(AddSessionRequest request) throws ImageException { Generation findGeneration = generationRepository.findById(request.generationId()) .orElseThrow(() -> new EntityNotFoundException("해당 기수를 찾을 수 없습니다.")); @@ -77,11 +77,11 @@ public AddSessionResponse addSession(AddSessionRequest request) { Session savedSession = sessionRepository.save(session); log.info("세션 생성 완료"); - AtomicInteger index = new AtomicInteger(0); - List sessionPhotos = new ArrayList<>(); if (request.photos() != null && !request.photos().isEmpty()) { + AtomicInteger index = new AtomicInteger(0); + List sessionPhotos = new ArrayList<>(); for (MultipartFile photoFile : request.photos()) { - S3Info s3Info = uploadFile(photoFile); + S3Info s3Info = s3Uploader.uploadFiles(photoFile, SESSION_BUCKET_DIRECTORY); if (s3Info != null) { SessionPhoto sessionPhoto = SessionPhoto.builder() .session(savedSession) @@ -92,24 +92,13 @@ public AddSessionResponse addSession(AddSessionRequest request) { sessionPhotos.add(sessionPhoto); } } + sessionPhotoRepository.saveAll(sessionPhotos); + log.info("세션 이미지 생성 완료"); } - - sessionPhotoRepository.saveAll(sessionPhotos); - log.info("세션 이미지 생성 완료"); - return AddSessionResponse.from(savedSession); } - private S3Info uploadFile(MultipartFile file) { - try { - return s3Uploader.uploadFiles(file, SESSION_BUCKET_DIRECTORY); - } catch (ImageException e) { - log.error("이미지 업로드 문제 발생" + e.getMessage()); - } - return null; - } - private int calculateLastSessionNumber(Generation generation) { List allSession = sessionRepository.findAllByGeneration(generation); return allSession.stream().mapToInt(Session::getNumber).max() @@ -183,7 +172,7 @@ public void updateSessionPhotoOrder(UpdateSessionPhotoOrderRequest request) { throw new AppException(ErrorCode.SESSION_PHOTO_COUNT_MISMATCH); } - if (orderList.stream().anyMatch(orderInfo -> !isOrderValid(orderInfo, savedPhotos.size()))) { + if (checkValidOrderRange(orderList)) { throw new AppException(ErrorCode.SESSION_ORDER_INVALID); } @@ -192,11 +181,19 @@ public void updateSessionPhotoOrder(UpdateSessionPhotoOrderRequest request) { Map orderMap = orderList.stream() .collect(Collectors.toMap(UpdateSessionPhotoOrderInfoRequest::photoId, Function.identity())); - for (SessionPhoto savePhoto : savedPhotos) { - updatePhotoOrder(savePhoto, orderMap); + for (SessionPhoto savedPhoto : savedPhotos) { + if (orderMap.get(savedPhoto.getId()) == null) { + throw new AppException(ErrorCode.SESSION_PHOTO_NOT_EXIST); + } + savedPhoto.updateOrder(orderMap.get(savedPhoto.getId()).order()); } } + private boolean checkValidOrderRange(List orderList) { + return orderList.stream().noneMatch(orderInfo -> + orderInfo.order() < 0 || orderInfo.order() >= orderList.size()); + } + private void checkOrderUnique(List orderList) { Set uniqueOrders = new HashSet<>(); for (UpdateSessionPhotoOrderInfoRequest orderInfo : orderList) { @@ -206,19 +203,6 @@ private void checkOrderUnique(List orderList } } - private boolean isOrderValid(UpdateSessionPhotoOrderInfoRequest orderInfo, int totalSize) { - return orderInfo.order() >= 0 && orderInfo.order() < totalSize; - } - - private void updatePhotoOrder(SessionPhoto sessionPhoto, Map orderMap) { - UpdateSessionPhotoOrderInfoRequest orderInfo = orderMap.get(sessionPhoto.getId()); - - if (orderInfo == null) { - throw new AppException(ErrorCode.SESSION_PHOTO_NOT_EXIST); - } - sessionPhoto.updateOrder(orderInfo.order()); - } - public List findSessionsByGenerationId(Long generationId) { Generation generation = generationRepository.findById(generationId) .orElseThrow(() -> new EntityNotFoundException("해당 기수를 찾을 수 없습니다.")); From e36b434984ef704c7d64f2a1e7ebbaae7e07f081 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Thu, 4 Jul 2024 17:42:15 +0900 Subject: [PATCH 19/21] =?UTF-8?q?feat:=20=EC=BD=94=EB=93=9C=20=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=EB=A5=BC=20=EA=B8=B0=EB=B0=98=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../generation/service/SessionService.java | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java index b31d5894..7c02389c 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java @@ -79,19 +79,21 @@ public AddSessionResponse addSession(AddSessionRequest request) throws ImageExce if (request.photos() != null && !request.photos().isEmpty()) { AtomicInteger index = new AtomicInteger(0); + List sessionPhotos = new ArrayList<>(); + for (MultipartFile photoFile : request.photos()) { S3Info s3Info = s3Uploader.uploadFiles(photoFile, SESSION_BUCKET_DIRECTORY); - if (s3Info != null) { - SessionPhoto sessionPhoto = SessionPhoto.builder() - .session(savedSession) - .s3Info(s3Info) - .order(index.getAndIncrement()) - .build(); - - sessionPhotos.add(sessionPhoto); - } + + SessionPhoto sessionPhoto = SessionPhoto.builder() + .session(savedSession) + .s3Info(s3Info) + .order(index.getAndIncrement()) + .build(); + + sessionPhotos.add(sessionPhoto); } + sessionPhotoRepository.saveAll(sessionPhotos); log.info("세션 이미지 생성 완료"); } @@ -131,7 +133,7 @@ public void updateSession(UpdateSessionRequest request) { public AddSessionPhotoResponse additionalSessionPhoto(AddSessionPhotoRequest request) throws ImageException { Session session = findSessionById(request.sessionId()); - S3Info imageInfo = s3Uploader.uploadFiles(request.photo(), "session"); + S3Info imageInfo = s3Uploader.uploadFiles(request.photo(), SESSION_BUCKET_DIRECTORY); Integer imageOrder = sessionPhotoRepository.findFirstBySessionOrderByOrderDesc(session) .map(sessionPhoto -> sessionPhoto.getOrder() + 1).orElse(0); @@ -176,7 +178,9 @@ public void updateSessionPhotoOrder(UpdateSessionPhotoOrderRequest request) { throw new AppException(ErrorCode.SESSION_ORDER_INVALID); } - checkOrderUnique(orderList); + if (!checkOrderUnique(orderList)) { + throw new AppException(ErrorCode.SESSION_ORDER_INVALID); + } Map orderMap = orderList.stream() .collect(Collectors.toMap(UpdateSessionPhotoOrderInfoRequest::photoId, Function.identity())); @@ -194,13 +198,15 @@ private boolean checkValidOrderRange(List or orderInfo.order() < 0 || orderInfo.order() >= orderList.size()); } - private void checkOrderUnique(List orderList) { + private boolean checkOrderUnique(List orderList) { Set uniqueOrders = new HashSet<>(); for (UpdateSessionPhotoOrderInfoRequest orderInfo : orderList) { if (!uniqueOrders.add(orderInfo.order())) { - throw new AppException(ErrorCode.SESSION_ORDER_INVALID); + return false; } } + + return true; } public List findSessionsByGenerationId(Long generationId) { From 1c7525d4e4c7341ab1a3b4453092a09a7a68d842 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Mon, 8 Jul 2024 22:54:10 +0900 Subject: [PATCH 20/21] =?UTF-8?q?refactor:=20=EC=97=90=EB=9F=AC=EC=BD=94?= =?UTF-8?q?=EB=93=9C=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/cotato/csquiz/common/error/ErrorCode.java | 7 ++++--- .../csquiz/domain/generation/service/SessionService.java | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java b/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java index 3349b362..3b2f0b82 100644 --- a/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java +++ b/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java @@ -45,6 +45,10 @@ public enum ErrorCode { EDUCATION_STATUS_NOT_BEFORE(HttpStatus.BAD_REQUEST, "E-402", "이미 시작한 적이 있는 교육입니다."), MEMBER_CANT_ACCESS(HttpStatus.BAD_REQUEST, "E-403", "해당 멤버의 ROLE로 접근할 수 없습니다"), + //세션 사진 + SESSION_PHOTO_COUNT_MISMATCH(HttpStatus.BAD_REQUEST, "P-101", "저장된 사진 수와 요청 사진 수가 다릅니다."), + SESSION_ORDER_INVALID(HttpStatus.BAD_REQUEST, "P-102", "입력한 순서는 유효하지 않습니다."), + INVALID_ANSWER(HttpStatus.BAD_REQUEST, "Q-101", "객관식 문제는 숫자 형식의 값만 정답으로 추가할 수 있습니다."), CONTENT_IS_NOT_ANSWER(HttpStatus.BAD_REQUEST, "Q-201", "추가되지 않은 정답을 추가할 수 없습니다."), QUIZ_NUMBER_DUPLICATED(HttpStatus.CONFLICT, "Q-301", "퀴즈 번호는 중복될 수 없습니다."), @@ -69,9 +73,6 @@ public enum ErrorCode { IMAGE_DELETE_FAIL(HttpStatus.INTERNAL_SERVER_ERROR, "S-003", "s3 이미지 삭제처리를 실패했습니다"), INTERNAL_SQL_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "S-004", "SQL 관련 에러 발생"), ENUM_NOT_RESOLVED(HttpStatus.BAD_REQUEST, "S-005", "입력한 Enum이 존재하지 않습니다."), - SESSION_PHOTO_COUNT_MISMATCH(HttpStatus.BAD_REQUEST, "S-006", "저장된 사진 수와 요청 사진 수가 다릅니다."), - SESSION_PHOTO_NOT_EXIST(HttpStatus.BAD_REQUEST, "S-007", "저장되지 않은 사진에 대한 요청이 있습니다."), - SESSION_ORDER_INVALID(HttpStatus.BAD_REQUEST, "S-008", "입력한 순서는 유효하지 않습니다."), ; private final HttpStatus httpStatus; diff --git a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java index 7c02389c..b1b1f50f 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java @@ -187,7 +187,7 @@ public void updateSessionPhotoOrder(UpdateSessionPhotoOrderRequest request) { for (SessionPhoto savedPhoto : savedPhotos) { if (orderMap.get(savedPhoto.getId()) == null) { - throw new AppException(ErrorCode.SESSION_PHOTO_NOT_EXIST); + throw new EntityNotFoundException("해당 사진을 찾을 수 없습니다."); } savedPhoto.updateOrder(orderMap.get(savedPhoto.getId()).order()); } From 25d69522cc27db0fe8d59718118535acab8a4d28 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Mon, 8 Jul 2024 22:55:08 +0900 Subject: [PATCH 21/21] =?UTF-8?q?feat:=20=EA=B8=B0=EC=A1=B4=20=EC=84=B8?= =?UTF-8?q?=EC=85=98=20=EC=82=AC=EC=A7=84=20=ED=95=AD=EB=AA=A9=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - photoS3Info 삭제 --- .../csquiz/domain/generation/entity/Session.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/domain/generation/entity/Session.java b/src/main/java/org/cotato/csquiz/domain/generation/entity/Session.java index 68a9aa65..449e4352 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/entity/Session.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/entity/Session.java @@ -44,9 +44,6 @@ public class Session extends BaseTimeEntity { @OneToMany(mappedBy = "session", orphanRemoval = true) private List sessionPhotos = new ArrayList<>(); - @Embedded - private S3Info photoS3Info; - @Column(name = "session_description") private String description; @@ -67,9 +64,8 @@ public class Session extends BaseTimeEntity { private SessionContents sessionContents; @Builder - public Session(Integer number, S3Info s3Info, String title, String description, Generation generation, SessionContents sessionContents) { + public Session(Integer number, String title, String description, Generation generation, SessionContents sessionContents) { this.number = number; - this.photoS3Info = s3Info; this.title = title; this.description = description; this.generation = generation; @@ -84,10 +80,6 @@ public void updateDescription(String description) { this.description = description; } - public void changePhotoUrl(S3Info photoUrl) { - this.photoS3Info = photoUrl; - } - public void updateSessionContents(SessionContents sessionContents) { this.sessionContents = sessionContents; }