From 36f83fc4a4909ca532674b33dfaca1567f80a205 Mon Sep 17 00:00:00 2001 From: Minjoon Kim <59060780+sanbonai06@users.noreply.github.com> Date: Mon, 6 Feb 2023 15:45:55 +0900 Subject: [PATCH 1/7] =?UTF-8?q?fix:=20=EC=9D=91=EC=9B=90=EA=B8=80=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20API=20=EC=9D=B8=EC=A6=9D=20=EA=B3=BC?= =?UTF-8?q?=EC=A0=95=20=EC=82=AD=EC=A0=9C=20(#310)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 응원글 조회 API 인증 과정 삭제 * fix : @DisableSwaggerSecurity 어노테이션으로 수정 --- .../gosrock/api/comment/controller/CommentController.java | 4 ++++ .../java/band/gosrock/api/config/security/SecurityConfig.java | 2 ++ 2 files changed, 6 insertions(+) diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/comment/controller/CommentController.java b/DuDoong-Api/src/main/java/band/gosrock/api/comment/controller/CommentController.java index 49be246e..d938592a 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/comment/controller/CommentController.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/comment/controller/CommentController.java @@ -12,6 +12,7 @@ import band.gosrock.api.comment.service.RetrieveCommentUseCase; import band.gosrock.api.comment.service.RetrieveRandomCommentUseCase; import band.gosrock.api.common.slice.SliceResponse; +import band.gosrock.common.annotation.DisableSwaggerSecurity; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; @@ -53,6 +54,7 @@ public CreateCommentResponse postComment( return createCommentUseCase.execute(eventId, createCommentRequest); } + @DisableSwaggerSecurity @Operation(summary = "응원글을 조회합니다.") @GetMapping public SliceResponse getComments( @@ -67,12 +69,14 @@ public void deleteComment(@PathVariable Long eventId, @PathVariable Long comment deleteCommentUseCase.execute(eventId, commentId); } + @DisableSwaggerSecurity @Operation(summary = "응원글 개수를 카운팅합니다.") @GetMapping(value = "/counts") public RetrieveCommentCountResponse getCommentCounts(@PathVariable Long eventId) { return retrieveCommentCountUseCase.execute(eventId); } + @DisableSwaggerSecurity @Operation(summary = "응원글을 랜덤으로 뽑아옵니다.") @GetMapping(value = "/random") public RetrieveRandomCommentResponse getRandomComment(@PathVariable Long eventId) { diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/config/security/SecurityConfig.java b/DuDoong-Api/src/main/java/band/gosrock/api/config/security/SecurityConfig.java index 7e8d6082..425869b0 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/config/security/SecurityConfig.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/config/security/SecurityConfig.java @@ -37,6 +37,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .permitAll() .mvcMatchers(HttpMethod.GET, "/v1/events/{eventId:[\\d+]}/ticketItems") .permitAll() + .mvcMatchers(HttpMethod.GET, "/v1/events/{eventId:[\\d+]}/comments/**") + .permitAll() .mvcMatchers(HttpMethod.POST, "/v1/coupons/campaigns") .hasRole("SUPER_ADMIN") .anyRequest() From cf4558c999790b906d49da59c375cdbd9a08bfd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EA=B2=BD=EB=AF=BC?= Date: Tue, 7 Feb 2023 20:31:14 +0900 Subject: [PATCH 2/7] =?UTF-8?q?refactor=20:=20=ED=98=B8=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EB=B0=8F=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EA=B8=B8=EC=9D=B4?= =?UTF-8?q?=20=EC=A0=9C=ED=95=9C=20=EC=B6=94=EA=B0=80=20(#319)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor : 호스트 및 이벤트 요청 DTO 길이 제한 검증 추가 * refactor : 호스트 및 이벤트 엔티티 길이 제약조건 추가 --- .../api/event/model/dto/request/CreateEventRequest.java | 2 ++ .../event/model/dto/request/UpdateEventBasicRequest.java | 2 ++ .../api/host/model/dto/request/CreateHostRequest.java | 6 ++++-- .../gosrock/domain/domains/event/domain/EventBasic.java | 3 +++ .../gosrock/domain/domains/host/domain/HostProfile.java | 1 + 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/request/CreateEventRequest.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/request/CreateEventRequest.java index 340ad527..e680dcbb 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/request/CreateEventRequest.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/request/CreateEventRequest.java @@ -9,6 +9,7 @@ import javax.validation.constraints.Positive; import lombok.Getter; import lombok.RequiredArgsConstructor; +import org.hibernate.validator.constraints.Length; @Getter @RequiredArgsConstructor @@ -19,6 +20,7 @@ public class CreateEventRequest { @Schema(defaultValue = "고스락 제 22회 정기공연", description = "공연 이름") @NotBlank(message = "공연 이름을 입력하세요") + @Length(max = 25) private String name; @Schema( diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/request/UpdateEventBasicRequest.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/request/UpdateEventBasicRequest.java index fee560f0..9005ba6a 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/request/UpdateEventBasicRequest.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/request/UpdateEventBasicRequest.java @@ -9,12 +9,14 @@ import javax.validation.constraints.Positive; import lombok.Getter; import lombok.RequiredArgsConstructor; +import org.hibernate.validator.constraints.Length; @Getter @RequiredArgsConstructor public class UpdateEventBasicRequest { @Schema(defaultValue = "고스락 제 22회 정기공연", description = "공연 이름") @NotBlank(message = "공연 이름을 입력하세요") + @Length(max = 25) private String name; @Schema( diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/request/CreateHostRequest.java b/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/request/CreateHostRequest.java index 5ee70e20..2369b893 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/request/CreateHostRequest.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/request/CreateHostRequest.java @@ -4,16 +4,18 @@ import band.gosrock.common.annotation.Phone; import io.swagger.v3.oas.annotations.media.Schema; import javax.validation.constraints.Email; -import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotBlank; import lombok.Getter; import lombok.RequiredArgsConstructor; +import org.hibernate.validator.constraints.Length; /** 호스트 간편 생성 요청 DTO */ @Getter @RequiredArgsConstructor public class CreateHostRequest { @Schema(defaultValue = "고스락", description = "호스트 이름") - @NotEmpty(message = "호스트 이름을 입력해주세요") + @NotBlank(message = "호스트 이름을 입력해주세요") + @Length(max = 15) private String name; @Schema(defaultValue = "gosrock@gsrk.com", description = "마스터 이메일") diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/EventBasic.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/EventBasic.java index a217ef97..55af7abe 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/EventBasic.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/EventBasic.java @@ -2,6 +2,7 @@ import java.time.LocalDateTime; +import javax.persistence.Column; import javax.persistence.Embeddable; import lombok.AccessLevel; import lombok.Builder; @@ -12,7 +13,9 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class EventBasic { + @Column(length = 25) private String name; + private LocalDateTime startAt; private Long runTime; diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/domain/HostProfile.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/domain/HostProfile.java index 1152c338..0053186b 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/domain/HostProfile.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/domain/HostProfile.java @@ -15,6 +15,7 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class HostProfile { // 호스트 이름 + @Column(length = 15) private String name; // 간단 소개 From 6bbf63c85a13be110b8756b8b57f647e255cdca5 Mon Sep 17 00:00:00 2001 From: Minjoon Kim <59060780+sanbonai06@users.noreply.github.com> Date: Wed, 8 Feb 2023 15:18:38 +0900 Subject: [PATCH 3/7] =?UTF-8?q?refactor:=20=EC=9D=91=EC=9B=90=ED=86=A1=20?= =?UTF-8?q?=EB=9E=9C=EB=8D=A4=20=EC=A1=B0=ED=9A=8C=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20=EB=9E=9C=EB=8D=A4=20=EC=BF=BC=EB=A6=AC=20=EC=9C=84?= =?UTF-8?q?=ED=95=B4=20nativeQuery=EB=A1=9C=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81=20(#315)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 응원톡 랜덤 조회 쿼리 파라미터 추가 및 랜덤 쿼리 위해 nativeQuery로 리팩토링 * feat : queryParam validation 추가 * fix : 사용하지 않는 쿼리 삭제 * fix : @Validated 추가 --- .../comment/controller/CommentController.java | 10 ++++-- .../api/comment/mapper/CommentMapper.java | 5 +-- .../RetrieveRandomCommentResponse.java | 7 ++-- .../service/RetrieveRandomCommentUseCase.java | 7 ++-- .../comment/adaptor/CommentAdaptor.java | 6 ++-- .../repository/CommentCustomRepository.java | 2 -- .../CommentCustomRepositoryImpl.java | 35 ------------------- .../comment/repository/CommentRepository.java | 16 ++++++++- 8 files changed, 38 insertions(+), 50 deletions(-) diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/comment/controller/CommentController.java b/DuDoong-Api/src/main/java/band/gosrock/api/comment/controller/CommentController.java index d938592a..18ad93b6 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/comment/controller/CommentController.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/comment/controller/CommentController.java @@ -17,22 +17,26 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import javax.validation.Valid; +import javax.validation.constraints.Min; import lombok.RequiredArgsConstructor; import org.springdoc.api.annotations.ParameterObject; import org.springframework.data.domain.Pageable; import org.springframework.data.web.PageableDefault; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; 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.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @SecurityRequirement(name = "access-token") @Tag(name = "응원톡 컨트롤러") @RestController @RequestMapping("/v1/events/{eventId}/comments") +@Validated @RequiredArgsConstructor public class CommentController { @@ -79,7 +83,9 @@ public RetrieveCommentCountResponse getCommentCounts(@PathVariable Long eventId) @DisableSwaggerSecurity @Operation(summary = "응원글을 랜덤으로 뽑아옵니다.") @GetMapping(value = "/random") - public RetrieveRandomCommentResponse getRandomComment(@PathVariable Long eventId) { - return retrieveRandomCommentUseCase.execute(eventId); + public RetrieveRandomCommentResponse getRandomComment( + @PathVariable Long eventId, + @RequestParam @Min(value = 1L, message = "limit 값은 0보다 커야 합니다.") Long limit) { + return retrieveRandomCommentUseCase.execute(eventId, limit); } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/comment/mapper/CommentMapper.java b/DuDoong-Api/src/main/java/band/gosrock/api/comment/mapper/CommentMapper.java index 1f683319..49bb79b5 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/comment/mapper/CommentMapper.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/comment/mapper/CommentMapper.java @@ -13,6 +13,7 @@ import band.gosrock.domain.domains.comment.dto.condition.CommentCondition; import band.gosrock.domain.domains.event.domain.Event; import band.gosrock.domain.domains.user.domain.User; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Slice; import org.springframework.transaction.annotation.Transactional; @@ -49,8 +50,8 @@ public RetrieveCommentCountResponse toRetrieveCommentCountResponse(Long commentC return RetrieveCommentCountResponse.of(commentCount); } - public RetrieveRandomCommentResponse toRetrieveRandomCommentResponse(Comment comment) { - return RetrieveRandomCommentResponse.of(comment); + public RetrieveRandomCommentResponse toRetrieveRandomCommentResponse(List comments) { + return RetrieveRandomCommentResponse.of(comments); } private RetrieveCommentDTO toRetrieveCommentDTO(Comment comment, Long currentUserId) { diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/comment/model/response/RetrieveRandomCommentResponse.java b/DuDoong-Api/src/main/java/band/gosrock/api/comment/model/response/RetrieveRandomCommentResponse.java index f2cd2b19..934321e0 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/comment/model/response/RetrieveRandomCommentResponse.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/comment/model/response/RetrieveRandomCommentResponse.java @@ -3,6 +3,7 @@ import band.gosrock.domain.common.vo.CommentInfoVo; import band.gosrock.domain.domains.comment.domain.Comment; +import java.util.List; import lombok.Builder; import lombok.Getter; @@ -10,11 +11,11 @@ @Builder public class RetrieveRandomCommentResponse { - private final CommentInfoVo commentInfo; + private final List commentInfos; - public static RetrieveRandomCommentResponse of(Comment comment) { + public static RetrieveRandomCommentResponse of(List comments) { return RetrieveRandomCommentResponse.builder() - .commentInfo(comment.toCommentInfoVo()) + .commentInfos(comments.stream().map(Comment::toCommentInfoVo).toList()) .build(); } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/comment/service/RetrieveRandomCommentUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/comment/service/RetrieveRandomCommentUseCase.java index 511c2399..ae35fe59 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/comment/service/RetrieveRandomCommentUseCase.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/comment/service/RetrieveRandomCommentUseCase.java @@ -8,6 +8,7 @@ import band.gosrock.domain.domains.comment.domain.Comment; import band.gosrock.domain.domains.event.adaptor.EventAdaptor; import band.gosrock.domain.domains.event.domain.Event; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.transaction.annotation.Transactional; @@ -22,9 +23,9 @@ public class RetrieveRandomCommentUseCase { private final EventAdaptor eventAdaptor; @Transactional(readOnly = true) - public RetrieveRandomCommentResponse execute(Long eventId) { + public RetrieveRandomCommentResponse execute(Long eventId, Long limit) { Event event = eventAdaptor.findById(eventId); - Comment comment = commentAdaptor.queryRandomComment(event.getId()); - return commentMapper.toRetrieveRandomCommentResponse(comment); + List comments = commentAdaptor.queryRandomComment(event.getId(), limit); + return commentMapper.toRetrieveRandomCommentResponse(comments); } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/comment/adaptor/CommentAdaptor.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/comment/adaptor/CommentAdaptor.java index f0e0ab09..ebdfd791 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/comment/adaptor/CommentAdaptor.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/comment/adaptor/CommentAdaptor.java @@ -6,6 +6,7 @@ import band.gosrock.domain.domains.comment.dto.condition.CommentCondition; import band.gosrock.domain.domains.comment.exception.CommentNotFoundException; import band.gosrock.domain.domains.comment.repository.CommentRepository; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Slice; @@ -33,8 +34,9 @@ public Long queryCommentCount(Long eventId) { return commentRepository.countComment(eventId); } - public Comment queryRandomComment(Long eventId) { + public List queryRandomComment(Long eventId, Long limit) { Long countComment = queryCommentCount(eventId); - return commentRepository.queryRandomComment(eventId, countComment); + // return commentRepository.queryRandomComment(eventId, countComment, offset); + return commentRepository.findAllRandom(eventId, limit); } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/comment/repository/CommentCustomRepository.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/comment/repository/CommentCustomRepository.java index 0549217c..8b1f2846 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/comment/repository/CommentCustomRepository.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/comment/repository/CommentCustomRepository.java @@ -10,6 +10,4 @@ public interface CommentCustomRepository { Slice searchToPage(CommentCondition commentCondition); Long countComment(Long eventId); - - Comment queryRandomComment(Long eventId, Long count); } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/comment/repository/CommentCustomRepositoryImpl.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/comment/repository/CommentCustomRepositoryImpl.java index 14959669..822d9503 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/comment/repository/CommentCustomRepositoryImpl.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/comment/repository/CommentCustomRepositoryImpl.java @@ -7,17 +7,11 @@ import band.gosrock.domain.domains.comment.domain.Comment; import band.gosrock.domain.domains.comment.domain.CommentStatus; import band.gosrock.domain.domains.comment.dto.condition.CommentCondition; -import band.gosrock.domain.domains.comment.exception.RetrieveRandomCommentNotFoundException; import com.querydsl.core.types.dsl.BooleanExpression; -import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; -import java.security.SecureRandom; import java.util.List; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Slice; -import org.springframework.data.support.PageableExecutionUtils; @RequiredArgsConstructor public class CommentCustomRepositoryImpl implements CommentCustomRepository { @@ -70,33 +64,4 @@ public Long countComment(Long eventId) { .where(eventIdEq(eventId), comment.commentStatus.eq(CommentStatus.ACTIVE)) .fetchOne(); } - - @Override - public Comment queryRandomComment(Long eventId, Long countComment) { - SecureRandom secureRandom = new SecureRandom(); - int idx = (int) (secureRandom.nextFloat(1) * countComment); - - PageRequest pageRequest = PageRequest.of(idx, 1); - List comments = - queryFactory - .selectFrom(comment) - .where(eventIdEq(eventId), comment.commentStatus.eq(CommentStatus.ACTIVE)) - .offset(pageRequest.getOffset()) - .limit(1) - .fetch(); - - JPAQuery countQuery = - queryFactory - .select(comment.count()) - .from(comment) - .where(eventIdEq(eventId), comment.commentStatus.eq(CommentStatus.ACTIVE)); - - Page commentOfPage = - PageableExecutionUtils.getPage(comments, pageRequest, countQuery::fetchOne); - - if (commentOfPage.hasContent()) { - return commentOfPage.getContent().get(0); - } - throw RetrieveRandomCommentNotFoundException.EXCEPTION; - } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/comment/repository/CommentRepository.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/comment/repository/CommentRepository.java index 91d9aa64..52dc1e35 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/comment/repository/CommentRepository.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/comment/repository/CommentRepository.java @@ -2,6 +2,20 @@ import band.gosrock.domain.domains.comment.domain.Comment; +import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; -public interface CommentRepository extends JpaRepository, CommentCustomRepository {} +public interface CommentRepository extends JpaRepository, CommentCustomRepository { + + @Query( + nativeQuery = true, + value = + "SELECT * " + + "FROM tbl_comment as c " + + "WHERE c.event_id = :eventId " + + "ORDER BY RAND() DESC " + + "LIMIT :offset") + List findAllRandom(@Param("eventId") Long eventId, @Param("offset") Long limit); +} From a57f3d8dfbe1bb113ea684f4fe084011abaf148c Mon Sep 17 00:00:00 2001 From: Chan Jin Date: Wed, 8 Feb 2023 15:50:16 +0900 Subject: [PATCH 4/7] =?UTF-8?q?refactor=20:=20=EC=8B=A4=EC=A0=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EC=9A=B0=EC=84=A0=20=ED=9B=84=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20=EC=9D=B4=EB=A6=84=20=EB=B6=88=EB=9F=AC?= =?UTF-8?q?=EC=98=A4=EA=B8=B0=20(#323)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../outer/api/oauth/dto/KakaoInformationResponse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/outer/api/oauth/dto/KakaoInformationResponse.java b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/outer/api/oauth/dto/KakaoInformationResponse.java index d0674869..23da1960 100644 --- a/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/outer/api/oauth/dto/KakaoInformationResponse.java +++ b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/outer/api/oauth/dto/KakaoInformationResponse.java @@ -58,7 +58,7 @@ public String getPhoneNumber() { } public String getName() { - return kakaoAccount.getName(); + return kakaoAccount.getName() != null ? kakaoAccount.getName() : properties.getNickname(); } public String getProfileUrl() { From 12ebcc392719d44063e496f5c7e559a211867671 Mon Sep 17 00:00:00 2001 From: Chan Jin Date: Wed, 8 Feb 2023 19:46:33 +0900 Subject: [PATCH 5/7] feature : async error handler with slack alarm (#322) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat : async 에러 처리 핸들러 추가 * refactor : slack provider 분리 * feat : slack sender 위치 재조정 * feat : 비동기 에러 슬랙 핸들러 설정 --- .../response/GlobalExceptionHandler.java | 6 +- .../sender/SlackInternalErrorSender.java} | 52 +++------------ .../src/main/resources/application.yml | 4 -- .../common/events/order/CreateOrderEvent.java | 2 + .../common/events/order/DoneOrderEvent.java | 2 + .../events/order/WithDrawOrderEvent.java | 2 + .../common/events/user/UserRegisterEvent.java | 2 + .../config/CustomAsyncExceptionHandler.java | 27 ++++++++ .../domain/config/EnableAsyncConfig.java | 14 ++++- .../config/slack/SlackAsyncErrorSender.java | 59 +++++++++++++++++ .../config/slack/SlackProvider.java | 63 +++++++++++++++++++ .../resources/application-infrastructure.yml | 4 +- 12 files changed, 181 insertions(+), 56 deletions(-) rename DuDoong-Api/src/main/java/band/gosrock/api/{config/slack/SlackApiProvider.java => slack/sender/SlackInternalErrorSender.java} (59%) create mode 100644 DuDoong-Domain/src/main/java/band/gosrock/domain/config/CustomAsyncExceptionHandler.java create mode 100644 DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/slack/SlackAsyncErrorSender.java create mode 100644 DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/slack/SlackProvider.java diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/config/response/GlobalExceptionHandler.java b/DuDoong-Api/src/main/java/band/gosrock/api/config/response/GlobalExceptionHandler.java index 214faf42..baf23174 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/config/response/GlobalExceptionHandler.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/config/response/GlobalExceptionHandler.java @@ -2,7 +2,7 @@ import band.gosrock.api.config.security.SecurityUtils; -import band.gosrock.api.config.slack.SlackApiProvider; +import band.gosrock.api.slack.sender.SlackInternalErrorSender; import band.gosrock.common.dto.ErrorReason; import band.gosrock.common.dto.ErrorResponse; import band.gosrock.common.exception.BaseErrorCode; @@ -39,7 +39,7 @@ @RequiredArgsConstructor public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { - private final SlackApiProvider slackApiProvider; + private final SlackInternalErrorSender slackInternalErrorSender; // /** Json 날짜 형식 파싱에 대한 에러 핸들러 */ // @ExceptionHandler({ InvalidFormatException.class, DateTimeParseException.class}) // public ResponseEntity JsonParseExceptionHandler( @@ -181,7 +181,7 @@ protected ResponseEntity handleException(Exception e, HttpServlet internalServerError.getReason(), url); - slackApiProvider.sendError(cachingRequest, e, userId); + slackInternalErrorSender.execute(cachingRequest, e, userId); return ResponseEntity.status(HttpStatus.valueOf(internalServerError.getStatus())) .body(errorResponse); } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/config/slack/SlackApiProvider.java b/DuDoong-Api/src/main/java/band/gosrock/api/slack/sender/SlackInternalErrorSender.java similarity index 59% rename from DuDoong-Api/src/main/java/band/gosrock/api/config/slack/SlackApiProvider.java rename to DuDoong-Api/src/main/java/band/gosrock/api/slack/sender/SlackInternalErrorSender.java index a4732f93..0d7fd57f 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/config/slack/SlackApiProvider.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/slack/sender/SlackInternalErrorSender.java @@ -1,68 +1,40 @@ -package band.gosrock.api.config.slack; +package band.gosrock.api.slack.sender; import static com.slack.api.model.block.Blocks.divider; import static com.slack.api.model.block.Blocks.section; import static com.slack.api.model.block.composition.BlockCompositions.plainText; +import band.gosrock.infrastructure.config.slack.SlackProvider; import com.fasterxml.jackson.databind.ObjectMapper; -import com.slack.api.methods.MethodsClient; -import com.slack.api.methods.SlackApiException; -import com.slack.api.methods.request.chat.ChatPostMessageRequest; import com.slack.api.model.block.Blocks; import com.slack.api.model.block.LayoutBlock; import com.slack.api.model.block.composition.MarkdownTextObject; import com.slack.api.model.block.composition.TextObject; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.env.Environment; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; import org.springframework.web.util.ContentCachingRequestWrapper; @Component @RequiredArgsConstructor @Slf4j -public class SlackApiProvider { - private final MethodsClient methodsClient; +public class SlackInternalErrorSender { private final ObjectMapper objectMapper; - private final Environment env; + private final SlackProvider slackProvider; - private final List sendAlarmProfiles = List.of("staging", "prod"); - - @Value("${slack.webhook.id}") - private String CHANNEL_ID; - - private final int MAX_LEN = 500; - - @Async - public void sendError(ContentCachingRequestWrapper cachingRequest, Exception e, Long userId) - throws IOException { - String[] activeProfiles = env.getActiveProfiles(); - List currentProfile = Arrays.stream(activeProfiles).toList(); - if (CollectionUtils.containsAny(sendAlarmProfiles, currentProfile)) { - executeSendError(cachingRequest, e, userId); - } - } - - private void executeSendError( - ContentCachingRequestWrapper cachingRequest, Exception e, Long userId) + public void execute(ContentCachingRequestWrapper cachingRequest, Exception e, Long userId) throws IOException { final String url = cachingRequest.getRequestURL().toString(); final String method = cachingRequest.getMethod(); final String body = objectMapper.readTree(cachingRequest.getContentAsByteArray()).toString(); - final String exceptionAsString = Arrays.toString(e.getStackTrace()); - final int cutLength = Math.min(exceptionAsString.length(), MAX_LEN); final String errorMessage = e.getMessage(); - final String errorStack = exceptionAsString.substring(0, cutLength); + String errorStack = slackProvider.getErrorStack(e); final String errorUserIP = cachingRequest.getRemoteAddr(); List layoutBlocks = new ArrayList<>(); @@ -99,16 +71,6 @@ private void executeSendError( layoutBlocks.add( section(section -> section.fields(List.of(errorNameMarkdown, errorStackMarkdown)))); - ChatPostMessageRequest chatPostMessageRequest = - ChatPostMessageRequest.builder() - .channel(CHANNEL_ID) - .text("") - .blocks(layoutBlocks) - .build(); - try { - methodsClient.chatPostMessage(chatPostMessageRequest); - } catch (SlackApiException slackApiException) { - log.error(slackApiException.toString()); - } + slackProvider.sendNotification(layoutBlocks); } } diff --git a/DuDoong-Api/src/main/resources/application.yml b/DuDoong-Api/src/main/resources/application.yml index c26a9c7c..8f9b0e45 100644 --- a/DuDoong-Api/src/main/resources/application.yml +++ b/DuDoong-Api/src/main/resources/application.yml @@ -18,10 +18,6 @@ server: context-path: /api forward-headers-strategy: framework - -slack: - webhook: - id: ${SLACK_WEBHOOK_ID:} --- spring: config: diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/events/order/CreateOrderEvent.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/events/order/CreateOrderEvent.java index bb384316..e14ec5a1 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/events/order/CreateOrderEvent.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/events/order/CreateOrderEvent.java @@ -6,10 +6,12 @@ import band.gosrock.domain.domains.order.domain.OrderMethod; import lombok.Builder; import lombok.Getter; +import lombok.ToString; import org.springframework.lang.Nullable; @Getter @Builder +@ToString public class CreateOrderEvent extends DomainEvent { private final String orderUuid; diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/events/order/DoneOrderEvent.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/events/order/DoneOrderEvent.java index 2492d071..628ee226 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/events/order/DoneOrderEvent.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/events/order/DoneOrderEvent.java @@ -6,10 +6,12 @@ import band.gosrock.domain.domains.order.domain.OrderMethod; import lombok.Builder; import lombok.Getter; +import lombok.ToString; import org.springframework.lang.Nullable; @Getter @Builder +@ToString public class DoneOrderEvent extends DomainEvent { private final String orderUuid; diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/events/order/WithDrawOrderEvent.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/events/order/WithDrawOrderEvent.java index 9d6bebbc..996389ef 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/events/order/WithDrawOrderEvent.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/events/order/WithDrawOrderEvent.java @@ -7,10 +7,12 @@ import band.gosrock.domain.domains.order.domain.OrderStatus; import lombok.Builder; import lombok.Getter; +import lombok.ToString; import org.springframework.lang.Nullable; @Getter @Builder +@ToString public class WithDrawOrderEvent extends DomainEvent { private final String orderUuid; diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/events/user/UserRegisterEvent.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/events/user/UserRegisterEvent.java index 82ed6c4c..98735a46 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/events/user/UserRegisterEvent.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/events/user/UserRegisterEvent.java @@ -4,8 +4,10 @@ import band.gosrock.domain.common.aop.domainEvent.DomainEvent; import lombok.Builder; import lombok.Getter; +import lombok.ToString; @Getter +@ToString public class UserRegisterEvent extends DomainEvent { private final Long userId; diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/config/CustomAsyncExceptionHandler.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/config/CustomAsyncExceptionHandler.java new file mode 100644 index 00000000..c8f72b58 --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/config/CustomAsyncExceptionHandler.java @@ -0,0 +1,27 @@ +package band.gosrock.domain.config; + + +import band.gosrock.infrastructure.config.slack.SlackAsyncErrorSender; +import java.lang.reflect.Method; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler { + + private final SlackAsyncErrorSender slackAsyncErrorSender; + + @Override + public void handleUncaughtException(Throwable throwable, Method method, Object... params) { + log.error("Exception message - " + throwable); + log.error("Method name - " + method.getName()); + for (Object param : params) { + log.error("Parameter value - " + param); + } + slackAsyncErrorSender.execute(method.getName(), throwable, params); + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/config/EnableAsyncConfig.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/config/EnableAsyncConfig.java index 44263c97..d0f98be4 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/config/EnableAsyncConfig.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/config/EnableAsyncConfig.java @@ -1,9 +1,21 @@ package band.gosrock.domain.config; +import lombok.RequiredArgsConstructor; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurer; import org.springframework.scheduling.annotation.EnableAsync; @EnableAsync @Configuration -public class EnableAsyncConfig {} +@RequiredArgsConstructor +public class EnableAsyncConfig implements AsyncConfigurer { + + private final CustomAsyncExceptionHandler customAsyncExceptionHandler; + + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return customAsyncExceptionHandler; + } +} diff --git a/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/slack/SlackAsyncErrorSender.java b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/slack/SlackAsyncErrorSender.java new file mode 100644 index 00000000..22082192 --- /dev/null +++ b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/slack/SlackAsyncErrorSender.java @@ -0,0 +1,59 @@ +package band.gosrock.infrastructure.config.slack; + +import static com.slack.api.model.block.Blocks.divider; +import static com.slack.api.model.block.Blocks.section; +import static com.slack.api.model.block.composition.BlockCompositions.plainText; + +import com.slack.api.model.block.Blocks; +import com.slack.api.model.block.LayoutBlock; +import com.slack.api.model.block.composition.MarkdownTextObject; +import java.util.ArrayList; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@RequiredArgsConstructor +@Component +@Slf4j +public class SlackAsyncErrorSender { + private final SlackProvider slackProvider; + + public void execute(String name, Throwable throwable, Object[] params) { + List layoutBlocks = new ArrayList<>(); + layoutBlocks.add( + Blocks.header( + headerBlockBuilder -> headerBlockBuilder.text(plainText("비동기 에러 알림")))); + layoutBlocks.add(divider()); + + MarkdownTextObject errorUserIdMarkdown = + MarkdownTextObject.builder().text("* 메소드 이름 :*\n" + name).build(); + MarkdownTextObject errorUserIpMarkdown = + MarkdownTextObject.builder() + .text("* 요청 파라미터 :*\n" + getParamsToString(params)) + .build(); + layoutBlocks.add( + section( + section -> + section.fields(List.of(errorUserIdMarkdown, errorUserIpMarkdown)))); + + layoutBlocks.add(divider()); + String errorStack = slackProvider.getErrorStack(throwable); + String message = throwable.toString(); + MarkdownTextObject errorNameMarkdown = + MarkdownTextObject.builder().text("* Message :*\n" + message).build(); + MarkdownTextObject errorStackMarkdown = + MarkdownTextObject.builder().text("* Stack Trace :*\n" + errorStack).build(); + layoutBlocks.add( + section(section -> section.fields(List.of(errorNameMarkdown, errorStackMarkdown)))); + slackProvider.sendNotification(layoutBlocks); + } + + private String getParamsToString(Object[] params) { + StringBuilder paramToString = new StringBuilder(); + for (Object param : params) { + paramToString.append(param.toString()); + } + return paramToString.toString(); + } +} diff --git a/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/slack/SlackProvider.java b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/slack/SlackProvider.java new file mode 100644 index 00000000..ae6daa75 --- /dev/null +++ b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/slack/SlackProvider.java @@ -0,0 +1,63 @@ +package band.gosrock.infrastructure.config.slack; + + +import com.slack.api.methods.MethodsClient; +import com.slack.api.methods.SlackApiException; +import com.slack.api.methods.request.chat.ChatPostMessageRequest; +import com.slack.api.model.block.LayoutBlock; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.env.Environment; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +@Component +@RequiredArgsConstructor +@Slf4j +public class SlackProvider { + + private final Environment env; + + private final List sendAlarmProfiles = List.of("staging", "prod"); + private final int MAX_LEN = 500; + + @Value("${slack.webhook.id}") + private String CHANNEL_ID; + + private final MethodsClient methodsClient; + + private Boolean isNeedToNotificationProfile() { + String[] activeProfiles = env.getActiveProfiles(); + List currentProfile = Arrays.stream(activeProfiles).toList(); + return CollectionUtils.containsAny(sendAlarmProfiles, currentProfile); + } + + public String getErrorStack(Throwable throwable) { + String exceptionAsString = Arrays.toString(throwable.getStackTrace()); + int cutLength = Math.min(exceptionAsString.length(), MAX_LEN); + return exceptionAsString.substring(0, cutLength); + } + + @Async + public void sendNotification(List layoutBlocks) { + if (!isNeedToNotificationProfile()) { + return; + } + ChatPostMessageRequest chatPostMessageRequest = + ChatPostMessageRequest.builder() + .channel(CHANNEL_ID) + .text("") + .blocks(layoutBlocks) + .build(); + try { + methodsClient.chatPostMessage(chatPostMessageRequest); + } catch (SlackApiException | IOException slackApiException) { + log.error(slackApiException.toString()); + } + } +} diff --git a/DuDoong-Infrastructure/src/main/resources/application-infrastructure.yml b/DuDoong-Infrastructure/src/main/resources/application-infrastructure.yml index f776b5e4..ab643117 100644 --- a/DuDoong-Infrastructure/src/main/resources/application-infrastructure.yml +++ b/DuDoong-Infrastructure/src/main/resources/application-infrastructure.yml @@ -15,9 +15,7 @@ spring: slack: webhook: token: ${SLACK_WEBHOOK_TOKEN:} - - - + id: ${SLACK_WEBHOOK_ID:} --- From 5278a0a8ed24adf4587da9c1ee95c168e28a0ba4 Mon Sep 17 00:00:00 2001 From: Chan Jin Date: Wed, 8 Feb 2023 19:46:43 +0900 Subject: [PATCH 6/7] =?UTF-8?q?feat=20:=20=EC=9C=A0=EC=A0=80=20=EB=A7=88?= =?UTF-8?q?=EC=A7=80=EB=A7=89=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=8B=9C?= =?UTF-8?q?=EC=A0=90=20=EC=A0=81=EC=9A=A9=20(#321)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../band/gosrock/api/auth/service/RefreshUseCase.java | 5 ++++- .../api/auth/service/helper/TokenGenerateHelper.java | 2 ++ .../band/gosrock/domain/domains/user/domain/User.java | 4 ++++ .../domain/domains/user/service/UserDomainService.java | 9 +-------- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/auth/service/RefreshUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/auth/service/RefreshUseCase.java index 40e21e21..693dac41 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/auth/service/RefreshUseCase.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/auth/service/RefreshUseCase.java @@ -9,6 +9,7 @@ import band.gosrock.domain.domains.user.adaptor.UserAdaptor; import band.gosrock.domain.domains.user.domain.RefreshTokenEntity; import band.gosrock.domain.domains.user.domain.User; +import band.gosrock.domain.domains.user.service.UserDomainService; import lombok.RequiredArgsConstructor; @UseCase @@ -17,6 +18,7 @@ public class RefreshUseCase { private final UserAdaptor userAdaptor; private final JwtTokenProvider jwtTokenProvider; + private final UserDomainService userDomainService; private final RefreshTokenAdaptor refreshTokenAdaptor; private final TokenGenerateHelper tokenGenerateHelper; @@ -29,7 +31,8 @@ public TokenAndUserResponse execute(String refreshToken) { jwtTokenProvider.parseRefreshToken(savedRefreshTokenEntity.getRefreshToken()); User user = userAdaptor.queryUser(refreshUserId); - + // 리프레쉬 시에도 last로그인 정보 업데이트 + userDomainService.loginUser(user.getOauthInfo()); return tokenGenerateHelper.execute(user); } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/auth/service/helper/TokenGenerateHelper.java b/DuDoong-Api/src/main/java/band/gosrock/api/auth/service/helper/TokenGenerateHelper.java index 239d6331..35a1627b 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/auth/service/helper/TokenGenerateHelper.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/auth/service/helper/TokenGenerateHelper.java @@ -9,6 +9,7 @@ import band.gosrock.domain.domains.user.domain.RefreshTokenEntity; import band.gosrock.domain.domains.user.domain.User; import lombok.RequiredArgsConstructor; +import org.springframework.transaction.annotation.Transactional; @Helper @RequiredArgsConstructor @@ -18,6 +19,7 @@ public class TokenGenerateHelper { private final RefreshTokenAdaptor refreshTokenAdaptor; + @Transactional public TokenAndUserResponse execute(User user) { String newAccessToken = jwtTokenProvider.generateAccessToken( diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/user/domain/User.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/user/domain/User.java index 11b90742..d554fb71 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/user/domain/User.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/user/domain/User.java @@ -9,6 +9,7 @@ import band.gosrock.domain.domains.user.exception.AlreadyDeletedUserException; import band.gosrock.domain.domains.user.exception.ForbiddenUserException; import band.gosrock.infrastructure.config.mail.dto.EmailUserInfo; +import java.time.LocalDateTime; import javax.persistence.Column; import javax.persistence.Embedded; import javax.persistence.Entity; @@ -46,6 +47,8 @@ public class User extends BaseTimeEntity { @Enumerated(EnumType.STRING) private AccountRole accountRole = AccountRole.USER; + private LocalDateTime lastLoginAt = LocalDateTime.now(); + @Builder public User(Profile profile, OauthInfo oauthInfo) { this.profile = profile; @@ -74,6 +77,7 @@ public void login() { if (!AccountState.NORMAL.equals(this.accountState)) { throw ForbiddenUserException.EXCEPTION; } + lastLoginAt = LocalDateTime.now(); } public UserInfoVo toUserInfoVo() { diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/user/service/UserDomainService.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/user/service/UserDomainService.java index ea45ebee..4bda32b3 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/user/service/UserDomainService.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/user/service/UserDomainService.java @@ -50,6 +50,7 @@ public void validUserCanRegister(OauthInfo oauthInfo) { if (!checkUserCanRegister(oauthInfo)) throw AlreadySignUpUserException.EXCEPTION; } + @Transactional public User loginUser(OauthInfo oauthInfo) { User user = userAdaptor.queryUserByOauthInfo(oauthInfo); user.login(); @@ -62,12 +63,4 @@ public void withDrawUser(Long userId) { User user = userAdaptor.queryUser(userId); user.withDrawUser(); } - - /* - 유저 id로 유저 가져오기 작성 - 민준 - */ - @Transactional(readOnly = true) - public User retrieveUser(Long userId) { - return userAdaptor.queryUser(userId); - } } From 9d34dfa878447dc4d157e4830d50783197dd7716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EA=B2=BD=EB=AF=BC?= Date: Wed, 8 Feb 2023 23:04:52 +0900 Subject: [PATCH 7/7] =?UTF-8?q?refactor=20:=20=EC=9D=B4=EB=B2=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=98=A4=ED=94=88=20api=20=EB=B6=84=EB=A6=AC=20(#320)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor : 이벤트 오픈 api 분리 * refactor : 레이어 분리 * refactor : 티켓 아이템 서비스 참조 --- .../api/event/controller/EventController.java | 9 ++++- .../api/event/service/OpenEventUseCase.java | 27 +++++++++++++ .../domain/domains/event/domain/Event.java | 16 ++++---- .../AlreadyCalculatingStatusException.java | 13 +++++++ .../AlreadyCloseStatusException.java | 13 +++++++ .../exception/AlreadyOpenStatusException.java | 13 +++++++ .../AlreadyPreparingStatusException.java | 13 +++++++ .../exception/CannotOpenEventException.java | 13 +++++++ .../event/exception/EventErrorCode.java | 13 +++++-- .../event/exception/UseOtherApiException.java | 13 +++++++ .../domains/event/service/EventService.java | 38 +++++++++++++------ .../service/TicketItemService.java | 7 ++++ 12 files changed, 164 insertions(+), 24 deletions(-) create mode 100644 DuDoong-Api/src/main/java/band/gosrock/api/event/service/OpenEventUseCase.java create mode 100644 DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/AlreadyCalculatingStatusException.java create mode 100644 DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/AlreadyCloseStatusException.java create mode 100644 DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/AlreadyOpenStatusException.java create mode 100644 DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/AlreadyPreparingStatusException.java create mode 100644 DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/CannotOpenEventException.java create mode 100644 DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/UseOtherApiException.java diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/controller/EventController.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/controller/EventController.java index c06cb73d..679f7f18 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/event/controller/EventController.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/controller/EventController.java @@ -36,6 +36,7 @@ public class EventController { private final UpdateEventBasicUseCase updateEventBasicUseCase; private final UpdateEventDetailUseCase updateEventDetailUseCase; private final UpdateEventStatusUseCase updateEventStatusUseCase; + private final OpenEventUseCase openEventStatusUseCase; @Operation(summary = "자신이 관리 중인 이벤트 리스트를 가져옵니다.") @GetMapping @@ -79,7 +80,13 @@ public EventResponse updateEventDetail( return updateEventDetailUseCase.execute(eventId, updateEventDetailRequest); } - @Operation(summary = "공연 상태를 변경합니다.") + @Operation(summary = "공연을 오픈 상태로 변경합니다. 모든 체크리스트를 달성해야 합니다.") + @PatchMapping("/{eventId}/open") + public EventResponse updateEventStatus(@PathVariable Long eventId) { + return openEventStatusUseCase.execute(eventId); + } + + @Operation(summary = "공연 상태를 변경합니다. (OPEN 제외)") @PatchMapping("/{eventId}/status") public EventResponse updateEventStatus( @PathVariable Long eventId, diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/service/OpenEventUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/service/OpenEventUseCase.java new file mode 100644 index 00000000..fbcc331b --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/service/OpenEventUseCase.java @@ -0,0 +1,27 @@ +package band.gosrock.api.event.service; + +import static band.gosrock.api.common.aop.hostRole.FindHostFrom.EVENT_ID; +import static band.gosrock.api.common.aop.hostRole.HostQualification.MANAGER; + +import band.gosrock.api.common.aop.hostRole.HostRolesAllowed; +import band.gosrock.api.event.model.dto.response.EventResponse; +import band.gosrock.common.annotation.UseCase; +import band.gosrock.domain.domains.event.adaptor.EventAdaptor; +import band.gosrock.domain.domains.event.domain.Event; +import band.gosrock.domain.domains.event.service.EventService; +import lombok.RequiredArgsConstructor; +import org.springframework.transaction.annotation.Transactional; + +@UseCase +@RequiredArgsConstructor +public class OpenEventUseCase { + private final EventService eventService; + private final EventAdaptor eventAdaptor; + + @Transactional + @HostRolesAllowed(role = MANAGER, findHostFrom = EVENT_ID) + public EventResponse execute(Long eventId) { + final Event event = eventAdaptor.findById(eventId); + return EventResponse.of(eventService.openEvent(event)); + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/Event.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/Event.java index 3d4620d1..2c41ec66 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/Event.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/Event.java @@ -3,10 +3,7 @@ import band.gosrock.domain.common.model.BaseTimeEntity; import band.gosrock.domain.common.vo.*; -import band.gosrock.domain.domains.event.exception.CannotModifyEventBasicException; -import band.gosrock.domain.domains.event.exception.EventCannotEndBeforeStartException; -import band.gosrock.domain.domains.event.exception.EventNotOpenException; -import band.gosrock.domain.domains.event.exception.EventTicketingTimeIsPassedException; +import band.gosrock.domain.domains.event.exception.*; import java.time.LocalDateTime; import javax.persistence.*; import lombok.AccessLevel; @@ -156,22 +153,23 @@ public EventPlaceVo toEventPlaceVo() { } public void prepare() { - // TODO : 오픈할수 있는 상태인지 검증필요함. + if (this.status == EventStatus.PREPARING) throw AlreadyPreparingStatusException.EXCEPTION; this.status = EventStatus.PREPARING; } public void open() { - // TODO : 오픈할수 있는 상태인지 검증필요함. + if (this.status == EventStatus.OPEN) throw AlreadyOpenStatusException.EXCEPTION; this.status = EventStatus.OPEN; } public void calculate() { - // TODO : 오픈할수 있는 상태인지 검증필요함. + if (this.status == EventStatus.CALCULATING) + throw AlreadyCalculatingStatusException.EXCEPTION; this.status = EventStatus.CALCULATING; } public void close() { - // TODO : 오픈할수 있는 상태인지 검증필요함. - this.status = EventStatus.OPEN; + if (this.status == EventStatus.CLOSED) throw AlreadyCloseStatusException.EXCEPTION; + this.status = EventStatus.CLOSED; } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/AlreadyCalculatingStatusException.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/AlreadyCalculatingStatusException.java new file mode 100644 index 00000000..efcfd5cd --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/AlreadyCalculatingStatusException.java @@ -0,0 +1,13 @@ +package band.gosrock.domain.domains.event.exception; + + +import band.gosrock.common.exception.DuDoongCodeException; + +public class AlreadyCalculatingStatusException extends DuDoongCodeException { + + public static final DuDoongCodeException EXCEPTION = new AlreadyCalculatingStatusException(); + + private AlreadyCalculatingStatusException() { + super(EventErrorCode.ALREADY_CALCULATING_STATUS); + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/AlreadyCloseStatusException.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/AlreadyCloseStatusException.java new file mode 100644 index 00000000..36259e53 --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/AlreadyCloseStatusException.java @@ -0,0 +1,13 @@ +package band.gosrock.domain.domains.event.exception; + + +import band.gosrock.common.exception.DuDoongCodeException; + +public class AlreadyCloseStatusException extends DuDoongCodeException { + + public static final DuDoongCodeException EXCEPTION = new AlreadyCloseStatusException(); + + private AlreadyCloseStatusException() { + super(EventErrorCode.ALREADY_CLOSE_STATUS); + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/AlreadyOpenStatusException.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/AlreadyOpenStatusException.java new file mode 100644 index 00000000..5615b97f --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/AlreadyOpenStatusException.java @@ -0,0 +1,13 @@ +package band.gosrock.domain.domains.event.exception; + + +import band.gosrock.common.exception.DuDoongCodeException; + +public class AlreadyOpenStatusException extends DuDoongCodeException { + + public static final DuDoongCodeException EXCEPTION = new AlreadyOpenStatusException(); + + private AlreadyOpenStatusException() { + super(EventErrorCode.ALREADY_OPEN_STATUS); + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/AlreadyPreparingStatusException.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/AlreadyPreparingStatusException.java new file mode 100644 index 00000000..3008da3d --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/AlreadyPreparingStatusException.java @@ -0,0 +1,13 @@ +package band.gosrock.domain.domains.event.exception; + + +import band.gosrock.common.exception.DuDoongCodeException; + +public class AlreadyPreparingStatusException extends DuDoongCodeException { + + public static final DuDoongCodeException EXCEPTION = new AlreadyPreparingStatusException(); + + private AlreadyPreparingStatusException() { + super(EventErrorCode.ALREADY_PREPARING_STATUS); + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/CannotOpenEventException.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/CannotOpenEventException.java new file mode 100644 index 00000000..2cc613f1 --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/CannotOpenEventException.java @@ -0,0 +1,13 @@ +package band.gosrock.domain.domains.event.exception; + + +import band.gosrock.common.exception.DuDoongCodeException; + +public class CannotOpenEventException extends DuDoongCodeException { + + public static final DuDoongCodeException EXCEPTION = new CannotOpenEventException(); + + private CannotOpenEventException() { + super(EventErrorCode.CANNOT_OPEN_EVENT); + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/EventErrorCode.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/EventErrorCode.java index 90b9f8f9..803bea2e 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/EventErrorCode.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/EventErrorCode.java @@ -15,14 +15,21 @@ @AllArgsConstructor public enum EventErrorCode implements BaseErrorCode { EVENT_NOT_FOUND(NOT_FOUND, "Event_404_1", "이벤트를 찾을 수 없습니다."), - HOST_NOT_AUTH_EVENT(BAD_REQUEST, "Event_400_1", "Host Not Auth Event."), + HOST_NOT_AUTH_EVENT(BAD_REQUEST, "Event_400_1", "Host Not Auth Event."), EVENT_CANNOT_END_BEFORE_START(BAD_REQUEST, "Event_400_2", "시작 시각은 종료 시각보다 빨라야 합니다."), - EVENT_URL_NAME_ALREADY_EXIST(BAD_REQUEST, "Event_400_3", "중복된 URL 표시 이름입니다."), CANNOT_MODIFY_EVENT_BASIC(BAD_REQUEST, "Event_400_4", "이벤트 기본 정보는 수정할 수 없습니다."), EVENT_NOT_OPEN(BAD_REQUEST, "Event_400_5", "아직 오픈되지 않은 이벤트에는 접근할 수 없습니다."), - EVENT_TICKETING_TIME_IS_PASSED(BAD_REQUEST, "Event_400_6", "이벤트 시작시간이 지나 티켓팅을 할 수 없습니다."); + EVENT_TICKETING_TIME_IS_PASSED(BAD_REQUEST, "Event_400_6", "이벤트 시작시간이 지나 티켓팅을 할 수 없습니다."), + CANNOT_OPEN_EVENT(BAD_REQUEST, "Event_400_7", "이벤트 오픈 조건을 충족하지 않았습니다."), + ALREADY_OPEN_STATUS(BAD_REQUEST, "Event_400_8", "이미 오픈 중인 이벤트입니다."), + ALREADY_CALCULATING_STATUS(BAD_REQUEST, "Event_400_9", "이미 정산중인 이벤트입니다."), + ALREADY_CLOSE_STATUS(BAD_REQUEST, "Event_400_10", "이미 닫은 이벤트입니다."), + ALREADY_PREPARING_STATUS(BAD_REQUEST, "Event_400_11", "이미 준비중인 이벤트입니다."), + + USE_OTHER_API(BAD_REQUEST, "Event_400_8", "잘못된 접근입니다."); + private Integer status; private String code; private String reason; diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/UseOtherApiException.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/UseOtherApiException.java new file mode 100644 index 00000000..ec296a3b --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/UseOtherApiException.java @@ -0,0 +1,13 @@ +package band.gosrock.domain.domains.event.exception; + + +import band.gosrock.common.exception.DuDoongCodeException; + +public class UseOtherApiException extends DuDoongCodeException { + + public static final DuDoongCodeException EXCEPTION = new UseOtherApiException(); + + private UseOtherApiException() { + super(EventErrorCode.USE_OTHER_API); + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/service/EventService.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/service/EventService.java index e6998607..0a4c4f33 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/service/EventService.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/service/EventService.java @@ -4,8 +4,10 @@ import band.gosrock.common.annotation.DomainService; import band.gosrock.domain.domains.event.adaptor.EventAdaptor; import band.gosrock.domain.domains.event.domain.*; -import band.gosrock.domain.domains.event.exception.HostNotAuthEventException; +import band.gosrock.domain.domains.event.exception.CannotOpenEventException; +import band.gosrock.domain.domains.event.exception.UseOtherApiException; import band.gosrock.domain.domains.event.repository.EventRepository; +import band.gosrock.domain.domains.ticket_item.service.TicketItemService; import lombok.RequiredArgsConstructor; import org.springframework.transaction.annotation.Transactional; @@ -15,6 +17,7 @@ public class EventService { private final EventRepository eventRepository; private final EventAdaptor eventAdaptor; + private final TicketItemService ticketItemService; public Event createEvent(Event event) { return eventRepository.save(event); @@ -36,19 +39,32 @@ public Event updateEventPlace(Event event, EventPlace eventPlace) { return eventRepository.save(event); } + public void validateEventBasicExistence(Event event) { + if (!event.hasEventBasic() || !event.hasEventPlace()) { + throw CannotOpenEventException.EXCEPTION; + } + } + + public void validateEventDetailExistence(Event event) { + if (!event.hasEventDetail()) { + throw CannotOpenEventException.EXCEPTION; + } + } + + public Event openEvent(Event event) { + this.validateEventBasicExistence(event); + this.validateEventDetailExistence(event); + ticketItemService.validateExistenceByEventId(event.getId()); + event.open(); + return eventRepository.save(event); + } + public Event updateEventStatus(Event event, EventStatus status) { - // todo :: 이벤트 상태 변경시 검증 필요 - if (status == EventStatus.OPEN) event.open(); - else if (status == EventStatus.CLOSED) event.close(); + if (status == EventStatus.OPEN) { + throw UseOtherApiException.EXCEPTION; // open 은 다른 API 강제 + } else if (status == EventStatus.CLOSED) event.close(); else if (status == EventStatus.CALCULATING) event.calculate(); else if (status == EventStatus.PREPARING) event.prepare(); return eventRepository.save(event); } - - public void checkEventHost(Long hostId, Long eventId) { - Event event = eventAdaptor.findById(eventId); - if (!event.getHostId().equals(hostId)) { - throw HostNotAuthEventException.EXCEPTION; - } - } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/service/TicketItemService.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/service/TicketItemService.java index fdabd704..b08c2d01 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/service/TicketItemService.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/service/TicketItemService.java @@ -5,6 +5,7 @@ import band.gosrock.domain.common.aop.redissonLock.RedissonLock; import band.gosrock.domain.domains.ticket_item.adaptor.TicketItemAdaptor; import band.gosrock.domain.domains.ticket_item.domain.TicketItem; +import band.gosrock.domain.domains.ticket_item.exception.InvalidTicketItemException; import lombok.RequiredArgsConstructor; import org.springframework.transaction.annotation.Transactional; @@ -23,6 +24,12 @@ public TicketItem createTicketItem(TicketItem ticketItem, Boolean isPartner) { return ticketItemAdaptor.save(ticketItem); } + public void validateExistenceByEventId(Long eventId) { + if (!ticketItemAdaptor.existsByEventId(eventId)) { + throw InvalidTicketItemException.EXCEPTION; + } + } + @RedissonLock(LockName = "티켓관리", identifier = "ticketItemId") public void softDeleteTicketItem(Long eventId, Long ticketItemId) {