diff --git a/DuDoong-Api/build.gradle b/DuDoong-Api/build.gradle index 39e18a3a..41a10b78 100644 --- a/DuDoong-Api/build.gradle +++ b/DuDoong-Api/build.gradle @@ -14,7 +14,6 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springdoc:springdoc-openapi-ui:1.6.12' implementation 'org.springframework.boot:spring-boot-starter-security' - implementation project(':DuDoong-Domain') implementation project(':DuDoong-Common') implementation project(':DuDoong-Infrastructure') diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/cart/docs/CreateCartExceptionDocs.java b/DuDoong-Api/src/main/java/band/gosrock/api/cart/docs/CreateCartExceptionDocs.java index 38749976..35a20c29 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/cart/docs/CreateCartExceptionDocs.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/cart/docs/CreateCartExceptionDocs.java @@ -8,7 +8,7 @@ import band.gosrock.domain.domains.cart.exception.CartInvalidOptionAnswerException; import band.gosrock.domain.domains.cart.exception.CartItemNotOneTypeException; import band.gosrock.domain.domains.cart.exception.CartNotAnswerAllOptionGroupException; -import band.gosrock.domain.domains.event.exception.EventIsNotOpenStatusException; +import band.gosrock.domain.domains.event.exception.EventNotOpenException; import band.gosrock.domain.domains.event.exception.EventTicketingTimeIsPassedException; import band.gosrock.domain.domains.ticket_item.exception.TicketItemQuantityLackException; import band.gosrock.domain.domains.ticket_item.exception.TicketPurchaseLimitException; @@ -23,7 +23,7 @@ public class CreateCartExceptionDocs implements SwaggerExampleExceptions { public DuDoongCodeException 응답_다대답_안했을때 = CartNotAnswerAllOptionGroupException.EXCEPTION; @ExplainError("이벤트가 열린 상태가 아닐때") - public DuDoongCodeException 이벤트_닫힘 = EventIsNotOpenStatusException.EXCEPTION; + public DuDoongCodeException 이벤트_닫힘 = EventNotOpenException.EXCEPTION; @ExplainError("이벤트 티켓팅 시간이 지났을때.") public DuDoongCodeException 티켓팅_시간지남 = EventTicketingTimeIsPassedException.EXCEPTION; diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/FindHostFrom.java b/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/FindHostFrom.java new file mode 100644 index 00000000..8369a764 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/FindHostFrom.java @@ -0,0 +1,16 @@ +package band.gosrock.api.common.aop.hostRole; + + +import lombok.Getter; + +@Getter +public enum FindHostFrom { + HOST_ID("hostId"), + EVENT_ID("eventId"); + + private final String identifier; + + FindHostFrom(String identifier) { + this.identifier = identifier; + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostCallTransactionFactory.java b/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostCallTransactionFactory.java new file mode 100644 index 00000000..53cf8592 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostCallTransactionFactory.java @@ -0,0 +1,20 @@ +package band.gosrock.api.common.aop.hostRole; + + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@RequiredArgsConstructor +@Component +public class HostCallTransactionFactory { + + private final HostRoleEventTransaction hostRoleEventTransaction; + private final HostRoleHostTransaction hostRoleHostTransaction; + + public HostRoleCallTransaction getCallTransaction(FindHostFrom findHostFrom) { + if (findHostFrom == FindHostFrom.HOST_ID) { + return hostRoleHostTransaction; + } + return hostRoleEventTransaction; + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostQualification.java b/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostQualification.java new file mode 100644 index 00000000..60ef994d --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostQualification.java @@ -0,0 +1,27 @@ +package band.gosrock.api.common.aop.hostRole; + + +import band.gosrock.domain.domains.host.domain.Host; +import java.util.function.BiConsumer; + +/** 각 권한에 맞춰서 host 도메인의 검증메소드를 실행시킵니다. 검증 메소드이므로 biConsumer 를 통해 실행 시킬 함수를 미리 생성해 둡니다. -이찬진 */ +public enum HostQualification { + MASTER((userId, host) -> host.validateMasterHostUser(userId)), + MANAGER((userId, host) -> host.validateManagerHostUser(userId)), + GUEST((userId, host) -> host.validateActiveHostUser(userId)); + private final BiConsumer consumer; + + HostQualification(BiConsumer consumer) { + this.consumer = consumer; + } + + /** + * 호스트의 검증을 수행하는 메서드 + * + * @param userId + * @param host + */ + public void validQualification(Long userId, Host host) { + consumer.accept(userId, host); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostRoleAop.java b/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostRoleAop.java new file mode 100644 index 00000000..42da6578 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostRoleAop.java @@ -0,0 +1,60 @@ +package band.gosrock.api.common.aop.hostRole; + + +import java.lang.reflect.Method; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; + +/** + * 호스트 관리자 인가를 위한 aop 입니다 메소드 레벨에서 작동하며 권한 정보를 어노테이션으로 받고 eventId를 인자에서 찾아와 호스트 정보를 불러온뒤 권한 검증을 합니다. + */ +@Aspect +@Component +@RequiredArgsConstructor +@Slf4j +@ConditionalOnExpression("${ableHostRoleAop:true}") +public class HostRoleAop { + private final HostCallTransactionFactory hostCallTransactionFactory; + + /** + * master 호스트의 마스터 manager 호스트의 수정,조회 ( 호스트유저도메인의 슈퍼 호스트 ) guest 호스트의 조회권한 (호스트유저도메인의 호스트 ) + * + * @see band.gosrock.domain.domains.host.domain.HostRole + */ + @Around("@annotation(band.gosrock.api.common.aop.hostRole.HostRolesAllowed)") + public Object aop(final ProceedingJoinPoint joinPoint) throws Throwable { + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + HostRolesAllowed annotation = method.getAnnotation(HostRolesAllowed.class); + HostQualification hostQualification = annotation.role(); + // 제공된 호스트의 role 이 정의된 세개의 롤과 같은지 확인한다. + // 없으면 IllegalArgumentException 발생 + FindHostFrom findHostFrom = annotation.findHostFrom(); + String identifier = findHostFrom.getIdentifier(); + + String[] parameterNames = signature.getParameterNames(); + Object[] args = joinPoint.getArgs(); + + Long id = getId(parameterNames, args, identifier); + + return hostCallTransactionFactory + .getCallTransaction(findHostFrom) + .proceed(id, hostQualification, joinPoint); + } + + public Long getId(String[] parameterNames, Object[] args, String paramName) { + for (int i = 0; i < parameterNames.length; i++) { + if (parameterNames[i].equals(paramName)) { + // 롱타입이라 가정. 안되면 classCastException 터트림 + return (Long) args[i]; + } + } + throw new IllegalArgumentException(); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostRoleCallTransaction.java b/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostRoleCallTransaction.java new file mode 100644 index 00000000..38db54ed --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostRoleCallTransaction.java @@ -0,0 +1,9 @@ +package band.gosrock.api.common.aop.hostRole; + + +import org.aspectj.lang.ProceedingJoinPoint; + +public interface HostRoleCallTransaction { + Object proceed(Long id, HostQualification role, final ProceedingJoinPoint joinPoint) + throws Throwable; +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostRoleEventTransaction.java b/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostRoleEventTransaction.java new file mode 100644 index 00000000..ea551557 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostRoleEventTransaction.java @@ -0,0 +1,34 @@ +package band.gosrock.api.common.aop.hostRole; + + +import band.gosrock.api.common.UserUtils; +import band.gosrock.domain.domains.event.adaptor.EventAdaptor; +import band.gosrock.domain.domains.event.domain.Event; +import band.gosrock.domain.domains.host.adaptor.HostAdaptor; +import band.gosrock.domain.domains.host.domain.Host; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +/** 호스트 정보를 트랜잭션 안에서 조회하기 위해서 만든 클래스입니다. 트랜잭션 내에서 캐시 할수 있으면 좋으니 이렇게 만들었습니다. - 이찬진 */ +@Component +@RequiredArgsConstructor +@Slf4j +public class HostRoleEventTransaction implements HostRoleCallTransaction { + + private final UserUtils userUtils; + private final EventAdaptor eventAdaptor; + private final HostAdaptor hostAdaptor; + + @Transactional(readOnly = true) + public Object proceed(Long eventId, HostQualification role, final ProceedingJoinPoint joinPoint) + throws Throwable { + Long currentUserId = userUtils.getCurrentUserId(); + Event event = eventAdaptor.findById(eventId); + Host host = hostAdaptor.findById(event.getHostId()); + role.validQualification(currentUserId, host); + return joinPoint.proceed(); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostRoleHostTransaction.java b/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostRoleHostTransaction.java new file mode 100644 index 00000000..f9443441 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostRoleHostTransaction.java @@ -0,0 +1,30 @@ +package band.gosrock.api.common.aop.hostRole; + + +import band.gosrock.api.common.UserUtils; +import band.gosrock.domain.domains.host.adaptor.HostAdaptor; +import band.gosrock.domain.domains.host.domain.Host; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +/** 호스트 정보를 트랜잭션 안에서 조회하기 위해서 만든 클래스입니다. 트랜잭션 내에서 캐시 할수 있으면 좋으니 이렇게 만들었습니다. - 이찬진 */ +@Component +@RequiredArgsConstructor +@Slf4j +public class HostRoleHostTransaction implements HostRoleCallTransaction { + + private final UserUtils userUtils; + private final HostAdaptor hostAdaptor; + + @Transactional(readOnly = true) + public Object proceed(Long hostId, HostQualification role, final ProceedingJoinPoint joinPoint) + throws Throwable { + Long currentUserId = userUtils.getCurrentUserId(); + Host host = hostAdaptor.findById(hostId); + role.validQualification(currentUserId, host); + return joinPoint.proceed(); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostRolesAllowed.java b/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostRolesAllowed.java new file mode 100644 index 00000000..a37b9efb --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/common/aop/hostRole/HostRolesAllowed.java @@ -0,0 +1,21 @@ +package band.gosrock.api.common.aop.hostRole; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** HostRoles aop 를 적용하기 위해 다는 어노테이션 - 이찬진 */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HostRolesAllowed { + /** + * 세가지 값을 가짐 "MASTER","MANAGER","GUEST" 권한 정보는 + * + * @see HostRoleAop + */ + HostQualification role(); + + FindHostFrom findHostFrom(); +} 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 6328a933..214faf42 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 @@ -1,6 +1,8 @@ package band.gosrock.api.config.response; +import band.gosrock.api.config.security.SecurityUtils; +import band.gosrock.api.config.slack.SlackApiProvider; import band.gosrock.common.dto.ErrorReason; import band.gosrock.common.dto.ErrorResponse; import band.gosrock.common.exception.BaseErrorCode; @@ -37,6 +39,7 @@ @RequiredArgsConstructor public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { + private final SlackApiProvider slackApiProvider; // /** Json 날짜 형식 파싱에 대한 에러 핸들러 */ // @ExceptionHandler({ InvalidFormatException.class, DateTimeParseException.class}) // public ResponseEntity JsonParseExceptionHandler( @@ -163,6 +166,7 @@ public ResponseEntity DuDoongDynamicExceptionHandler( protected ResponseEntity handleException(Exception e, HttpServletRequest request) throws IOException { final ContentCachingRequestWrapper cachingRequest = (ContentCachingRequestWrapper) request; + final Long userId = SecurityUtils.getCurrentUserId(); String url = UriComponentsBuilder.fromHttpRequest(new ServletServerHttpRequest(request)) .build() @@ -176,8 +180,8 @@ protected ResponseEntity handleException(Exception e, HttpServlet internalServerError.getCode(), internalServerError.getReason(), url); - // TODO : 슬랙 오류 발송 - // slackProvider.sendError(url, cachingRequest, e); + + slackApiProvider.sendError(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/config/slack/SlackApiProvider.java new file mode 100644 index 00000000..a4732f93 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/config/slack/SlackApiProvider.java @@ -0,0 +1,114 @@ +package band.gosrock.api.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.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; + private final ObjectMapper objectMapper; + + private final Environment env; + + 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) + 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); + final String errorUserIP = cachingRequest.getRemoteAddr(); + + List layoutBlocks = new ArrayList<>(); + layoutBlocks.add( + Blocks.header( + headerBlockBuilder -> + headerBlockBuilder.text(plainText("Error Detection")))); + layoutBlocks.add(divider()); + + MarkdownTextObject errorUserIdMarkdown = + MarkdownTextObject.builder().text("* User Id :*\n" + userId).build(); + MarkdownTextObject errorUserIpMarkdown = + MarkdownTextObject.builder().text("* User IP :*\n" + errorUserIP).build(); + layoutBlocks.add( + section( + section -> + section.fields(List.of(errorUserIdMarkdown, errorUserIpMarkdown)))); + + MarkdownTextObject methodMarkdown = + MarkdownTextObject.builder() + .text("* Request Addr :*\n" + method + " : " + url) + .build(); + MarkdownTextObject bodyMarkdown = + MarkdownTextObject.builder().text("* Request Body :*\n" + body).build(); + List fields = List.of(methodMarkdown, bodyMarkdown); + layoutBlocks.add(section(section -> section.fields(fields))); + + layoutBlocks.add(divider()); + + MarkdownTextObject errorNameMarkdown = + MarkdownTextObject.builder().text("* Message :*\n" + errorMessage).build(); + MarkdownTextObject errorStackMarkdown = + MarkdownTextObject.builder().text("* Stack Trace :*\n" + errorStack).build(); + 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()); + } + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/coupon/service/CreateCouponUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/coupon/service/CreateCouponUseCase.java index bc393422..7fd61c17 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/coupon/service/CreateCouponUseCase.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/coupon/service/CreateCouponUseCase.java @@ -28,7 +28,7 @@ public CreateCouponCampaignResponse execute( // 존재하는 유저인지 검증 User user = userUtils.getCurrentUser(); // 슈퍼 호스트인지 검증 - hostService.validateSuperHostUser(createCouponCampaignRequest.getHostId(), user.getId()); + hostService.validateManagerHostUser(createCouponCampaignRequest.getHostId(), user.getId()); // 이미 생성된 쿠폰 코드인지 검증 createCouponCampaignDomainService.checkCouponCodeExists( createCouponCampaignRequest.getCouponCode()); 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 83cf638c..babf43d5 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 @@ -5,12 +5,12 @@ import band.gosrock.api.event.model.dto.request.CreateEventRequest; import band.gosrock.api.event.model.dto.request.UpdateEventBasicRequest; import band.gosrock.api.event.model.dto.request.UpdateEventDetailRequest; +import band.gosrock.api.event.model.dto.request.UpdateEventStatusRequest; +import band.gosrock.api.event.model.dto.response.EventChecklistResponse; +import band.gosrock.api.event.model.dto.response.EventDetailResponse; import band.gosrock.api.event.model.dto.response.EventProfileResponse; import band.gosrock.api.event.model.dto.response.EventResponse; -import band.gosrock.api.event.service.CreateEventUseCase; -import band.gosrock.api.event.service.ReadEventProfileListUseCase; -import band.gosrock.api.event.service.UpdateEventBasicUseCase; -import band.gosrock.api.event.service.UpdateEventDetailUseCase; +import band.gosrock.api.event.service.*; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; @@ -28,18 +28,19 @@ @RequiredArgsConstructor public class EventController { - private final ReadEventProfileListUseCase readHostEventListUseCase; + private final ReadUserEventProfilesUseCase readUserHostEventListUseCase; + private final ReadEventDetailUseCase readEventDetailUseCase; + private final ReadEventChecklistUseCase readEventChecklistUseCase; private final CreateEventUseCase createEventUseCase; private final UpdateEventBasicUseCase updateEventBasicUseCase; private final UpdateEventDetailUseCase updateEventDetailUseCase; + private final UpdateEventStatusUseCase updateEventStatusUseCase; - // todo :: querydsl + 검색 기능 작동하도록 만들기 - @Operation(summary = "특정 호스트가 관리 중인 이벤트 리스트를 가져옵니다") + @Operation(summary = "자신이 관리 중인 이벤트 리스트를 가져옵니다.") @GetMapping - public PageResponse getAllEventByHostId( - @RequestParam Long hostId, + public PageResponse getAllEventByUser( @ParameterObject @PageableDefault(size = 10) Pageable pageable) { - return readHostEventListUseCase.execute(hostId, pageable); + return readUserHostEventListUseCase.execute(pageable); } @Operation(summary = "공연 기본 정보를 등록하여, 새로운 이벤트(공연)를 생성합니다") @@ -48,6 +49,18 @@ public EventResponse createEvent(@RequestBody @Valid CreateEventRequest createEv return createEventUseCase.execute(createEventRequest); } + @Operation(summary = "공연 상세 정보를 가져옵니다.") + @GetMapping("/{eventId}") + public EventDetailResponse getEventDetailById(@PathVariable Long eventId) { + return readEventDetailUseCase.execute(eventId); + } + + @Operation(summary = "공연 체크리스트 가져오기") + @GetMapping("/{eventId}/checklist") + public EventChecklistResponse getEventChecklistById(@PathVariable Long eventId) { + return readEventChecklistUseCase.execute(eventId); + } + @Operation(summary = "공연 기본 정보를 등록하여, 새로운 이벤트(공연)를 생성합니다") @PatchMapping("/{eventId}/basic") public EventResponse updateEventBasic( @@ -63,4 +76,12 @@ public EventResponse updateEventDetail( @RequestBody @Valid UpdateEventDetailRequest updateEventDetailRequest) { return updateEventDetailUseCase.execute(eventId, updateEventDetailRequest); } + + @Operation(summary = "공연 상태를 변경합니다.") + @PatchMapping("/{eventId}/status") + public EventResponse updateEventStatus( + @PathVariable Long eventId, + @RequestBody @Valid UpdateEventStatusRequest updateEventDetailRequest) { + return updateEventStatusUseCase.execute(eventId, updateEventDetailRequest); + } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/request/UpdateEventDetailRequest.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/request/UpdateEventDetailRequest.java index 33b6c816..d3e168aa 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/request/UpdateEventDetailRequest.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/request/UpdateEventDetailRequest.java @@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import lombok.Getter; @@ -16,10 +17,11 @@ public class UpdateEventDetailRequest { // 포스터 이미지 url - @Schema(defaultValue = "https://s3.dudoong.com/image", description = "포스터 이미지 url") - @URL(message = "올바른 url 형식을 입력하세요") - private String posterImage; + @Schema(defaultValue = "test/event/5/aa.jpeg", description = "포스터 이미지 key") + @NotEmpty + private String posterImageKey; + // TODO : 기획에서 제거 예정? @ArraySchema( arraySchema = @Schema( diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/request/UpdateEventStatusRequest.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/request/UpdateEventStatusRequest.java new file mode 100644 index 00000000..66ecf7db --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/request/UpdateEventStatusRequest.java @@ -0,0 +1,17 @@ +package band.gosrock.api.event.model.dto.request; + + +import band.gosrock.common.annotation.Enum; +import band.gosrock.domain.domains.event.domain.EventStatus; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class UpdateEventStatusRequest { + + @Schema(defaultValue = "OPEN", description = "오픈 상태", allowableValues = "OPEN,CLOSED,PREPARING") + @Enum(message = "올바른 값을 입력해주세요.") + private EventStatus status; +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/response/EventChecklistResponse.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/response/EventChecklistResponse.java new file mode 100644 index 00000000..587062d7 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/response/EventChecklistResponse.java @@ -0,0 +1,32 @@ +package band.gosrock.api.event.model.dto.response; + + +import band.gosrock.domain.domains.event.domain.Event; +import lombok.Builder; +import lombok.Getter; + +/** 공연 체크 리스트 응답 DTO */ +@Getter +@Builder +public class EventChecklistResponse { + private Long hostId; + private Long eventId; + private String name; + // 공연 기본 정보 (공연장 위치로 구분) 작성 여부 + private Boolean hasBasic; + // 공연 상세 정보 작성 여부 + private Boolean hasDetail; + // 티켓 상품 설정했는지 여부 + private Boolean hasTicketItem; + + public static EventChecklistResponse of(Event event, Boolean hasTicket) { + return EventChecklistResponse.builder() + .hostId(event.getHostId()) + .eventId(event.getId()) + .name(event.getEventBasic().getName()) + .hasBasic(event.hasEventBasic() && event.hasEventPlace()) + .hasDetail(event.hasEventDetail()) + .hasTicketItem(hasTicket) + .build(); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/response/EventDetailResponse.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/response/EventDetailResponse.java new file mode 100644 index 00000000..c55549cc --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/response/EventDetailResponse.java @@ -0,0 +1,42 @@ +package band.gosrock.api.event.model.dto.response; + + +import band.gosrock.common.annotation.DateFormat; +import band.gosrock.domain.common.vo.EventBasicVo; +import band.gosrock.domain.common.vo.EventDetailVo; +import band.gosrock.domain.common.vo.EventPlaceVo; +import band.gosrock.domain.common.vo.HostInfoVo; +import band.gosrock.domain.domains.event.domain.Event; +import band.gosrock.domain.domains.event.domain.EventStatus; +import band.gosrock.domain.domains.host.domain.Host; +import com.fasterxml.jackson.annotation.JsonUnwrapped; +import java.time.LocalDateTime; +import lombok.Builder; +import lombok.Getter; + +/** 이벤트 디테일 응답 DTO */ +@Getter +@Builder +public class EventDetailResponse { + + private String name; + @DateFormat private LocalDateTime startAt; + private Long runTime; + private EventStatus status; + private HostInfoVo host; + private EventPlaceVo place; + @JsonUnwrapped private EventDetailVo eventDetailVo; + + public static EventDetailResponse of(Host host, Event event) { + EventBasicVo eventBasicVo = event.toEventBasicVo(); + return EventDetailResponse.builder() + .name(eventBasicVo.getName()) + .startAt(eventBasicVo.getStartAt()) + .runTime(eventBasicVo.getRunTime()) + .eventDetailVo(event.toEventDetailVo()) + .place(event.toEventPlaceVo()) + .host(host.toHostInfoVo()) + .status(event.getStatus()) + .build(); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/response/EventProfileResponse.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/response/EventProfileResponse.java index 7d6c806e..5a1c7a45 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/response/EventProfileResponse.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/response/EventProfileResponse.java @@ -3,6 +3,7 @@ import band.gosrock.domain.common.vo.EventProfileVo; import band.gosrock.domain.domains.event.domain.Event; +import band.gosrock.domain.domains.host.domain.Host; import com.fasterxml.jackson.annotation.JsonUnwrapped; import lombok.Builder; import lombok.Getter; @@ -11,9 +12,17 @@ @Getter @Builder public class EventProfileResponse { + private Long hostId; + + private String hostName; + @JsonUnwrapped private EventProfileVo eventProfileVo; - public static EventProfileResponse of(Event event) { - return EventProfileResponse.builder().eventProfileVo(event.toEventProfileVo()).build(); + public static EventProfileResponse of(Host host, Event event) { + return EventProfileResponse.builder() + .hostId(host.getId()) + .hostName(host.getProfile().getName()) + .eventProfileVo(event.toEventProfileVo()) + .build(); } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/response/EventResponse.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/response/EventResponse.java index d017475e..34325ecc 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/response/EventResponse.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/dto/response/EventResponse.java @@ -1,13 +1,12 @@ package band.gosrock.api.event.model.dto.response; -import band.gosrock.common.annotation.DateFormat; import band.gosrock.domain.common.vo.EventBasicVo; import band.gosrock.domain.common.vo.EventDetailVo; import band.gosrock.domain.common.vo.EventPlaceVo; import band.gosrock.domain.domains.event.domain.Event; +import band.gosrock.domain.domains.event.domain.EventStatus; import com.fasterxml.jackson.annotation.JsonUnwrapped; -import java.time.LocalDateTime; import lombok.Builder; import lombok.Getter; @@ -15,18 +14,12 @@ @Builder public class EventResponse { private Long eventId; - private Long hostId; + private EventStatus status; @JsonUnwrapped private EventBasicVo eventBasic; @JsonUnwrapped private EventDetailVo eventDetail; - @JsonUnwrapped private EventPlaceVo eventPlace; - - /*************** 미확정된 정보 ******************/ - @DateFormat private LocalDateTime ticketingStartAt; - - @DateFormat private LocalDateTime ticketingEndAt; - /************* 미확정된 정보 ******************/ + private EventPlaceVo place; public static EventResponse of(Event event) { return EventResponse.builder() @@ -34,9 +27,8 @@ public static EventResponse of(Event event) { .hostId(event.getHostId()) .eventBasic(EventBasicVo.from(event)) .eventDetail(EventDetailVo.from(event)) - .eventPlace(EventPlaceVo.from(event)) - .ticketingStartAt(event.getTicketingStartAt()) - .ticketingEndAt(event.getTicketingEndAt()) + .place(EventPlaceVo.from(event)) + .status(event.getStatus()) .build(); } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/model/mapper/EventMapper.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/mapper/EventMapper.java index be53c95e..ceb42729 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/event/model/mapper/EventMapper.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/model/mapper/EventMapper.java @@ -4,20 +4,31 @@ import band.gosrock.api.event.model.dto.request.CreateEventRequest; import band.gosrock.api.event.model.dto.request.UpdateEventBasicRequest; import band.gosrock.api.event.model.dto.request.UpdateEventDetailRequest; +import band.gosrock.api.event.model.dto.response.EventChecklistResponse; +import band.gosrock.api.event.model.dto.response.EventDetailResponse; +import band.gosrock.api.event.model.dto.response.EventProfileResponse; import band.gosrock.common.annotation.Mapper; +import band.gosrock.domain.domains.event.adaptor.EventAdaptor; import band.gosrock.domain.domains.event.domain.Event; import band.gosrock.domain.domains.event.domain.EventBasic; import band.gosrock.domain.domains.event.domain.EventDetail; import band.gosrock.domain.domains.event.domain.EventPlace; -import band.gosrock.domain.domains.event.service.EventService; +import band.gosrock.domain.domains.host.adaptor.HostAdaptor; +import band.gosrock.domain.domains.host.domain.Host; +import band.gosrock.domain.domains.ticket_item.adaptor.TicketItemAdaptor; +import java.util.List; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.transaction.annotation.Transactional; @Mapper @RequiredArgsConstructor public class EventMapper { - private final EventService eventService; + private final HostAdaptor hostAdaptor; + private final EventAdaptor eventAdaptor; + private final TicketItemAdaptor ticketItemAdaptor; @Transactional(readOnly = true) public Event toEntity(CreateEventRequest createEventRequest) { @@ -39,7 +50,7 @@ public EventBasic toEventBasic(UpdateEventBasicRequest updateEventBasicRequest) public EventDetail toEventDetail(UpdateEventDetailRequest updateEventDetailRequest) { return EventDetail.builder() - .posterImage(updateEventDetailRequest.getPosterImage()) + .posterImageKey(updateEventDetailRequest.getPosterImageKey()) .detailImages(updateEventDetailRequest.getDetailImages()) .content(updateEventDetailRequest.getContent()) .build(); @@ -54,5 +65,26 @@ public EventPlace toEventPlace(UpdateEventBasicRequest updateEventBasicRequest) .build(); } - // todo :: 공연 장소 + public EventDetailResponse toEventDetailResponse(Host host, Event event) { + return EventDetailResponse.of(host, event); + } + + public EventChecklistResponse toEventChecklistResponse(Event event) { + final Boolean hasTicketItem = ticketItemAdaptor.existsByEventId(event.getId()); + return EventChecklistResponse.of(event, hasTicketItem); + } + + public Page toEventProfileResponsePage(Long userId, Pageable pageable) { + List hostList = hostAdaptor.findAllByHostUsers_UserId(userId); + List hostIds = hostList.stream().map(Host::getId).toList(); + Page eventList = eventAdaptor.findAllByHostIdIn(hostIds, pageable); + return eventList.map(event -> this.toEventProfileResponse(hostList, event)); + } + + private EventProfileResponse toEventProfileResponse(List hostList, Event event) { + for (Host host : hostList) { + if (host.getId().equals(event.getHostId())) return EventProfileResponse.of(host, event); + } + return null; + } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/service/CreateEventUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/service/CreateEventUseCase.java index a2d2215b..ea16b698 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/event/service/CreateEventUseCase.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/service/CreateEventUseCase.java @@ -26,7 +26,7 @@ public EventResponse execute(CreateEventRequest createEventRequest) { final User user = userUtils.getCurrentUser(); final Long userId = user.getId(); // 슈퍼 호스트 이상만 공연 생성 가능 - hostService.validateSuperHostUser(createEventRequest.getHostId(), userId); + hostService.validateManagerHostUser(createEventRequest.getHostId(), userId); final Event event = eventMapper.toEntity(createEventRequest); return EventResponse.of(eventService.createEvent(event)); } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/service/ReadEventChecklistUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/service/ReadEventChecklistUseCase.java new file mode 100644 index 00000000..c9bf649d --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/service/ReadEventChecklistUseCase.java @@ -0,0 +1,32 @@ +package band.gosrock.api.event.service; + + +import band.gosrock.api.common.UserUtils; +import band.gosrock.api.event.model.dto.response.EventChecklistResponse; +import band.gosrock.api.event.model.mapper.EventMapper; +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.host.adaptor.HostAdaptor; +import band.gosrock.domain.domains.host.domain.Host; +import lombok.RequiredArgsConstructor; +import org.springframework.transaction.annotation.Transactional; + +@UseCase +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class ReadEventChecklistUseCase { + private final UserUtils userUtils; + private final EventAdaptor eventAdaptor; + private final EventMapper eventMapper; + private final HostAdaptor hostAdaptor; + + public EventChecklistResponse execute(Long eventId) { + final Event event = eventAdaptor.findById(eventId); + final Host host = hostAdaptor.findById(event.getHostId()); + final Long userId = userUtils.getCurrentUserId(); + host.validateHostUser(userId); + + return eventMapper.toEventChecklistResponse(event); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/service/ReadEventDetailUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/service/ReadEventDetailUseCase.java new file mode 100644 index 00000000..264bb3b2 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/service/ReadEventDetailUseCase.java @@ -0,0 +1,36 @@ +package band.gosrock.api.event.service; + + +import band.gosrock.api.common.UserUtils; +import band.gosrock.api.event.model.dto.response.EventDetailResponse; +import band.gosrock.api.event.model.mapper.EventMapper; +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.exception.EventNotOpenException; +import band.gosrock.domain.domains.host.adaptor.HostAdaptor; +import band.gosrock.domain.domains.host.domain.Host; +import lombok.RequiredArgsConstructor; +import org.springframework.transaction.annotation.Transactional; + +@UseCase +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class ReadEventDetailUseCase { + private final UserUtils userUtils; + private final EventAdaptor eventAdaptor; + private final EventMapper eventMapper; + private final HostAdaptor hostAdaptor; + + public EventDetailResponse execute(Long eventId) { + final Event event = eventAdaptor.findById(eventId); + final Host host = hostAdaptor.findById(event.getHostId()); + final Long userId = userUtils.getCurrentUserId(); + + // 호스트 유저가 아닐 경우 준비 상태일 때 조회할 수 없음 + if (event.isPreparing() && !host.hasHostUserId(userId)) { + throw EventNotOpenException.EXCEPTION; + } + return eventMapper.toEventDetailResponse(host, event); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/service/ReadEventProfileListUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/service/ReadEventProfileListUseCase.java deleted file mode 100644 index 58d5e927..00000000 --- a/DuDoong-Api/src/main/java/band/gosrock/api/event/service/ReadEventProfileListUseCase.java +++ /dev/null @@ -1,22 +0,0 @@ -package band.gosrock.api.event.service; - - -import band.gosrock.api.common.page.PageResponse; -import band.gosrock.api.event.model.dto.response.EventProfileResponse; -import band.gosrock.common.annotation.UseCase; -import band.gosrock.domain.domains.event.adaptor.EventAdaptor; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Pageable; -import org.springframework.transaction.annotation.Transactional; - -@UseCase -@RequiredArgsConstructor -@Transactional(readOnly = true) -public class ReadEventProfileListUseCase { - private final EventAdaptor eventAdaptor; - - public PageResponse execute(Long hostId, Pageable pageable) { - return PageResponse.of( - eventAdaptor.findAllByHostId(hostId, pageable).map(EventProfileResponse::of)); - } -} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/service/ReadUserEventProfilesUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/service/ReadUserEventProfilesUseCase.java new file mode 100644 index 00000000..5885a991 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/service/ReadUserEventProfilesUseCase.java @@ -0,0 +1,26 @@ +package band.gosrock.api.event.service; + + +import band.gosrock.api.common.UserUtils; +import band.gosrock.api.common.page.PageResponse; +import band.gosrock.api.event.model.dto.response.EventProfileResponse; +import band.gosrock.api.event.model.mapper.EventMapper; +import band.gosrock.common.annotation.UseCase; +import band.gosrock.domain.domains.user.domain.User; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.transaction.annotation.Transactional; + +@UseCase +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class ReadUserEventProfilesUseCase { + private final UserUtils userUtils; + private final EventMapper eventMapper; + + public PageResponse execute(Pageable pageable) { + final User user = userUtils.getCurrentUser(); + final Long userId = user.getId(); + return PageResponse.of(eventMapper.toEventProfileResponsePage(userId, pageable)); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/service/UpdateEventBasicUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/service/UpdateEventBasicUseCase.java index 40be9a4e..889dcde9 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/event/service/UpdateEventBasicUseCase.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/service/UpdateEventBasicUseCase.java @@ -30,7 +30,7 @@ public EventResponse execute(Long eventId, UpdateEventBasicRequest updateEventBa final User user = userUtils.getCurrentUser(); final Long userId = user.getId(); final Event event = eventAdaptor.findById(eventId); - hostService.validateSuperHostUser(event.getHostId(), userId); + hostService.validateManagerHostUser(event.getHostId(), userId); EventBasic eventBasic = eventMapper.toEventBasic(updateEventBasicRequest); EventPlace eventPlace = eventMapper.toEventPlace(updateEventBasicRequest); diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/service/UpdateEventDetailUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/service/UpdateEventDetailUseCase.java index ca59373b..d2f18884 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/event/service/UpdateEventDetailUseCase.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/service/UpdateEventDetailUseCase.java @@ -1,7 +1,9 @@ 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.UserUtils; +import band.gosrock.api.common.aop.hostRole.HostRolesAllowed; import band.gosrock.api.event.model.dto.request.UpdateEventDetailRequest; import band.gosrock.api.event.model.dto.response.EventResponse; import band.gosrock.api.event.model.mapper.EventMapper; @@ -9,27 +11,20 @@ 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 band.gosrock.domain.domains.host.service.HostService; -import band.gosrock.domain.domains.user.domain.User; import lombok.RequiredArgsConstructor; import org.springframework.transaction.annotation.Transactional; @UseCase @RequiredArgsConstructor public class UpdateEventDetailUseCase { - private final UserUtils userUtils; - private final HostService hostService; private final EventService eventService; private final EventAdaptor eventAdaptor; private final EventMapper eventMapper; @Transactional + @HostRolesAllowed(role = MANAGER, findHostFrom = EVENT_ID) public EventResponse execute(Long eventId, UpdateEventDetailRequest updateEventDetailRequest) { - final User user = userUtils.getCurrentUser(); - final Long userId = user.getId(); final Event event = eventAdaptor.findById(eventId); - hostService.validateSuperHostUser(event.getHostId(), userId); - return EventResponse.of( eventService.updateEventDetail( event, eventMapper.toEventDetail(updateEventDetailRequest))); diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/event/service/UpdateEventStatusUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/event/service/UpdateEventStatusUseCase.java new file mode 100644 index 00000000..7bd9841b --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/event/service/UpdateEventStatusUseCase.java @@ -0,0 +1,35 @@ +package band.gosrock.api.event.service; + + +import band.gosrock.api.common.UserUtils; +import band.gosrock.api.event.model.dto.request.UpdateEventStatusRequest; +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.domain.EventStatus; +import band.gosrock.domain.domains.event.service.EventService; +import band.gosrock.domain.domains.host.service.HostService; +import band.gosrock.domain.domains.user.domain.User; +import lombok.RequiredArgsConstructor; +import org.springframework.transaction.annotation.Transactional; + +@UseCase +@RequiredArgsConstructor +public class UpdateEventStatusUseCase { + private final UserUtils userUtils; + private final HostService hostService; + private final EventService eventService; + private final EventAdaptor eventAdaptor; + + @Transactional + public EventResponse execute(Long eventId, UpdateEventStatusRequest updateEventStatusRequest) { + final User user = userUtils.getCurrentUser(); + final Long userId = user.getId(); + final Event event = eventAdaptor.findById(eventId); + hostService.validateManagerHostUser(event.getHostId(), userId); + final EventStatus status = updateEventStatusRequest.getStatus(); + + return EventResponse.of(eventService.updateEventStatus(event, status)); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/host/controller/HostController.java b/DuDoong-Api/src/main/java/band/gosrock/api/host/controller/HostController.java index 19b4bb4d..1810ef39 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/host/controller/HostController.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/host/controller/HostController.java @@ -4,6 +4,7 @@ import band.gosrock.api.common.page.PageResponse; import band.gosrock.api.host.model.dto.request.*; import band.gosrock.api.host.model.dto.response.HostDetailResponse; +import band.gosrock.api.host.model.dto.response.HostEventProfileResponse; import band.gosrock.api.host.model.dto.response.HostProfileResponse; import band.gosrock.api.host.model.dto.response.HostResponse; import band.gosrock.api.host.service.*; @@ -28,8 +29,9 @@ @Validated public class HostController { private final ReadHostUseCase readHostUseCase; - private final ReadHostProfileListUseCase readHostListUseCase; - private final ReadInviteUserListUseCase readInviteUserListUseCase; + private final ReadHostProfilesUseCase readHostsUseCase; + private final ReadHostEventsUseCase readHostEventsUseCase; + private final ReadInviteUsersUseCase readInviteUsersUseCase; private final CreateHostUseCase createHostUseCase; private final UpdateHostProfileUseCase updateHostProfileUseCase; private final UpdateHostSlackUrlUseCase updateHostSlackUrlUseCase; @@ -41,7 +43,7 @@ public class HostController { @GetMapping public PageResponse getAllHosts( @ParameterObject @PageableDefault(size = 10) Pageable pageable) { - return readHostListUseCase.execute(pageable); + return readHostsUseCase.execute(pageable); } @Operation(summary = "고유 아이디에 해당하는 호스트 정보를 가져옵니다.") @@ -54,7 +56,15 @@ public HostDetailResponse getHostById(@PathVariable Long hostId) { @GetMapping("/{hostId}/invite/users") public UserProfileVo getInviteUserListByEmail( @PathVariable Long hostId, @RequestParam(value = "email") @Email String email) { - return readInviteUserListUseCase.execute(hostId, email); + return readInviteUsersUseCase.execute(hostId, email); + } + + @Operation(summary = "해당 호스트가 관리중인 이벤트 리스트를 가져옵니다.") + @GetMapping("/{hostId}/events") + public PageResponse getHostEventsById( + @PathVariable Long hostId, + @ParameterObject @PageableDefault(size = 10) Pageable pageable) { + return readHostEventsUseCase.execute(hostId, pageable); } @Operation(summary = "호스트 간편 생성. 호스트를 생성한 유저 자신은 마스터 호스트가 됩니다.") @@ -76,7 +86,7 @@ public HostDetailResponse inviteHost( return inviteHostUseCase.execute(hostId, inviteHostRequest); } - @Operation(summary = "호스트 유저의 권한을 변경합니다. 슈퍼 호스트 이상만 가능합니다.") + @Operation(summary = "호스트 유저의 권한을 변경합니다. 매니저 이상만 가능합니다.") @PatchMapping("/{hostId}/role") public HostDetailResponse patchHostUserRole( @PathVariable Long hostId, @@ -85,14 +95,14 @@ public HostDetailResponse patchHostUserRole( } // todo :: 슈퍼 호스트 이상으로? - @Operation(summary = "호스트 정보를 변경합니다. 슈퍼 호스트 이상만 가능합니다.") + @Operation(summary = "호스트 정보를 변경합니다. 매니저 이상만 가능합니다.") @PatchMapping("/{hostId}/profile") public HostDetailResponse patchHostById( @PathVariable Long hostId, @RequestBody @Valid UpdateHostRequest updateHostRequest) { return updateHostProfileUseCase.execute(hostId, updateHostRequest); } - @Operation(summary = "호스트 슬랙 알람 URL 을 변경합니다. 슈퍼 호스트 이상만 가능합니다.") + @Operation(summary = "호스트 슬랙 알람 URL 을 변경합니다. 매니저 이상만 가능합니다.") @PatchMapping("/{hostId}/slack") public HostDetailResponse patchHostSlackUrlById( @PathVariable Long hostId, diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/request/UpdateHostRequest.java b/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/request/UpdateHostRequest.java index f2c93fbb..a59bf195 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/request/UpdateHostRequest.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/request/UpdateHostRequest.java @@ -4,18 +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.NotNull; import lombok.Getter; import lombok.RequiredArgsConstructor; -import org.hibernate.validator.constraints.URL; /** 호스트 정보 변경 요청 DTO */ @Getter @RequiredArgsConstructor public class UpdateHostRequest { - @Schema(defaultValue = "https://s3.dudoong.com/img", description = "호스트 프로필 이미지") - @URL(message = "올바른 형식의 URL 을 입력해주세요") - private String profileImageUrl; + @Schema(defaultValue = "test/host/5/aa.jpg", description = "호스트 프로필 이미지") + @NotEmpty + private String profileImageKey; @Schema(defaultValue = "고슬고슬고스락", description = "호스트 간단 소개") @NotNull(message = "간단 소개를 입력해주세요") diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/request/UpdateHostUserRoleRequest.java b/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/request/UpdateHostUserRoleRequest.java index 1822cbaf..46c29b5f 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/request/UpdateHostUserRoleRequest.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/request/UpdateHostUserRoleRequest.java @@ -18,7 +18,7 @@ public class UpdateHostUserRoleRequest { @Positive(message = "올바른 유저 고유 아이디를 입력해주세요") private Long userId; - @Schema(defaultValue = "HOST", description = "호스트 유저 역할") - @Enum(message = "HOST 또는 SUPER_HOST 만 허용됩니다") + @Schema(defaultValue = "MANAGER", description = "호스트 유저 역할") + @Enum(message = "GUEST, MANAGER, MASTER 만 허용됩니다") private HostRole role; } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/response/CreateHostResponse.java b/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/response/CreateHostResponse.java deleted file mode 100644 index 01cda70d..00000000 --- a/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/response/CreateHostResponse.java +++ /dev/null @@ -1,33 +0,0 @@ -package band.gosrock.api.host.model.dto.response; - - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; -import lombok.Getter; - -@Getter -@Builder -@Deprecated -public class CreateHostResponse { - @Schema(description = "담당자 이메일") - private final String contactEmail; - - @Schema(description = "담당자 전화번호") - private final String contactNumber; - - @Schema(description = "마스터 유저의 정보") - private final Long masterUserId; - // private final HostUser masterUser; - - @Schema(description = "파트너쉽 여부") - private final boolean partner; - - // public static CreateHostResponse of(Host host) { - // return CreateHostResponse.builder() - // .contactEmail(host.getContactEmail()) - // .contactNumber(host.getContactNumber()) - // .masterUserId(host.getMasterUserId()) // todo:: 마스터 정보 나오도록 - // .partner(host.getPartner()) - // .build(); - // } -} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/response/HostEventProfileResponse.java b/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/response/HostEventProfileResponse.java new file mode 100644 index 00000000..df845882 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/response/HostEventProfileResponse.java @@ -0,0 +1,27 @@ +package band.gosrock.api.host.model.dto.response; + + +import band.gosrock.domain.common.vo.EventProfileVo; +import band.gosrock.domain.domains.event.domain.Event; +import band.gosrock.domain.domains.host.domain.Host; +import com.fasterxml.jackson.annotation.JsonUnwrapped; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class HostEventProfileResponse { + private Long hostId; + + private String hostName; + + @JsonUnwrapped private EventProfileVo eventProfileVo; + + public static HostEventProfileResponse of(Host host, Event event) { + return HostEventProfileResponse.builder() + .hostId(host.getId()) + .hostName(host.getProfile().getName()) + .eventProfileVo(event.toEventProfileVo()) + .build(); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/response/HostProfileResponse.java b/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/response/HostProfileResponse.java index d19523ca..22e88ca9 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/response/HostProfileResponse.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/host/model/dto/response/HostProfileResponse.java @@ -1,6 +1,7 @@ package band.gosrock.api.host.model.dto.response; +import band.gosrock.domain.common.vo.ImageVo; import band.gosrock.domain.domains.host.domain.Host; import band.gosrock.domain.domains.host.domain.HostRole; import io.swagger.v3.oas.annotations.media.Schema; @@ -21,7 +22,7 @@ public class HostProfileResponse { private final String introduce; @Schema(description = "호스트 프로필 이미지") - private final String profileImageUrl; + private final ImageVo profileImageUrl; @Schema(description = "속한 호스트에서의 역할") private HostRole role; @@ -34,7 +35,7 @@ public static HostProfileResponse of(Host host, Long userId) { .hostId(host.getId()) .name(host.getProfile().getName()) .introduce(host.getProfile().getIntroduce()) - .profileImageUrl(host.getProfile().getProfileImageUrl()) + .profileImageUrl(host.getProfile().getProfileImage()) .role(host.getHostUserByUserId(userId).getRole()) .isMaster(host.getMasterUserId().equals(userId)) .build(); diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/host/model/mapper/HostMapper.java b/DuDoong-Api/src/main/java/band/gosrock/api/host/model/mapper/HostMapper.java index f0f635be..9e0a6b7a 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/host/model/mapper/HostMapper.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/host/model/mapper/HostMapper.java @@ -40,7 +40,7 @@ public Host toEntity(CreateHostRequest createHostRequest, Long masterUserId) { public HostProfile toHostProfile(UpdateHostRequest updateHostRequest) { return HostProfile.builder() .introduce(updateHostRequest.getIntroduce()) - .profileImageUrl(updateHostRequest.getProfileImageUrl()) + .profileImageKey(updateHostRequest.getProfileImageKey()) .contactEmail(updateHostRequest.getContactEmail()) .contactNumber(updateHostRequest.getContactNumber()) .build(); @@ -52,10 +52,16 @@ public HostUser toHostUser(Long hostId, Long userId, HostRole role) { return HostUser.builder().userId(userId).host(host).role(role).build(); } - /** 역할 지정하여 주입하는 생성자 */ - public HostUser toSuperHostUser(Long hostId, Long userId) { + /** 매니저로 주입하는 생성자 */ + public HostUser toManagerHostUser(Long hostId, Long userId) { final Host host = hostAdaptor.findById(hostId); - return HostUser.builder().userId(userId).host(host).role(HostRole.SUPER_HOST).build(); + return HostUser.builder().userId(userId).host(host).role(HostRole.MANAGER).build(); + } + + /** 마스터 주입하는 생성자 */ + public HostUser toMasterHostUser(Long hostId, Long userId) { + final Host host = hostAdaptor.findById(hostId); + return HostUser.builder().userId(userId).host(host).role(HostRole.MASTER).build(); } @Transactional(readOnly = true) @@ -88,8 +94,6 @@ private HostDetailResponse toHostDetailResponseExecute(Host host) { .map(User::toUserInfoVo) .collect(Collectors.toSet()); - // todo :: 유저 리스트에 역할까지 추가하기 - final Set hostUserVoSet = userInfoVoSet.stream() .map( diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/host/service/CreateHostUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/host/service/CreateHostUseCase.java index 22f72050..efce78a9 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/host/service/CreateHostUseCase.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/host/service/CreateHostUseCase.java @@ -27,8 +27,8 @@ public HostResponse execute(CreateHostRequest createHostRequest) { final Long userId = user.getId(); // 호스트 생성 final Host host = hostService.createHost(hostMapper.toEntity(createHostRequest, userId)); - // 생성한 유저를 마스터로 + 슈퍼 호스트 권한으로 등록 - final HostUser masterHostUser = hostMapper.toSuperHostUser(host.getId(), userId); + // 생성한 유저를 마스터 권한으로 등록 + final HostUser masterHostUser = hostMapper.toMasterHostUser(host.getId(), userId); // 초대 보류 없이 즉시 활성화 masterHostUser.activate(); return HostResponse.of(hostService.addHostUser(host, masterHostUser)); diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/host/service/ReadHostEventsUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/host/service/ReadHostEventsUseCase.java new file mode 100644 index 00000000..8f74ed99 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/host/service/ReadHostEventsUseCase.java @@ -0,0 +1,28 @@ +package band.gosrock.api.host.service; + + +import band.gosrock.api.common.page.PageResponse; +import band.gosrock.api.host.model.dto.response.HostEventProfileResponse; +import band.gosrock.common.annotation.UseCase; +import band.gosrock.domain.domains.event.adaptor.EventAdaptor; +import band.gosrock.domain.domains.host.adaptor.HostAdaptor; +import band.gosrock.domain.domains.host.domain.Host; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.transaction.annotation.Transactional; + +@UseCase +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class ReadHostEventsUseCase { + private final HostAdaptor hostAdaptor; + private final EventAdaptor eventAdaptor; + + public PageResponse execute(Long hostId, Pageable pageable) { + Host host = hostAdaptor.findById(hostId); + return PageResponse.of( + eventAdaptor + .findAllByHostId(hostId, pageable) + .map(event -> HostEventProfileResponse.of(host, event))); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/host/service/ReadHostProfileListUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/host/service/ReadHostProfilesUseCase.java similarity index 96% rename from DuDoong-Api/src/main/java/band/gosrock/api/host/service/ReadHostProfileListUseCase.java rename to DuDoong-Api/src/main/java/band/gosrock/api/host/service/ReadHostProfilesUseCase.java index 384e755e..f2ad4b20 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/host/service/ReadHostProfileListUseCase.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/host/service/ReadHostProfilesUseCase.java @@ -14,7 +14,7 @@ @UseCase @RequiredArgsConstructor @Transactional(readOnly = true) -public class ReadHostProfileListUseCase { +public class ReadHostProfilesUseCase { private final UserUtils userUtils; private final HostAdaptor hostAdaptor; diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/host/service/ReadInviteUserListUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/host/service/ReadInviteUsersUseCase.java similarity index 94% rename from DuDoong-Api/src/main/java/band/gosrock/api/host/service/ReadInviteUserListUseCase.java rename to DuDoong-Api/src/main/java/band/gosrock/api/host/service/ReadInviteUsersUseCase.java index 61a203a4..d3ce742d 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/host/service/ReadInviteUserListUseCase.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/host/service/ReadInviteUsersUseCase.java @@ -12,7 +12,7 @@ @UseCase @RequiredArgsConstructor @Transactional(readOnly = true) -public class ReadInviteUserListUseCase { +public class ReadInviteUsersUseCase { private final UserUtils userUtils; private final HostMapper hostMapper; diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/host/service/UpdateHostProfileUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/host/service/UpdateHostProfileUseCase.java index 07495685..e3c6ba5e 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/host/service/UpdateHostProfileUseCase.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/host/service/UpdateHostProfileUseCase.java @@ -29,7 +29,7 @@ public HostDetailResponse execute(Long hostId, UpdateHostRequest updateHostReque final Host host = hostAdaptor.findById(hostId); // 슈퍼 호스트 검증 - host.validateSuperHostUser(userId); + host.validateManagerHostUser(userId); return hostMapper.toHostDetailResponse( hostService.updateHostProfile(host, hostMapper.toHostProfile(updateHostRequest))); diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/host/service/UpdateHostSlackUrlUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/host/service/UpdateHostSlackUrlUseCase.java index fc89d598..c59c7383 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/host/service/UpdateHostSlackUrlUseCase.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/host/service/UpdateHostSlackUrlUseCase.java @@ -1,7 +1,9 @@ package band.gosrock.api.host.service; +import static band.gosrock.api.common.aop.hostRole.FindHostFrom.HOST_ID; +import static band.gosrock.api.common.aop.hostRole.HostQualification.MANAGER; -import band.gosrock.api.common.UserUtils; +import band.gosrock.api.common.aop.hostRole.HostRolesAllowed; import band.gosrock.api.host.model.dto.request.UpdateHostSlackRequest; import band.gosrock.api.host.model.dto.response.HostDetailResponse; import band.gosrock.api.host.model.mapper.HostMapper; @@ -9,28 +11,21 @@ import band.gosrock.domain.domains.host.adaptor.HostAdaptor; import band.gosrock.domain.domains.host.domain.Host; import band.gosrock.domain.domains.host.service.HostService; -import band.gosrock.domain.domains.user.domain.User; import lombok.RequiredArgsConstructor; import org.springframework.transaction.annotation.Transactional; @UseCase @RequiredArgsConstructor public class UpdateHostSlackUrlUseCase { - private final UserUtils userUtils; private final HostService hostService; private final HostAdaptor hostAdaptor; private final HostMapper hostMapper; @Transactional + @HostRolesAllowed(role = MANAGER, findHostFrom = HOST_ID) public HostDetailResponse execute(Long hostId, UpdateHostSlackRequest updateHostSlackRequest) { - // 존재하는 유저인지 검증 - final User user = userUtils.getCurrentUser(); - final Long userId = user.getId(); - final Host host = hostAdaptor.findById(hostId); final String slackUrl = updateHostSlackRequest.getSlackUrl(); - // 슈퍼 호스트 검증 - host.validateSuperHostUser(userId); return hostMapper.toHostDetailResponse(hostService.updateHostSlackUrl(host, slackUrl)); } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/host/service/UpdateHostUserRoleUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/host/service/UpdateHostUserRoleUseCase.java index d12cb6e4..b2c9890c 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/host/service/UpdateHostUserRoleUseCase.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/host/service/UpdateHostUserRoleUseCase.java @@ -29,8 +29,8 @@ public HostDetailResponse execute( final User user = userUtils.getCurrentUser(); final Long userId = user.getId(); final Host host = hostAdaptor.findById(hostId); - // 슈퍼 호스트 검증 - host.validateSuperHostUser(userId); + // 매니저 호스트 검증 + host.validateManagerHostUser(userId); final Long updateUserId = updateHostUserRoleRequest.getUserId(); final HostRole updateUserRole = updateHostUserRoleRequest.getRole(); diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/image/controller/ImageController.java b/DuDoong-Api/src/main/java/band/gosrock/api/image/controller/ImageController.java new file mode 100644 index 00000000..9f425fd1 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/image/controller/ImageController.java @@ -0,0 +1,39 @@ +package band.gosrock.api.image.controller; + + +import band.gosrock.api.image.dto.ImageUrlResponse; +import band.gosrock.api.image.service.GetImageUploadUrlUseCase; +import band.gosrock.infrastructure.config.s3.ImageFileExtension; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +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") +@RequiredArgsConstructor +public class ImageController { + + private final GetImageUploadUrlUseCase getImageUploadUrlUseCase; + + @Operation(summary = "이벤트 관련 이미지 업로드 url 요청할수 있는 api 입니다.") + @PostMapping(value = "/events/{eventId}/images") + public ImageUrlResponse getIssuedTickets( + @PathVariable Long eventId, @RequestParam ImageFileExtension imageFileExtension) { + return getImageUploadUrlUseCase.forEvent(eventId, imageFileExtension); + } + + @Operation(summary = "호스트 관련 이미지 업로드 url 요청할수 있는 api 입니다.") + @PostMapping(value = "/hosts/{hostId}/images") + public ImageUrlResponse patchIssuedTicketStatus( + @PathVariable Long hostId, @RequestParam ImageFileExtension imageFileExtension) { + return getImageUploadUrlUseCase.forHost(hostId, imageFileExtension); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/image/dto/ImageUrlRequest.java b/DuDoong-Api/src/main/java/band/gosrock/api/image/dto/ImageUrlRequest.java new file mode 100644 index 00000000..5eba0f3f --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/image/dto/ImageUrlRequest.java @@ -0,0 +1,14 @@ +package band.gosrock.api.image.dto; + + +import band.gosrock.common.annotation.Enum; +import band.gosrock.infrastructure.config.s3.ImageFileExtension; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class ImageUrlRequest { + + @Enum private ImageFileExtension imageFileExtension; +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/image/dto/ImageUrlResponse.java b/DuDoong-Api/src/main/java/band/gosrock/api/image/dto/ImageUrlResponse.java new file mode 100644 index 00000000..f34cc076 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/image/dto/ImageUrlResponse.java @@ -0,0 +1,24 @@ +package band.gosrock.api.image.dto; + + +import band.gosrock.domain.common.vo.ImageVo; +import band.gosrock.infrastructure.config.s3.ImageUrlDto; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class ImageUrlResponse { + + private final String presignedUrl; + private final String key; + private final ImageVo url; + + public static ImageUrlResponse from(ImageUrlDto urlDto) { + return ImageUrlResponse.builder() + .presignedUrl(urlDto.getUrl()) + .key(urlDto.getKey()) + .url(ImageVo.valueOf(urlDto.getKey())) + .build(); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/image/service/GetImageUploadUrlUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/image/service/GetImageUploadUrlUseCase.java new file mode 100644 index 00000000..6a089f82 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/image/service/GetImageUploadUrlUseCase.java @@ -0,0 +1,31 @@ +package band.gosrock.api.image.service; + +import static band.gosrock.api.common.aop.hostRole.FindHostFrom.EVENT_ID; +import static band.gosrock.api.common.aop.hostRole.FindHostFrom.HOST_ID; +import static band.gosrock.api.common.aop.hostRole.HostQualification.MANAGER; + +import band.gosrock.api.common.aop.hostRole.HostRolesAllowed; +import band.gosrock.api.image.dto.ImageUrlResponse; +import band.gosrock.common.annotation.UseCase; +import band.gosrock.infrastructure.config.s3.ImageFileExtension; +import band.gosrock.infrastructure.config.s3.S3UploadPresignedUrlService; +import lombok.RequiredArgsConstructor; + +@UseCase +@RequiredArgsConstructor +public class GetImageUploadUrlUseCase { + + private final S3UploadPresignedUrlService presignedUrlService; + + @HostRolesAllowed(role = MANAGER, findHostFrom = EVENT_ID) + public ImageUrlResponse forEvent(Long eventId, ImageFileExtension imageFileExtension) { + + return ImageUrlResponse.from(presignedUrlService.forEvent(eventId, imageFileExtension)); + } + + @HostRolesAllowed(role = MANAGER, findHostFrom = HOST_ID) + public ImageUrlResponse forHost(Long hostId, ImageFileExtension imageFileExtension) { + + return ImageUrlResponse.from(presignedUrlService.forHost(hostId, imageFileExtension)); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/controller/AdminIssuedTicketController.java b/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/controller/AdminIssuedTicketController.java index 2e2192ed..9f9e91df 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/controller/AdminIssuedTicketController.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/controller/AdminIssuedTicketController.java @@ -19,7 +19,7 @@ @SecurityRequirement(name = "access-token") @Tag(name = "발급 티켓 관련 어드민 컨트롤러") @RestController -@RequestMapping("/v1/admin/issuedTickets") +@RequestMapping("/v1/event/{eventId}/issuedTickets") @RequiredArgsConstructor public class AdminIssuedTicketController { @@ -30,8 +30,8 @@ public class AdminIssuedTicketController { @Operation(summary = "[어드민 기능] 발급 티켓 리스트 가져오기 API 입니다.") @GetMapping public RetrieveIssuedTicketListResponse getIssuedTickets( + @PathVariable Long eventId, @RequestParam Long page, - @RequestParam Long eventId, @RequestParam(required = false) String userName, @RequestParam(required = false) String phoneNumber) { return readIssuedTicketsUseCase.execute(page, eventId, userName, phoneNumber); @@ -39,7 +39,8 @@ public RetrieveIssuedTicketListResponse getIssuedTickets( @Operation(summary = "[어드민 기능] 발급 티켓 입장 처리 API 입니다.") @PatchMapping(value = "/{issuedTicketId}") - public IssuedTicketInfoVo patchIssuedTicketStatus(@PathVariable Long issuedTicketId) { - return entranceIssuedTicketUseCase.execute(issuedTicketId); + public IssuedTicketInfoVo patchIssuedTicketStatus( + @PathVariable Long eventId, @PathVariable Long issuedTicketId) { + return entranceIssuedTicketUseCase.execute(eventId, issuedTicketId); } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/controller/IssuedTicketController.java b/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/controller/IssuedTicketController.java index 14aacdb8..a45dd328 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/controller/IssuedTicketController.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/controller/IssuedTicketController.java @@ -2,18 +2,13 @@ import band.gosrock.api.issuedTicket.dto.response.RetrieveIssuedTicketDetailResponse; -import band.gosrock.api.issuedTicket.service.CreateIssuedTicketUseCase; import band.gosrock.api.issuedTicket.service.ReadIssuedTicketUseCase; -import band.gosrock.common.annotation.DevelopOnlyApi; -import band.gosrock.domain.domains.issuedTicket.dto.request.CreateIssuedTicketForDevDTO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; 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.RestController; @@ -24,7 +19,6 @@ @RequiredArgsConstructor public class IssuedTicketController { - private final CreateIssuedTicketUseCase createIssuedTicketUseCase; private final ReadIssuedTicketUseCase readIssuedTicketUseCase; @Operation(summary = "발급 티켓 가져오기 API 입니다.") @@ -32,12 +26,4 @@ public class IssuedTicketController { public RetrieveIssuedTicketDetailResponse getIssuedTicket(@PathVariable Long issuedTicketId) { return readIssuedTicketUseCase.execute(issuedTicketId); } - - @Operation(summary = "개발용 발급 티켓 생성 API 입니다.") - @DevelopOnlyApi - @PostMapping(value = "/develop") - public RetrieveIssuedTicketDetailResponse postIssuedTicket( - @RequestBody CreateIssuedTicketForDevDTO body) { - return createIssuedTicketUseCase.executeForDev(body); - } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/dto/response/RetrieveIssuedTicketDTO.java b/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/dto/response/RetrieveIssuedTicketDTO.java index 6d026ad6..f399a59b 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/dto/response/RetrieveIssuedTicketDTO.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/dto/response/RetrieveIssuedTicketDTO.java @@ -3,10 +3,8 @@ import band.gosrock.domain.common.vo.IssuedTicketInfoVo; import band.gosrock.domain.common.vo.IssuedTicketOptionAnswerVo; -import band.gosrock.domain.common.vo.UserInfoVo; import band.gosrock.domain.domains.issuedTicket.domain.IssuedTicket; import band.gosrock.domain.domains.issuedTicket.domain.IssuedTicketOptionAnswer; -import band.gosrock.domain.domains.user.domain.User; import java.util.List; import lombok.Builder; import lombok.Getter; @@ -17,14 +15,13 @@ public class RetrieveIssuedTicketDTO { private final IssuedTicketInfoVo issuedTicketInfo; - private final UserInfoVo userInfo; + // private final UserInfoVo userInfo; private final List issuedTicketOptionAnswers; - public static RetrieveIssuedTicketDTO of(IssuedTicket issuedTicket, User user) { + public static RetrieveIssuedTicketDTO of(IssuedTicket issuedTicket) { return RetrieveIssuedTicketDTO.builder() .issuedTicketInfo(issuedTicket.toIssuedTicketInfoVo()) - .userInfo(user.toUserInfoVo()) .issuedTicketOptionAnswers( issuedTicket.getIssuedTicketOptionAnswers().stream() .map(IssuedTicketOptionAnswer::toIssuedTicketOptionAnswerVo) diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/dto/response/RetrieveIssuedTicketDetailResponse.java b/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/dto/response/RetrieveIssuedTicketDetailResponse.java index e915cdef..551b8b4e 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/dto/response/RetrieveIssuedTicketDetailResponse.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/dto/response/RetrieveIssuedTicketDetailResponse.java @@ -3,6 +3,7 @@ import band.gosrock.domain.common.vo.EventInfoVo; import band.gosrock.domain.common.vo.IssuedTicketInfoVo; +import band.gosrock.domain.domains.event.domain.Event; import band.gosrock.domain.domains.issuedTicket.domain.IssuedTicket; import lombok.Builder; import lombok.Getter; @@ -23,16 +24,10 @@ public class RetrieveIssuedTicketDetailResponse { */ private final EventInfoVo eventInfo; - /* - 발급 유저 이름 - */ - private final String userName; - - public static RetrieveIssuedTicketDetailResponse of(IssuedTicket issuedTicket) { + public static RetrieveIssuedTicketDetailResponse of(IssuedTicket issuedTicket, Event event) { return RetrieveIssuedTicketDetailResponse.builder() .issuedTicketInfo(issuedTicket.toIssuedTicketInfoVo()) - .eventInfo(issuedTicket.getEvent().toEventInfoVo()) - .userName(issuedTicket.getUser().getProfile().getName()) + .eventInfo(event.toEventInfoVo()) .build(); } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/dto/response/RetrieveIssuedTicketListResponse.java b/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/dto/response/RetrieveIssuedTicketListResponse.java index e2cb8cfc..98e9ab22 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/dto/response/RetrieveIssuedTicketListResponse.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/dto/response/RetrieveIssuedTicketListResponse.java @@ -21,13 +21,7 @@ public static RetrieveIssuedTicketListResponse of(Page issuedTicke return RetrieveIssuedTicketListResponse.builder() .page(issuedTickets.getPageable().getPageNumber()) .totalPage(issuedTickets.getTotalPages()) - .issuedTickets( - issuedTickets.stream() - .map( - issuedTicket -> - RetrieveIssuedTicketDTO.of( - issuedTicket, issuedTicket.getUser())) - .toList()) + .issuedTickets(issuedTickets.stream().map(RetrieveIssuedTicketDTO::of).toList()) .build(); } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/mapper/IssuedTicketMapper.java b/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/mapper/IssuedTicketMapper.java index ae2c843e..e0854408 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/mapper/IssuedTicketMapper.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/mapper/IssuedTicketMapper.java @@ -4,7 +4,10 @@ import band.gosrock.api.issuedTicket.dto.response.RetrieveIssuedTicketDetailResponse; import band.gosrock.api.issuedTicket.dto.response.RetrieveIssuedTicketListResponse; import band.gosrock.common.annotation.Mapper; +import band.gosrock.domain.domains.event.adaptor.EventAdaptor; +import band.gosrock.domain.domains.event.domain.Event; import band.gosrock.domain.domains.issuedTicket.adaptor.IssuedTicketAdaptor; +import band.gosrock.domain.domains.issuedTicket.domain.IssuedTicket; import band.gosrock.domain.domains.issuedTicket.dto.condition.IssuedTicketCondition; import lombok.RequiredArgsConstructor; import org.springframework.transaction.annotation.Transactional; @@ -15,6 +18,8 @@ public class IssuedTicketMapper { private final IssuedTicketAdaptor issuedTicketAdaptor; + private final EventAdaptor eventAdaptor; + @Transactional(readOnly = true) public RetrieveIssuedTicketListResponse toIssuedTicketPageResponse( Long page, IssuedTicketCondition condition) { @@ -25,7 +30,13 @@ public RetrieveIssuedTicketListResponse toIssuedTicketPageResponse( @Transactional(readOnly = true) public RetrieveIssuedTicketDetailResponse toIssuedTicketDetailResponse( Long currentUserId, Long issuedTicketId) { - return RetrieveIssuedTicketDetailResponse.of( - issuedTicketAdaptor.findForUser(currentUserId, issuedTicketId)); + IssuedTicket issuedTicket = issuedTicketAdaptor.findForUser(currentUserId, issuedTicketId); + Event event = eventAdaptor.findById(issuedTicket.getEventId()); + return RetrieveIssuedTicketDetailResponse.of(issuedTicket, event); + } + + @Transactional(readOnly = true) + public IssuedTicket getIssuedTicket(Long issuedTicketId) { + return issuedTicketAdaptor.queryIssuedTicket(issuedTicketId); } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/service/CreateIssuedTicketUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/service/CreateIssuedTicketUseCase.java deleted file mode 100644 index ebfa8357..00000000 --- a/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/service/CreateIssuedTicketUseCase.java +++ /dev/null @@ -1,79 +0,0 @@ -package band.gosrock.api.issuedTicket.service; - - -import band.gosrock.api.config.security.SecurityUtils; -import band.gosrock.api.issuedTicket.dto.response.RetrieveIssuedTicketDetailResponse; -import band.gosrock.common.annotation.UseCase; -import band.gosrock.domain.common.vo.Money; -import band.gosrock.domain.domains.event.adaptor.EventAdaptor; -import band.gosrock.domain.domains.event.domain.Event; -import band.gosrock.domain.domains.issuedTicket.adaptor.IssuedTicketAdaptor; -import band.gosrock.domain.domains.issuedTicket.domain.IssuedTicket; -import band.gosrock.domain.domains.issuedTicket.domain.IssuedTicketOptionAnswer; -import band.gosrock.domain.domains.issuedTicket.dto.request.CreateIssuedTicketForDevDTO; -import band.gosrock.domain.domains.issuedTicket.service.IssuedTicketDomainService; -import band.gosrock.domain.domains.ticket_item.adaptor.OptionAdaptor; -import band.gosrock.domain.domains.ticket_item.adaptor.TicketItemAdaptor; -import band.gosrock.domain.domains.ticket_item.domain.TicketItem; -import band.gosrock.domain.domains.user.adaptor.UserAdaptor; -import band.gosrock.domain.domains.user.domain.User; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.transaction.annotation.Transactional; - -@UseCase -@RequiredArgsConstructor -public class CreateIssuedTicketUseCase { - - private final IssuedTicketDomainService issuedTicketDomainService; - private final IssuedTicketAdaptor issuedTicketAdaptor; - private final UserAdaptor userAdaptor; - private final EventAdaptor eventAdaptor; - private final TicketItemAdaptor ticketItemAdaptor; - private final OptionAdaptor optionAdaptor; - - @Transactional - public RetrieveIssuedTicketDetailResponse executeForDev(CreateIssuedTicketForDevDTO body) { - Long currentUserId = SecurityUtils.getCurrentUserId(); - User user = getUser(currentUserId); - Event event = getEvent(body.getEventId()); - TicketItem ticketItem = getTicketItem(body.getTicketItemId()); - - List issuedTicketOptionAnswers = - body.getOptionAnswers().stream() - .map( - option -> - IssuedTicketOptionAnswer.builder() - .option(optionAdaptor.queryOption(option)) - .answer("test") - .build()) - .toList(); - - IssuedTicket issuedTicket = - issuedTicketAdaptor.save( - IssuedTicket.createForDev( - event, - user, - body.getOrderLineId(), - ticketItem, - Money.wons(body.getAmount()), - issuedTicketOptionAnswers)); - - return new RetrieveIssuedTicketDetailResponse( - issuedTicket.toIssuedTicketInfoVo(), - issuedTicket.getEvent().toEventInfoVo(), - issuedTicket.getUser().getProfile().getName()); - } - - private Event getEvent(Long eventId) { - return eventAdaptor.findById(eventId); - } - - private User getUser(Long userId) { - return userAdaptor.queryUser(userId); - } - - private TicketItem getTicketItem(Long ticketItemId) { - return ticketItemAdaptor.queryTicketItem(ticketItemId); - } -} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/service/EntranceIssuedTicketUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/service/EntranceIssuedTicketUseCase.java index cc682e7b..b7bcd882 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/service/EntranceIssuedTicketUseCase.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/issuedTicket/service/EntranceIssuedTicketUseCase.java @@ -18,9 +18,9 @@ public class EntranceIssuedTicketUseCase { private final UserUtils userUtils; - public IssuedTicketInfoVo execute(Long issuedTicketId) { + public IssuedTicketInfoVo execute(Long eventId, Long issuedTicketId) { Long currentUserId = userUtils.getCurrentUserId(); return issuedTicketDomainService.processingEntranceIssuedTicket( - currentUserId, issuedTicketId); + eventId, currentUserId, issuedTicketId); } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/order/controller/OrderAdminController.java b/DuDoong-Api/src/main/java/band/gosrock/api/order/controller/OrderAdminController.java new file mode 100644 index 00000000..85419179 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/order/controller/OrderAdminController.java @@ -0,0 +1,51 @@ +package band.gosrock.api.order.controller; + + +import band.gosrock.api.common.page.PageResponse; +import band.gosrock.api.order.docs.ApproveOrderExceptionDocs; +import band.gosrock.api.order.model.dto.request.AdminOrderTableQueryRequest; +import band.gosrock.api.order.model.dto.response.OrderAdminTableElement; +import band.gosrock.api.order.model.dto.response.OrderResponse; +import band.gosrock.api.order.service.ApproveOrderUseCase; +import band.gosrock.api.order.service.ReadOrderUseCase; +import band.gosrock.common.annotation.ApiErrorExceptionsExample; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import javax.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springdoc.api.annotations.ParameterObject; +import org.springframework.data.domain.Pageable; +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.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@SecurityRequirement(name = "access-token") +@Tag(name = "주문 관련 컨트롤러") +@RestController +@RequestMapping("/v1/events/{eventId}/orders") +@RequiredArgsConstructor +public class OrderAdminController { + + private final ApproveOrderUseCase approveOrderUseCase; + private final ReadOrderUseCase readOrderUseCase; + + @Operation(summary = "어드민 목록 내 테이블 조회 OrderStage 는 꼭 보내주삼!") + @GetMapping + public PageResponse getEventOrders( + @ParameterObject @Valid AdminOrderTableQueryRequest adminOrderTableQueryRequest, + @ParameterObject Pageable pageable, + @PathVariable Long eventId) { + return readOrderUseCase.getEventOrders(eventId, adminOrderTableQueryRequest, pageable); + } + + @Operation(summary = "주문 승인하기 . 호스트 관리자가 티켓 주문을 승인합니다. ( 어드민 이벤트쪽으로 이동예정 )") + @ApiErrorExceptionsExample(ApproveOrderExceptionDocs.class) + @PostMapping("/{order_uuid}/approve") + public OrderResponse confirmOrder( + @PathVariable Long eventId, @PathVariable("order_uuid") String orderUuid) { + return approveOrderUseCase.execute(eventId, orderUuid); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/order/controller/OrderController.java b/DuDoong-Api/src/main/java/band/gosrock/api/order/controller/OrderController.java index 280550de..b0e0e34c 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/order/controller/OrderController.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/order/controller/OrderController.java @@ -2,7 +2,6 @@ import band.gosrock.api.common.page.PageResponse; -import band.gosrock.api.order.docs.ApproveOrderExceptionDocs; import band.gosrock.api.order.docs.CancelOrderExceptionDocs; import band.gosrock.api.order.docs.ConfirmOrderExceptionDocs; import band.gosrock.api.order.docs.CreateOrderExceptionDocs; @@ -82,13 +81,6 @@ public OrderResponse confirmOrder( return confirmOrderUseCase.execute(orderUuid, confirmOrderRequest); } - @Operation(summary = "주문 승인하기 . 호스트 관리자가 티켓 주문을 승인합니다. ( 어드민 이벤트쪽으로 이동예정 )") - @ApiErrorExceptionsExample(ApproveOrderExceptionDocs.class) - @PostMapping("/{order_uuid}/approve") - public OrderResponse confirmOrder(@PathVariable("order_uuid") String orderUuid) { - return approveOrderUseCase.execute(orderUuid); - } - @Operation(summary = "주문을 무료로 결제합니다. 선착순 방식 결제 0원일 때 지원") @ApiErrorExceptionsExample(FreeOrderExceptionDocs.class) @PostMapping("/{order_uuid}/free") diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/ApproveOrderExceptionDocs.java b/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/ApproveOrderExceptionDocs.java index 76a36cc6..87e74956 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/ApproveOrderExceptionDocs.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/ApproveOrderExceptionDocs.java @@ -5,7 +5,7 @@ import band.gosrock.common.annotation.ExplainError; import band.gosrock.common.exception.DuDoongCodeException; import band.gosrock.common.interfaces.SwaggerExampleExceptions; -import band.gosrock.domain.domains.event.exception.EventIsNotOpenStatusException; +import band.gosrock.domain.domains.event.exception.EventNotOpenException; import band.gosrock.domain.domains.event.exception.EventTicketingTimeIsPassedException; import band.gosrock.domain.domains.order.exception.NotApprovalOrderException; import band.gosrock.domain.domains.order.exception.NotPendingOrderException; @@ -24,7 +24,7 @@ public class ApproveOrderExceptionDocs implements SwaggerExampleExceptions { public DuDoongCodeException 주문상태_검증 = NotPendingOrderException.EXCEPTION; @ExplainError("이벤트가 열린 상태가 아닐때") - public DuDoongCodeException 이벤트_닫힘 = EventIsNotOpenStatusException.EXCEPTION; + public DuDoongCodeException 이벤트_닫힘 = EventNotOpenException.EXCEPTION; @ExplainError("이벤트 티켓팅 시간이 지났을때.") public DuDoongCodeException 티켓팅_시간지남 = EventTicketingTimeIsPassedException.EXCEPTION; diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/CancelOrderExceptionDocs.java b/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/CancelOrderExceptionDocs.java index 53f0a5db..a66a0328 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/CancelOrderExceptionDocs.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/CancelOrderExceptionDocs.java @@ -5,7 +5,7 @@ import band.gosrock.common.annotation.ExplainError; import band.gosrock.common.exception.DuDoongCodeException; import band.gosrock.common.interfaces.SwaggerExampleExceptions; -import band.gosrock.domain.domains.event.exception.EventIsNotOpenStatusException; +import band.gosrock.domain.domains.event.exception.EventNotOpenException; import band.gosrock.domain.domains.event.exception.EventTicketingTimeIsPassedException; import band.gosrock.domain.domains.order.exception.CanNotCancelOrderException; import band.gosrock.domain.domains.order.exception.NotRefundAvailableDateOrderException; @@ -20,7 +20,7 @@ public class CancelOrderExceptionDocs implements SwaggerExampleExceptions { public DuDoongCodeException 주문상태_취소가능_검증 = CanNotCancelOrderException.EXCEPTION; @ExplainError("이벤트가 열린 상태가 아닐때") - public DuDoongCodeException 이벤트_닫힘 = EventIsNotOpenStatusException.EXCEPTION; + public DuDoongCodeException 이벤트_닫힘 = EventNotOpenException.EXCEPTION; @ExplainError("이벤트 티켓팅 시간이 지났을때.") public DuDoongCodeException 티켓팅_시간지남 = EventTicketingTimeIsPassedException.EXCEPTION; diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/ConfirmOrderExceptionDocs.java b/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/ConfirmOrderExceptionDocs.java index e7d018bd..4d809e42 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/ConfirmOrderExceptionDocs.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/ConfirmOrderExceptionDocs.java @@ -5,7 +5,7 @@ import band.gosrock.common.annotation.ExplainError; import band.gosrock.common.exception.DuDoongCodeException; import band.gosrock.common.interfaces.SwaggerExampleExceptions; -import band.gosrock.domain.domains.event.exception.EventIsNotOpenStatusException; +import band.gosrock.domain.domains.event.exception.EventNotOpenException; import band.gosrock.domain.domains.event.exception.EventTicketingTimeIsPassedException; import band.gosrock.domain.domains.order.exception.NotPaymentOrderException; import band.gosrock.domain.domains.order.exception.NotPendingOrderException; @@ -24,7 +24,7 @@ public class ConfirmOrderExceptionDocs implements SwaggerExampleExceptions { public DuDoongCodeException 주문상태_검증 = NotPendingOrderException.EXCEPTION; @ExplainError("이벤트가 열린 상태가 아닐때") - public DuDoongCodeException 이벤트_닫힘 = EventIsNotOpenStatusException.EXCEPTION; + public DuDoongCodeException 이벤트_닫힘 = EventNotOpenException.EXCEPTION; @ExplainError("이벤트 티켓팅 시간이 지났을때.") public DuDoongCodeException 티켓팅_시간지남 = EventTicketingTimeIsPassedException.EXCEPTION; diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/CreateOrderExceptionDocs.java b/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/CreateOrderExceptionDocs.java index 9e7ed481..a6a5c536 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/CreateOrderExceptionDocs.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/CreateOrderExceptionDocs.java @@ -5,7 +5,7 @@ import band.gosrock.common.annotation.ExplainError; import band.gosrock.common.exception.DuDoongCodeException; import band.gosrock.common.interfaces.SwaggerExampleExceptions; -import band.gosrock.domain.domains.event.exception.EventIsNotOpenStatusException; +import band.gosrock.domain.domains.event.exception.EventNotOpenException; import band.gosrock.domain.domains.event.exception.EventTicketingTimeIsPassedException; import band.gosrock.domain.domains.order.exception.InvalidOrderException; import band.gosrock.domain.domains.order.exception.OrdeItemNotOneTypeException; @@ -20,7 +20,7 @@ public class CreateOrderExceptionDocs implements SwaggerExampleExceptions { public DuDoongCodeException 잘못된주문생성요청 = InvalidOrderException.EXCEPTION; @ExplainError("이벤트가 열린 상태가 아닐때") - public DuDoongCodeException 이벤트_닫힘 = EventIsNotOpenStatusException.EXCEPTION; + public DuDoongCodeException 이벤트_닫힘 = EventNotOpenException.EXCEPTION; @ExplainError("이벤트 티켓팅 시간이 지났을때.") public DuDoongCodeException 티켓팅_시간지남 = EventTicketingTimeIsPassedException.EXCEPTION; diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/FreeOrderExceptionDocs.java b/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/FreeOrderExceptionDocs.java index b5ad0dd2..5000a2a8 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/FreeOrderExceptionDocs.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/FreeOrderExceptionDocs.java @@ -5,7 +5,7 @@ import band.gosrock.common.annotation.ExplainError; import band.gosrock.common.exception.DuDoongCodeException; import band.gosrock.common.interfaces.SwaggerExampleExceptions; -import band.gosrock.domain.domains.event.exception.EventIsNotOpenStatusException; +import band.gosrock.domain.domains.event.exception.EventNotOpenException; import band.gosrock.domain.domains.event.exception.EventTicketingTimeIsPassedException; import band.gosrock.domain.domains.order.exception.NotFreeOrderException; import band.gosrock.domain.domains.order.exception.NotPaymentOrderException; @@ -28,7 +28,7 @@ public class FreeOrderExceptionDocs implements SwaggerExampleExceptions { public DuDoongCodeException 주문상태_검증 = NotPendingOrderException.EXCEPTION; @ExplainError("이벤트가 열린 상태가 아닐때") - public DuDoongCodeException 이벤트_닫힘 = EventIsNotOpenStatusException.EXCEPTION; + public DuDoongCodeException 이벤트_닫힘 = EventNotOpenException.EXCEPTION; @ExplainError("이벤트 티켓팅 시간이 지났을때.") public DuDoongCodeException 티켓팅_시간지남 = EventTicketingTimeIsPassedException.EXCEPTION; diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/RefundOrderExceptionDocs.java b/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/RefundOrderExceptionDocs.java index 1130d6e7..d96a691d 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/RefundOrderExceptionDocs.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/order/docs/RefundOrderExceptionDocs.java @@ -5,7 +5,7 @@ import band.gosrock.common.annotation.ExplainError; import band.gosrock.common.exception.DuDoongCodeException; import band.gosrock.common.interfaces.SwaggerExampleExceptions; -import band.gosrock.domain.domains.event.exception.EventIsNotOpenStatusException; +import band.gosrock.domain.domains.event.exception.EventNotOpenException; import band.gosrock.domain.domains.event.exception.EventTicketingTimeIsPassedException; import band.gosrock.domain.domains.order.exception.CanNotRefundOrderException; import band.gosrock.domain.domains.order.exception.NotRefundAvailableDateOrderException; @@ -20,7 +20,7 @@ public class RefundOrderExceptionDocs implements SwaggerExampleExceptions { public DuDoongCodeException 주문상태_취소가능_검증 = CanNotRefundOrderException.EXCEPTION; @ExplainError("이벤트가 열린 상태가 아닐때") - public DuDoongCodeException 이벤트_닫힘 = EventIsNotOpenStatusException.EXCEPTION; + public DuDoongCodeException 이벤트_닫힘 = EventNotOpenException.EXCEPTION; @ExplainError("이벤트 티켓팅 시간이 지났을때.") public DuDoongCodeException 티켓팅_시간지남 = EventTicketingTimeIsPassedException.EXCEPTION; diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/order/model/dto/request/AdminOrderTableQueryRequest.java b/DuDoong-Api/src/main/java/band/gosrock/api/order/model/dto/request/AdminOrderTableQueryRequest.java new file mode 100644 index 00000000..a3898867 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/order/model/dto/request/AdminOrderTableQueryRequest.java @@ -0,0 +1,34 @@ +package band.gosrock.api.order.model.dto.request; + + +import band.gosrock.common.annotation.Enum; +import band.gosrock.domain.domains.order.repository.condition.AdminTableOrderFilterType; +import band.gosrock.domain.domains.order.repository.condition.AdminTableSearchType; +import band.gosrock.domain.domains.order.repository.condition.FindEventOrdersCondition; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class AdminOrderTableQueryRequest { + + @Enum private AdminTableOrderFilterType orderStage; + + // nullable + private AdminTableSearchType searchType; + + @Schema(nullable = true) + private String searchString; + + @JsonIgnore + public FindEventOrdersCondition toCondition(Long eventId) { + return FindEventOrdersCondition.builder() + .eventId(eventId) + .filterType(orderStage) + .searchString(searchString) + .searchType(searchType) + .build(); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/order/model/dto/response/OrderAdminTableElement.java b/DuDoong-Api/src/main/java/band/gosrock/api/order/model/dto/response/OrderAdminTableElement.java new file mode 100644 index 00000000..8adee732 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/order/model/dto/response/OrderAdminTableElement.java @@ -0,0 +1,67 @@ +package band.gosrock.api.order.model.dto.response; + + +import band.gosrock.domain.common.vo.Money; +import band.gosrock.domain.common.vo.RefundInfoVo; +import band.gosrock.domain.common.vo.UserInfoVo; +import band.gosrock.domain.domains.event.domain.Event; +import band.gosrock.domain.domains.order.domain.Order; +import band.gosrock.domain.domains.order.domain.OrderStatus; +import band.gosrock.domain.domains.user.domain.User; +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class OrderAdminTableElement { + @Schema(description = "취소 가능 정보") + private final RefundInfoVo refundInfo; + + @Schema(description = "유저 정보") + private final UserInfoVo userInfoVo; + + @Schema(description = "주문 고유 uuid 대체키임") + private final String orderUuid; + + @Schema(description = "주문 번호 R------- 형식") + private final String orderNo; + + @Schema(description = "주문의 상태") + private final OrderStatus orderStatus; + + @Schema(description = "주문 이름") + private final String orderName; + + @Schema(description = "주문 생성 시간") + private final LocalDateTime createdAt; + + @Schema(description = "철회 완료 시간") + private final LocalDateTime withDrawAt; + + @Schema(description = "승인 된 시간") + private final LocalDateTime approveAt; + + @Schema(description = "아이템 총 갯수") + private final Long totalQuantity; + + @Schema(description = "아이템 총 갯수") + private final Money totalPaymentPrice; + + public static OrderAdminTableElement of(Order order, Event event, User user) { + return OrderAdminTableElement.builder() + .refundInfo(event.toRefundInfoVo()) + .orderUuid(order.getUuid()) + .orderNo(order.getOrderNo()) + .orderStatus(order.getOrderStatus()) + .userInfoVo(user.toUserInfoVo()) + .orderName(order.getOrderName()) + .createdAt(order.getCreatedAt()) + .withDrawAt(order.getWithDrawAt()) + .approveAt(order.getApprovedAt()) + .totalQuantity(order.getTotalQuantity()) + .totalPaymentPrice(order.getTotalPaymentPrice()) + .build(); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/order/model/dto/response/OrderBriefElement.java b/DuDoong-Api/src/main/java/band/gosrock/api/order/model/dto/response/OrderBriefElement.java index dbe3737a..551676da 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/order/model/dto/response/OrderBriefElement.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/order/model/dto/response/OrderBriefElement.java @@ -41,7 +41,7 @@ public class OrderBriefElement { public static OrderBriefElement of(Order order, Event event, IssuedTickets issuedTickets) { return OrderBriefElement.builder() - .refundInfo(event.getRefundInfoVo()) + .refundInfo(event.toRefundInfoVo()) .stage(issuedTickets.getIssuedTicketsStage()) .orderUuid(order.getUuid()) .orderNo(order.getOrderNo()) diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/order/model/dto/response/OrderResponse.java b/DuDoong-Api/src/main/java/band/gosrock/api/order/model/dto/response/OrderResponse.java index 7d186a92..3f35f959 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/order/model/dto/response/OrderResponse.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/order/model/dto/response/OrderResponse.java @@ -41,7 +41,7 @@ public class OrderResponse { public static OrderResponse of( Order order, Event event, List tickets) { return OrderResponse.builder() - .refundInfo(event.getRefundInfoVo()) + .refundInfo(event.toRefundInfoVo()) .orderMethod(order.getOrderMethod()) .paymentInfo(OrderPaymentResponse.from(order)) .tickets(tickets) diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/order/model/mapper/OrderMapper.java b/DuDoong-Api/src/main/java/band/gosrock/api/order/model/mapper/OrderMapper.java index 75b1f0cd..b825a898 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/order/model/mapper/OrderMapper.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/order/model/mapper/OrderMapper.java @@ -3,6 +3,7 @@ import band.gosrock.api.common.UserUtils; import band.gosrock.api.order.model.dto.response.CreateOrderResponse; +import band.gosrock.api.order.model.dto.response.OrderAdminTableElement; import band.gosrock.api.order.model.dto.response.OrderBriefElement; import band.gosrock.api.order.model.dto.response.OrderLineTicketResponse; import band.gosrock.api.order.model.dto.response.OrderResponse; @@ -56,8 +57,11 @@ public OrderResponse toOrderResponse(Order order) { return OrderResponse.of(order, event, orderLineTicketResponses); } - private Event getEvent(Order order) { - return eventAdaptor.findById(order.getItemGroupId()); + @Transactional(readOnly = true) + public OrderAdminTableElement toOrderAdminTableElement(Order order) { + Event event = getEvent(order); + User currentUser = userUtils.getCurrentUser(); + return OrderAdminTableElement.of(order, event, currentUser); } @Transactional(readOnly = true) @@ -118,8 +122,18 @@ public OrderBriefElement toOrderBriefElement(Order order) { } public Page toOrderBriefsResponse(Page ordersWithPagination) { - Page orderBriefElements = - ordersWithPagination.map(this::toOrderBriefElement); - return orderBriefElements; + return ordersWithPagination.map(this::toOrderBriefElement); + } + + public Page toOrderResponses(Page orders) { + return orders.map(this::toOrderResponse); + } + + public Page toOrderAdminTableElement(Page orders) { + return orders.map(this::toOrderAdminTableElement); + } + + private Event getEvent(Order order) { + return eventAdaptor.findById(order.getItemGroupId()); } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/order/service/ApproveOrderUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/order/service/ApproveOrderUseCase.java index b46831d1..9d73bba8 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/order/service/ApproveOrderUseCase.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/order/service/ApproveOrderUseCase.java @@ -1,9 +1,14 @@ package band.gosrock.api.order.service; +import band.gosrock.api.common.UserUtils; import band.gosrock.api.order.model.dto.response.OrderResponse; import band.gosrock.api.order.model.mapper.OrderMapper; 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.host.adaptor.HostAdaptor; +import band.gosrock.domain.domains.host.domain.Host; import band.gosrock.domain.domains.order.service.OrderApproveService; import lombok.RequiredArgsConstructor; @@ -14,9 +19,16 @@ public class ApproveOrderUseCase { private final OrderApproveService orderApproveService; private final OrderMapper orderMapper; + private final HostAdaptor hostAdaptor; + private final EventAdaptor eventAdaptor; + private final UserUtils userUtils; + + public OrderResponse execute(Long eventId, String orderUuid) { + Event event = eventAdaptor.findById(eventId); + Host host = hostAdaptor.findById(event.getHostId()); + Long userId = userUtils.getCurrentUserId(); + host.validateHostUser(userId); - public OrderResponse execute(String orderUuid) { - // TODO : 권한 체크 ( 호스트 관리자인지 ) String confirmOrderUuid = orderApproveService.execute(orderUuid); return orderMapper.toOrderResponse(confirmOrderUuid); } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/order/service/ReadOrderUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/order/service/ReadOrderUseCase.java index aeaca8e1..93db6300 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/order/service/ReadOrderUseCase.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/order/service/ReadOrderUseCase.java @@ -3,10 +3,16 @@ import band.gosrock.api.common.UserUtils; import band.gosrock.api.common.page.PageResponse; +import band.gosrock.api.order.model.dto.request.AdminOrderTableQueryRequest; +import band.gosrock.api.order.model.dto.response.OrderAdminTableElement; import band.gosrock.api.order.model.dto.response.OrderBriefElement; import band.gosrock.api.order.model.dto.response.OrderResponse; import band.gosrock.api.order.model.mapper.OrderMapper; 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.host.adaptor.HostAdaptor; +import band.gosrock.domain.domains.host.domain.Host; import band.gosrock.domain.domains.order.adaptor.OrderAdaptor; import band.gosrock.domain.domains.order.domain.Order; import band.gosrock.domain.domains.order.domain.validator.OrderValidator; @@ -25,7 +31,8 @@ public class ReadOrderUseCase { private final OrderAdaptor orderAdaptor; private final OrderValidator orderValidator; - + private final HostAdaptor hostAdaptor; + private final EventAdaptor eventAdaptor; private final UserUtils userUtils; public OrderResponse getOrderDetail(String orderUuid) { @@ -48,10 +55,25 @@ public PageResponse getMyOrders(Boolean showing, Pageable pag ? FindMyPageOrderCondition.onShowing(currentUserId) : FindMyPageOrderCondition.notShowing(currentUserId); - Page ordersWithPagination = - orderAdaptor.findOrdersWithPagination(condition, pageable); + Page ordersWithPagination = orderAdaptor.findMyOrders(condition, pageable); Page orderBriefElements = orderMapper.toOrderBriefsResponse(ordersWithPagination); return PageResponse.of(orderBriefElements); } + + public PageResponse getEventOrders( + Long eventId, + AdminOrderTableQueryRequest adminOrderTableQueryRequest, + Pageable pageable) { + + Event event = eventAdaptor.findById(eventId); + Host host = hostAdaptor.findById(event.getHostId()); + Long userId = userUtils.getCurrentUserId(); + host.validateHostUser(userId); + + Page orders = + orderAdaptor.findEventOrders( + adminOrderTableQueryRequest.toCondition(eventId), pageable); + return PageResponse.of(orderMapper.toOrderAdminTableElement(orders)); + } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/statistic/controller/AdminStatisticController.java b/DuDoong-Api/src/main/java/band/gosrock/api/statistic/controller/AdminStatisticController.java new file mode 100644 index 00000000..37be80ca --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/statistic/controller/AdminStatisticController.java @@ -0,0 +1,29 @@ +package band.gosrock.api.statistic.controller; + + +import band.gosrock.api.statistic.dto.DashBoardStatisticResponse; +import band.gosrock.api.statistic.useCase.StatisticUseCase; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@SecurityRequirement(name = "access-token") +@Tag(name = "어드민 통계관련") +@RestController +@RequestMapping("/v1/events/{eventId}/statistics") +@RequiredArgsConstructor +public class AdminStatisticController { + + private final StatisticUseCase statisticUseCase; + + @Operation(summary = "대시보드 통계를 불러옵니다.") + @GetMapping + public DashBoardStatisticResponse getStatistic(@PathVariable Long eventId) { + return statisticUseCase.execute(eventId); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/statistic/dto/DashBoardStatisticResponse.java b/DuDoong-Api/src/main/java/band/gosrock/api/statistic/dto/DashBoardStatisticResponse.java new file mode 100644 index 00000000..d5ed58df --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/statistic/dto/DashBoardStatisticResponse.java @@ -0,0 +1,31 @@ +package band.gosrock.api.statistic.dto; + + +import band.gosrock.api.statistic.query.result.IssuedTicketStatistic; +import band.gosrock.api.statistic.query.result.OrderStatistic; +import com.fasterxml.jackson.annotation.JsonUnwrapped; +import lombok.Builder; +import lombok.Getter; + +@Getter +public class DashBoardStatisticResponse { + + @JsonUnwrapped OrderStatistic orderStatistic; + + @JsonUnwrapped IssuedTicketStatistic issuedTicketStatistic; + + @Builder + public DashBoardStatisticResponse( + OrderStatistic orderStatistic, IssuedTicketStatistic issuedTicketStatistic) { + this.orderStatistic = orderStatistic; + this.issuedTicketStatistic = issuedTicketStatistic; + } + + public static DashBoardStatisticResponse of( + OrderStatistic orderStatistic, IssuedTicketStatistic issuedTicketStatistic) { + return DashBoardStatisticResponse.builder() + .orderStatistic(orderStatistic) + .issuedTicketStatistic(issuedTicketStatistic) + .build(); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/statistic/query/IssuedTicketQueryRepository.java b/DuDoong-Api/src/main/java/band/gosrock/api/statistic/query/IssuedTicketQueryRepository.java new file mode 100644 index 00000000..b966b5f6 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/statistic/query/IssuedTicketQueryRepository.java @@ -0,0 +1,59 @@ +package band.gosrock.api.statistic.query; + +import static band.gosrock.domain.domains.issuedTicket.domain.IssuedTicketStatus.ENTRANCE_COMPLETED; +import static band.gosrock.domain.domains.issuedTicket.domain.IssuedTicketStatus.ENTRANCE_INCOMPLETE; +import static band.gosrock.domain.domains.issuedTicket.domain.QIssuedTicket.issuedTicket; +import static com.querydsl.core.types.ExpressionUtils.count; + +import band.gosrock.api.statistic.query.result.IssuedTicketStatistic; +import com.querydsl.core.types.Expression; +import com.querydsl.core.types.ExpressionUtils; +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.JPAExpressions; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class IssuedTicketQueryRepository { + + private final JPAQueryFactory queryFactory; + + public IssuedTicketStatistic statistic(Long eventId) { + return queryFactory + .select( + Projections.constructor( + IssuedTicketStatistic.class, + issuedCountEx(eventId), + enteredCountEx(eventId))) + .from(issuedTicket) + .fetchFirst(); + } + + private Expression enteredCountEx(Long eventId) { + return ExpressionUtils.as( + JPAExpressions.select(count(issuedTicket.id)) + .from(issuedTicket) + .where( + eventIdEq(eventId), + issuedTicket.issuedTicketStatus.eq(ENTRANCE_COMPLETED)), + "enteredCount"); + } + + private Expression issuedCountEx(Long eventId) { + return ExpressionUtils.as( + JPAExpressions.select(count(issuedTicket.id)) + .from(issuedTicket) + .where( + eventIdEq(eventId), + issuedTicket.issuedTicketStatus.in( + ENTRANCE_COMPLETED, ENTRANCE_INCOMPLETE)), + "issuedCount"); + } + + private BooleanExpression eventIdEq(Long eventId) { + return eventId == null ? null : issuedTicket.eventId.eq(eventId); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/statistic/query/OrderQueryRepository.java b/DuDoong-Api/src/main/java/band/gosrock/api/statistic/query/OrderQueryRepository.java new file mode 100644 index 00000000..f1f6dbb2 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/statistic/query/OrderQueryRepository.java @@ -0,0 +1,66 @@ +package band.gosrock.api.statistic.query; + +import static band.gosrock.domain.domains.order.domain.OrderStatus.APPROVED; +import static band.gosrock.domain.domains.order.domain.OrderStatus.CONFIRM; +import static band.gosrock.domain.domains.order.domain.OrderStatus.PENDING_APPROVE; +import static band.gosrock.domain.domains.order.domain.QOrder.order; +import static com.querydsl.core.types.ExpressionUtils.count; + +import band.gosrock.api.statistic.query.result.OrderStatistic; +import com.querydsl.core.types.Expression; +import com.querydsl.core.types.ExpressionUtils; +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.JPAExpressions; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.math.BigDecimal; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class OrderQueryRepository { + + private final JPAQueryFactory queryFactory; + + private Expression doneCountEx(Long eventId) { + return ExpressionUtils.as( + JPAExpressions.select(count(order.id)) + .from(order) + .where(eventIdEq(eventId), order.orderStatus.in(CONFIRM, APPROVED)), + "doneCount"); + } + + private Expression notApprovedCountEx(Long eventId) { + return ExpressionUtils.as( + JPAExpressions.select(count(order.id)) + .from(order) + .where(eventIdEq(eventId), order.orderStatus.eq(PENDING_APPROVE)), + "notApprovedCount"); + } + + private Expression sellAmount(Long eventId) { + return ExpressionUtils.as( + JPAExpressions.select(order.totalPaymentInfo.paymentAmount.amount.sum()) + .from(order) + .where(eventIdEq(eventId), order.orderStatus.eq(CONFIRM)), + "sellAmount"); + } + + public OrderStatistic statistic(Long eventId) { + + return queryFactory + .select( + Projections.constructor( + OrderStatistic.class, + doneCountEx(eventId), + notApprovedCountEx(eventId), + sellAmount(eventId))) + .from(order) + .fetchFirst(); + } + + private BooleanExpression eventIdEq(Long eventId) { + return eventId == null ? null : order.eventId.eq(eventId); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/statistic/query/result/IssuedTicketStatistic.java b/DuDoong-Api/src/main/java/band/gosrock/api/statistic/query/result/IssuedTicketStatistic.java new file mode 100644 index 00000000..c567cc97 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/statistic/query/result/IssuedTicketStatistic.java @@ -0,0 +1,18 @@ +package band.gosrock.api.statistic.query.result; + + +import lombok.Getter; + +@Getter +public class IssuedTicketStatistic { + + private final Long enteredCount; + private final Long notEnteredCount; + private final Long issuedCount; + + public IssuedTicketStatistic(Long issuedCount, Long enteredCount) { + this.enteredCount = enteredCount; + this.notEnteredCount = issuedCount - enteredCount; + this.issuedCount = issuedCount; + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/statistic/query/result/OrderStatistic.java b/DuDoong-Api/src/main/java/band/gosrock/api/statistic/query/result/OrderStatistic.java new file mode 100644 index 00000000..55258b40 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/statistic/query/result/OrderStatistic.java @@ -0,0 +1,20 @@ +package band.gosrock.api.statistic.query.result; + + +import band.gosrock.domain.common.vo.Money; +import java.math.BigDecimal; +import lombok.Getter; + +@Getter +public class OrderStatistic { + + private final Long notApprovedCount; + private final Long DoneCount; + private final Money sellAmount; + + public OrderStatistic(Long DoneCount, Long notApprovedCount, BigDecimal sellAmount) { + this.notApprovedCount = notApprovedCount; + this.DoneCount = DoneCount; + this.sellAmount = Money.wons(sellAmount.longValue()); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/statistic/useCase/StatisticUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/statistic/useCase/StatisticUseCase.java new file mode 100644 index 00000000..c7f3fb6f --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/statistic/useCase/StatisticUseCase.java @@ -0,0 +1,28 @@ +package band.gosrock.api.statistic.useCase; + +import static band.gosrock.api.common.aop.hostRole.FindHostFrom.EVENT_ID; +import static band.gosrock.api.common.aop.hostRole.HostQualification.GUEST; + +import band.gosrock.api.common.aop.hostRole.HostRolesAllowed; +import band.gosrock.api.statistic.dto.DashBoardStatisticResponse; +import band.gosrock.api.statistic.query.IssuedTicketQueryRepository; +import band.gosrock.api.statistic.query.OrderQueryRepository; +import band.gosrock.common.annotation.UseCase; +import lombok.RequiredArgsConstructor; +import org.springframework.transaction.annotation.Transactional; + +@UseCase +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class StatisticUseCase { + + private final IssuedTicketQueryRepository issuedTicketQueryRepository; + private final OrderQueryRepository orderQueryRepository; + + @HostRolesAllowed(role = GUEST, findHostFrom = EVENT_ID) + public DashBoardStatisticResponse execute(Long eventId) { + return DashBoardStatisticResponse.of( + orderQueryRepository.statistic(eventId), + issuedTicketQueryRepository.statistic(eventId)); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/controller/TicketItemController.java b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/controller/TicketItemController.java index 40ee4c50..4f0a589f 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/controller/TicketItemController.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/controller/TicketItemController.java @@ -3,14 +3,11 @@ import band.gosrock.api.ticketItem.dto.request.ApplyTicketOptionRequest; import band.gosrock.api.ticketItem.dto.request.CreateTicketItemRequest; -import band.gosrock.api.ticketItem.dto.response.ApplyTicketOptionResponse; +import band.gosrock.api.ticketItem.dto.response.GetAppliedOptionGroupsResponse; import band.gosrock.api.ticketItem.dto.response.GetEventTicketItemsResponse; import band.gosrock.api.ticketItem.dto.response.GetTicketItemOptionsResponse; import band.gosrock.api.ticketItem.dto.response.TicketItemResponse; -import band.gosrock.api.ticketItem.service.ApplyTicketOptionUseCase; -import band.gosrock.api.ticketItem.service.CreateTicketItemUseCase; -import band.gosrock.api.ticketItem.service.GetEventTicketItemsUseCase; -import band.gosrock.api.ticketItem.service.GetTicketOptionsUseCase; +import band.gosrock.api.ticketItem.service.*; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; @@ -29,6 +26,8 @@ public class TicketItemController { public final ApplyTicketOptionUseCase applyTicketOptionUseCase; public final GetTicketOptionsUseCase getTicketOptionsUseCase; public final GetEventTicketItemsUseCase getEventTicketItemsUseCase; + public final DeleteTicketItemUseCase deleteTicketItemUseCase; + public final GetAppliedOptionGroupsUseCase getAppliedOptionGroupsUseCase; @Operation( summary = "특정 이벤트에 속하는 티켓 상품을 생성합니다.", @@ -42,7 +41,7 @@ public TicketItemResponse createTicketItem( @Operation(summary = "옵션을 티켓상품에 적용합니다.") @PatchMapping("/{ticketItemId}/option") - public ApplyTicketOptionResponse applyTicketOption( + public GetTicketItemOptionsResponse applyTicketOption( @RequestBody @Valid ApplyTicketOptionRequest applyTicketOptionRequest, @PathVariable Long eventId, @PathVariable Long ticketItemId) { @@ -61,4 +60,17 @@ public GetTicketItemOptionsResponse getTicketItemOptions( @PathVariable Long eventId, @PathVariable Long ticketItemId) { return getTicketOptionsUseCase.execute(eventId, ticketItemId); } + + @Operation(summary = "해당 이벤트의 티켓상품 옵션 적용 현황을 모두 조회합니다.") + @GetMapping("/appliedOptionGroups") + public GetAppliedOptionGroupsResponse getAppliedOptionGroups(@PathVariable Long eventId) { + return getAppliedOptionGroupsUseCase.execute(eventId); + } + + @Operation(summary = "해당 티켓상품을 삭제합니다.") + @PatchMapping("/{ticketItemId}") + public GetEventTicketItemsResponse deleteTicketItem( + @PathVariable Long eventId, @PathVariable Long ticketItemId) { + return deleteTicketItemUseCase.execute(eventId, ticketItemId); + } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/controller/TicketOptionController.java b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/controller/TicketOptionController.java index 5811dcd9..1fa1f648 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/controller/TicketOptionController.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/controller/TicketOptionController.java @@ -2,8 +2,11 @@ import band.gosrock.api.ticketItem.dto.request.CreateTicketOptionRequest; +import band.gosrock.api.ticketItem.dto.response.GetEventOptionsResponse; import band.gosrock.api.ticketItem.dto.response.OptionGroupResponse; import band.gosrock.api.ticketItem.service.CreateTicketOptionUseCase; +import band.gosrock.api.ticketItem.service.DeleteOptionGroupUseCase; +import band.gosrock.api.ticketItem.service.GetEventOptionsUseCase; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; @@ -19,12 +22,27 @@ public class TicketOptionController { private final CreateTicketOptionUseCase createTicketOptionUseCase; + private final GetEventOptionsUseCase getEventOptionsUseCase; + private final DeleteOptionGroupUseCase deleteOptionGroupUseCase; - @Operation(summary = "특정 이벤트에 속하는 티켓옵션을 생성합니다.") + @Operation(summary = "해당 이벤트에 속하는 티켓옵션을 생성합니다.") @PostMapping public OptionGroupResponse createTicketOption( @RequestBody @Valid CreateTicketOptionRequest createTicketOptionRequest, @PathVariable Long eventId) { return createTicketOptionUseCase.execute(createTicketOptionRequest, eventId); } + + @Operation(summary = "해당 이벤트에 속하는 옵션을 모두 조회합니다.") + @GetMapping + public GetEventOptionsResponse getEventOptions(@PathVariable Long eventId) { + return getEventOptionsUseCase.execute(eventId); + } + + @Operation(summary = "해당 옵션그룹을 삭제합니다.") + @PatchMapping("/{optionGroupId}") + public GetEventOptionsResponse deleteOptionGroup( + @PathVariable Long eventId, @PathVariable Long optionGroupId) { + return deleteOptionGroupUseCase.execute(eventId, optionGroupId); + } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/dto/response/AppliedOptionGroupResponse.java b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/dto/response/AppliedOptionGroupResponse.java new file mode 100644 index 00000000..5aa0b794 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/dto/response/AppliedOptionGroupResponse.java @@ -0,0 +1,32 @@ +package band.gosrock.api.ticketItem.dto.response; + + +import band.gosrock.domain.domains.ticket_item.domain.TicketItem; +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class AppliedOptionGroupResponse { + + @Schema(description = "티켓상품 id") + private final Long ticketItemId; + + @Schema(description = "이름") + private final String ticketName; + + @Schema(description = "적용된 옵션그룹 리스트") + private final List optionGroups; + + public static AppliedOptionGroupResponse from( + TicketItem ticketItem, List optionGroup) { + + return AppliedOptionGroupResponse.builder() + .ticketItemId(ticketItem.getId()) + .ticketName(ticketItem.getName()) + .optionGroups(optionGroup) + .build(); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/dto/response/GetAppliedOptionGroupsResponse.java b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/dto/response/GetAppliedOptionGroupsResponse.java new file mode 100644 index 00000000..766c5be6 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/dto/response/GetAppliedOptionGroupsResponse.java @@ -0,0 +1,23 @@ +package band.gosrock.api.ticketItem.dto.response; + + +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class GetAppliedOptionGroupsResponse { + + @Schema(description = "적용 현황 리스트") + private List appliedOptionGroups; + + public static GetAppliedOptionGroupsResponse from( + List appliedOptionGroups) { + + return GetAppliedOptionGroupsResponse.builder() + .appliedOptionGroups(appliedOptionGroups) + .build(); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/dto/response/GetEventOptionsResponse.java b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/dto/response/GetEventOptionsResponse.java new file mode 100644 index 00000000..4ab8ffa2 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/dto/response/GetEventOptionsResponse.java @@ -0,0 +1,20 @@ +package band.gosrock.api.ticketItem.dto.response; + + +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class GetEventOptionsResponse { + + @Schema(description = "옵션그룹 리스트") + private List optionGroups; + + public static GetEventOptionsResponse from(List optionGroups) { + + return GetEventOptionsResponse.builder().optionGroups(optionGroups).build(); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/mapper/TicketItemMapper.java b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/mapper/TicketItemMapper.java index d6883d6a..80beb77a 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/mapper/TicketItemMapper.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/mapper/TicketItemMapper.java @@ -2,14 +2,15 @@ import band.gosrock.api.ticketItem.dto.request.CreateTicketItemRequest; -import band.gosrock.api.ticketItem.dto.response.GetEventTicketItemsResponse; -import band.gosrock.api.ticketItem.dto.response.TicketItemResponse; +import band.gosrock.api.ticketItem.dto.response.*; import band.gosrock.common.annotation.Mapper; import band.gosrock.domain.common.vo.Money; import band.gosrock.domain.domains.event.adaptor.EventAdaptor; import band.gosrock.domain.domains.event.domain.Event; import band.gosrock.domain.domains.ticket_item.adaptor.TicketItemAdaptor; +import band.gosrock.domain.domains.ticket_item.domain.ItemOptionGroup; import band.gosrock.domain.domains.ticket_item.domain.TicketItem; +import java.util.ArrayList; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.transaction.annotation.Transactional; @@ -44,4 +45,24 @@ public GetEventTicketItemsResponse toGetEventTicketItemsResponse(Long eventId) { return GetEventTicketItemsResponse.from( ticketItems.stream().map(TicketItemResponse::from).toList()); } + + @Transactional(readOnly = true) + public GetAppliedOptionGroupsResponse toGetAppliedOptionGroupsResponse(Long eventId) { + + Event event = eventAdaptor.findById(eventId); + List ticketItems = ticketItemAdaptor.findAllByEventId(event.getId()); + List appliedOptionGroups = new ArrayList<>(); + ticketItems.forEach( + ticketItem -> + appliedOptionGroups.add( + AppliedOptionGroupResponse.from( + ticketItem, + ticketItem.getItemOptionGroups().stream() + .map(ItemOptionGroup::getOptionGroup) + .toList() + .stream() + .map(OptionGroupResponse::from) + .toList()))); + return GetAppliedOptionGroupsResponse.from(appliedOptionGroups); + } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/mapper/TicketOptionMapper.java b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/mapper/TicketOptionMapper.java index 8a56d524..5eb01ff1 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/mapper/TicketOptionMapper.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/mapper/TicketOptionMapper.java @@ -2,10 +2,13 @@ import band.gosrock.api.ticketItem.dto.request.CreateTicketOptionRequest; +import band.gosrock.api.ticketItem.dto.response.GetEventOptionsResponse; import band.gosrock.api.ticketItem.dto.response.GetTicketItemOptionsResponse; import band.gosrock.api.ticketItem.dto.response.OptionGroupResponse; import band.gosrock.common.annotation.Mapper; +import band.gosrock.domain.domains.event.adaptor.EventAdaptor; import band.gosrock.domain.domains.event.domain.Event; +import band.gosrock.domain.domains.ticket_item.adaptor.OptionGroupAdaptor; import band.gosrock.domain.domains.ticket_item.adaptor.TicketItemAdaptor; import band.gosrock.domain.domains.ticket_item.domain.ItemOptionGroup; import band.gosrock.domain.domains.ticket_item.domain.OptionGroup; @@ -20,6 +23,8 @@ public class TicketOptionMapper { private final TicketItemAdaptor ticketItemAdaptor; + private final EventAdaptor eventAdaptor; + private final OptionGroupAdaptor optionGroupAdaptor; public OptionGroup toOptionGroup( CreateTicketOptionRequest createTicketOptionRequest, Event event) { @@ -38,7 +43,7 @@ public GetTicketItemOptionsResponse toGetTicketItemOptionResponse( Long eventId, Long ticketItemId) { TicketItem ticketItem = ticketItemAdaptor.queryTicketItem(ticketItemId); - ticketItem.checkEventId(eventId); + ticketItem.validateEventId(eventId); List optionGroups = ticketItem.getItemOptionGroups().stream() .map(ItemOptionGroup::getOptionGroup) @@ -47,4 +52,15 @@ public GetTicketItemOptionsResponse toGetTicketItemOptionResponse( return GetTicketItemOptionsResponse.from( optionGroups.stream().map(OptionGroupResponse::from).toList()); } + + @Transactional(readOnly = true) + public GetEventOptionsResponse toGetEventOptionResponse(Long eventId) { + + Event event = eventAdaptor.findById(eventId); + + List optionGroups = optionGroupAdaptor.findAllByEventId(event.getId()); + + return GetEventOptionsResponse.from( + optionGroups.stream().map(OptionGroupResponse::from).toList()); + } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/service/ApplyTicketOptionUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/service/ApplyTicketOptionUseCase.java index 800bc67c..95fe227f 100644 --- a/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/service/ApplyTicketOptionUseCase.java +++ b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/service/ApplyTicketOptionUseCase.java @@ -3,7 +3,8 @@ import band.gosrock.api.common.UserUtils; import band.gosrock.api.ticketItem.dto.request.ApplyTicketOptionRequest; -import band.gosrock.api.ticketItem.dto.response.ApplyTicketOptionResponse; +import band.gosrock.api.ticketItem.dto.response.GetTicketItemOptionsResponse; +import band.gosrock.api.ticketItem.mapper.TicketOptionMapper; import band.gosrock.common.annotation.UseCase; import band.gosrock.domain.domains.event.adaptor.EventAdaptor; import band.gosrock.domain.domains.event.domain.Event; @@ -24,8 +25,9 @@ public class ApplyTicketOptionUseCase { private final HostAdaptor hostAdaptor; private final ItemOptionGroupService itemOptionGroupService; private final HostService hostService; + private final TicketOptionMapper ticketOptionMapper; - public ApplyTicketOptionResponse execute( + public GetTicketItemOptionsResponse execute( ApplyTicketOptionRequest applyTicketOptionRequest, Long eventId, Long ticketItemId) { User user = userUtils.getCurrentUser(); Event event = eventAdaptor.findById(eventId); @@ -37,6 +39,7 @@ public ApplyTicketOptionResponse execute( TicketItem ticketItem = itemOptionGroupService.addItemOptionGroup(ticketItemId, optionGroupId, eventId); - return ApplyTicketOptionResponse.from(ticketItem); + + return ticketOptionMapper.toGetTicketItemOptionResponse(eventId, ticketItem.getId()); } } diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/service/DeleteOptionGroupUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/service/DeleteOptionGroupUseCase.java new file mode 100644 index 00000000..3ccce264 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/service/DeleteOptionGroupUseCase.java @@ -0,0 +1,29 @@ +package band.gosrock.api.ticketItem.service; + +import static band.gosrock.api.common.aop.hostRole.FindHostFrom.EVENT_ID; +import static band.gosrock.api.common.aop.hostRole.HostQualification.GUEST; + +import band.gosrock.api.common.aop.hostRole.HostRolesAllowed; +import band.gosrock.api.ticketItem.dto.response.GetEventOptionsResponse; +import band.gosrock.api.ticketItem.mapper.TicketOptionMapper; +import band.gosrock.common.annotation.UseCase; +import band.gosrock.domain.domains.ticket_item.service.TicketOptionService; +import lombok.RequiredArgsConstructor; +import org.springframework.transaction.annotation.Transactional; + +@UseCase +@RequiredArgsConstructor +public class DeleteOptionGroupUseCase { + + private final TicketOptionMapper ticketOptionMapper; + private final TicketOptionService ticketOptionService; + + @Transactional + @HostRolesAllowed(role = GUEST, findHostFrom = EVENT_ID) + public GetEventOptionsResponse execute(Long eventId, Long optionGroupId) { + + ticketOptionService.softDeleteOptionGroup(eventId, optionGroupId); + + return ticketOptionMapper.toGetEventOptionResponse(eventId); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/service/DeleteTicketItemUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/service/DeleteTicketItemUseCase.java new file mode 100644 index 00000000..f2aaabbb --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/service/DeleteTicketItemUseCase.java @@ -0,0 +1,39 @@ +package band.gosrock.api.ticketItem.service; + + +import band.gosrock.api.common.UserUtils; +import band.gosrock.api.ticketItem.dto.response.GetEventTicketItemsResponse; +import band.gosrock.api.ticketItem.mapper.TicketItemMapper; +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.host.adaptor.HostAdaptor; +import band.gosrock.domain.domains.host.domain.Host; +import band.gosrock.domain.domains.host.service.HostService; +import band.gosrock.domain.domains.ticket_item.service.TicketItemService; +import band.gosrock.domain.domains.user.domain.User; +import lombok.RequiredArgsConstructor; + +@UseCase +@RequiredArgsConstructor +public class DeleteTicketItemUseCase { + + private final TicketItemMapper ticketItemMapper; + private final UserUtils userUtils; + private final EventAdaptor eventAdaptor; + private final HostAdaptor hostAdaptor; + private final HostService hostService; + private final TicketItemService ticketItemService; + + public GetEventTicketItemsResponse execute(Long eventId, Long ticketItemId) { + // 권한체크 aop 변경 예정 + User user = userUtils.getCurrentUser(); + Event event = eventAdaptor.findById(eventId); + Host host = hostAdaptor.findById(event.getHostId()); + hostService.validateHostUser(host, user.getId()); + + ticketItemService.softDeleteTicketItem(eventId, ticketItemId); + + return ticketItemMapper.toGetEventTicketItemsResponse(eventId); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/service/GetAppliedOptionGroupsUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/service/GetAppliedOptionGroupsUseCase.java new file mode 100644 index 00000000..25777498 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/service/GetAppliedOptionGroupsUseCase.java @@ -0,0 +1,19 @@ +package band.gosrock.api.ticketItem.service; + + +import band.gosrock.api.ticketItem.dto.response.GetAppliedOptionGroupsResponse; +import band.gosrock.api.ticketItem.mapper.TicketItemMapper; +import band.gosrock.common.annotation.UseCase; +import lombok.RequiredArgsConstructor; + +@UseCase +@RequiredArgsConstructor +public class GetAppliedOptionGroupsUseCase { + + private final TicketItemMapper ticketItemMapper; + + public GetAppliedOptionGroupsResponse execute(Long eventId) { + + return ticketItemMapper.toGetAppliedOptionGroupsResponse(eventId); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/service/GetEventOptionsUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/service/GetEventOptionsUseCase.java new file mode 100644 index 00000000..48fe7280 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/ticketItem/service/GetEventOptionsUseCase.java @@ -0,0 +1,19 @@ +package band.gosrock.api.ticketItem.service; + + +import band.gosrock.api.ticketItem.dto.response.GetEventOptionsResponse; +import band.gosrock.api.ticketItem.mapper.TicketOptionMapper; +import band.gosrock.common.annotation.UseCase; +import lombok.RequiredArgsConstructor; + +@UseCase +@RequiredArgsConstructor +public class GetEventOptionsUseCase { + + private final TicketOptionMapper ticketOptionMapper; + + public GetEventOptionsResponse execute(Long eventId) { + + return ticketOptionMapper.toGetEventOptionResponse(eventId); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/user/controller/UserController.java b/DuDoong-Api/src/main/java/band/gosrock/api/user/controller/UserController.java new file mode 100644 index 00000000..42738cfb --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/user/controller/UserController.java @@ -0,0 +1,30 @@ +package band.gosrock.api.user.controller; + + +import band.gosrock.api.user.service.ReadUserUseCase; +import band.gosrock.domain.common.vo.UserInfoVo; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/v1/users") +@SecurityRequirement(name = "access-token") +@RequiredArgsConstructor +@Slf4j +@Tag(name = "유저 관련 컨트롤러") +public class UserController { + + private final ReadUserUseCase readUserUseCase; + + @Operation(summary = "내 유저 정보를 불러 옵니다.") + @GetMapping("/me") + public UserInfoVo getMyUserInfo() { + return readUserUseCase.execute(); + } +} diff --git a/DuDoong-Api/src/main/java/band/gosrock/api/user/service/ReadUserUseCase.java b/DuDoong-Api/src/main/java/band/gosrock/api/user/service/ReadUserUseCase.java new file mode 100644 index 00000000..4cb7f024 --- /dev/null +++ b/DuDoong-Api/src/main/java/band/gosrock/api/user/service/ReadUserUseCase.java @@ -0,0 +1,20 @@ +package band.gosrock.api.user.service; + + +import band.gosrock.api.common.UserUtils; +import band.gosrock.common.annotation.UseCase; +import band.gosrock.domain.common.vo.UserInfoVo; +import band.gosrock.domain.domains.user.domain.User; +import lombok.RequiredArgsConstructor; + +@UseCase +@RequiredArgsConstructor +public class ReadUserUseCase { + + private final UserUtils userUtils; + + public UserInfoVo execute() { + User currentUser = userUtils.getCurrentUser(); + return currentUser.toUserInfoVo(); + } +} diff --git a/DuDoong-Api/src/main/resources/application.yml b/DuDoong-Api/src/main/resources/application.yml index 36c210be..c26a9c7c 100644 --- a/DuDoong-Api/src/main/resources/application.yml +++ b/DuDoong-Api/src/main/resources/application.yml @@ -17,6 +17,11 @@ server: servlet: context-path: /api forward-headers-strategy: framework + + +slack: + webhook: + id: ${SLACK_WEBHOOK_ID:} --- spring: config: diff --git a/DuDoong-Api/src/test/java/band/gosrock/DuDoongApiServerApplication.java b/DuDoong-Api/src/test/java/band/gosrock/DuDoongApiServerApplication.java index 44e2b7ff..5cf34f64 100644 --- a/DuDoong-Api/src/test/java/band/gosrock/DuDoongApiServerApplication.java +++ b/DuDoong-Api/src/test/java/band/gosrock/DuDoongApiServerApplication.java @@ -1,15 +1,11 @@ package band.gosrock; +import band.gosrock.api.supports.ApiIntegrateSpringBootTest; import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.test.context.ActiveProfiles; -@ActiveProfiles("test") -@ComponentScan(basePackages = "band.gosrock") -@SpringBootTest -class DuDoongApiServerApplication { +@ApiIntegrateSpringBootTest +public class DuDoongApiServerApplication { @Test void contextLoads() {} } diff --git a/DuDoong-Api/src/test/java/band/gosrock/api/eventHandlers/RegisterUserEventHandlerTest.java b/DuDoong-Api/src/test/java/band/gosrock/api/eventHandlers/RegisterUserEventHandlerTest.java index e75ad771..e6226b00 100644 --- a/DuDoong-Api/src/test/java/band/gosrock/api/eventHandlers/RegisterUserEventHandlerTest.java +++ b/DuDoong-Api/src/test/java/band/gosrock/api/eventHandlers/RegisterUserEventHandlerTest.java @@ -3,16 +3,16 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.times; +import band.gosrock.api.supports.ApiIntegrateSpringBootTest; import band.gosrock.domain.domains.user.domain.OauthInfo; import band.gosrock.domain.domains.user.domain.Profile; import band.gosrock.domain.domains.user.service.UserDomainService; import org.junit.jupiter.api.Test; import org.mockito.BDDMockito; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; -@SpringBootTest() +@ApiIntegrateSpringBootTest class RegisterUserEventHandlerTest { @Autowired UserDomainService userDomainService; diff --git a/DuDoong-Api/src/test/java/band/gosrock/api/supports/ApiIntegrateProfileResolver.java b/DuDoong-Api/src/test/java/band/gosrock/api/supports/ApiIntegrateProfileResolver.java new file mode 100644 index 00000000..2af5d63e --- /dev/null +++ b/DuDoong-Api/src/test/java/band/gosrock/api/supports/ApiIntegrateProfileResolver.java @@ -0,0 +1,16 @@ +package band.gosrock.api.supports; + + +import org.springframework.test.context.ActiveProfilesResolver; + +/** + * activeProfile 의 Resolver 를 지정 통합테스트에 필요한 properties 인 common, infrastructure , domain 을 지정하기 위함. + */ +public class ApiIntegrateProfileResolver implements ActiveProfilesResolver { + + @Override + public String[] resolve(Class testClass) { + // some code to find out your active profiles + return new String[] {"common", "infrastructure", "domain"}; + } +} diff --git a/DuDoong-Api/src/test/java/band/gosrock/api/supports/ApiIntegrateSpringBootTest.java b/DuDoong-Api/src/test/java/band/gosrock/api/supports/ApiIntegrateSpringBootTest.java new file mode 100644 index 00000000..6148203b --- /dev/null +++ b/DuDoong-Api/src/test/java/band/gosrock/api/supports/ApiIntegrateSpringBootTest.java @@ -0,0 +1,18 @@ +package band.gosrock.api.supports; + + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +/** 도메인 모듈의 통합테스트의 편의성을 위해서 만든 어노테이션 -이찬진 */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@SpringBootTest(classes = ApiIntegrateTestConfig.class) +@ActiveProfiles(resolver = ApiIntegrateProfileResolver.class) +@Documented +public @interface ApiIntegrateSpringBootTest {} diff --git a/DuDoong-Api/src/test/java/band/gosrock/api/supports/ApiIntegrateTestConfig.java b/DuDoong-Api/src/test/java/band/gosrock/api/supports/ApiIntegrateTestConfig.java new file mode 100644 index 00000000..bf4aaca0 --- /dev/null +++ b/DuDoong-Api/src/test/java/band/gosrock/api/supports/ApiIntegrateTestConfig.java @@ -0,0 +1,20 @@ +package band.gosrock.api.supports; + + +import band.gosrock.DuDoongApiServerApplication; +import band.gosrock.common.DuDoongCommonApplication; +import band.gosrock.domain.DuDoongDomainApplication; +import band.gosrock.infrastructure.DuDoongInfraApplication; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +/** 스프링 부트 설정의 컴포넌트 스캔범위를 지정 통합 테스트를 위함 */ +@Configuration +@ComponentScan( + basePackageClasses = { + DuDoongInfraApplication.class, + DuDoongDomainApplication.class, + DuDoongCommonApplication.class, + DuDoongApiServerApplication.class + }) +public class ApiIntegrateTestConfig {} diff --git a/DuDoong-Common/src/main/java/band/gosrock/common/annotation/Enum.java b/DuDoong-Common/src/main/java/band/gosrock/common/annotation/Enum.java index 4a571163..f7c297d1 100644 --- a/DuDoong-Common/src/main/java/band/gosrock/common/annotation/Enum.java +++ b/DuDoong-Common/src/main/java/band/gosrock/common/annotation/Enum.java @@ -1,7 +1,7 @@ package band.gosrock.common.annotation; -import band.gosrock.common.annotation.validator.EnumValidator; +import band.gosrock.common.validator.EnumValidator; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/DuDoong-Common/src/main/java/band/gosrock/common/annotation/Phone.java b/DuDoong-Common/src/main/java/band/gosrock/common/annotation/Phone.java index 70a2d0f1..9939b034 100644 --- a/DuDoong-Common/src/main/java/band/gosrock/common/annotation/Phone.java +++ b/DuDoong-Common/src/main/java/band/gosrock/common/annotation/Phone.java @@ -1,7 +1,7 @@ package band.gosrock.common.annotation; -import band.gosrock.common.annotation.validator.PhoneValidator; +import band.gosrock.common.validator.PhoneValidator; import java.lang.annotation.*; import javax.validation.Constraint; diff --git a/DuDoong-Common/src/main/java/band/gosrock/common/consts/DuDoongStatic.java b/DuDoong-Common/src/main/java/band/gosrock/common/consts/DuDoongStatic.java index cc106205..0f020bcb 100644 --- a/DuDoong-Common/src/main/java/band/gosrock/common/consts/DuDoongStatic.java +++ b/DuDoong-Common/src/main/java/band/gosrock/common/consts/DuDoongStatic.java @@ -23,6 +23,8 @@ public class DuDoongStatic { public static final Long MINIMUM_PAYMENT_WON = 1000L; public static final Long ZERO = 0L; + public static final String assetDomain = "https://asset.dudoong.com/"; + public static final String KAKAO_OAUTH_QUERY_STRING = "/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code"; } diff --git a/DuDoong-Common/src/main/java/band/gosrock/common/annotation/validator/EnumValidator.java b/DuDoong-Common/src/main/java/band/gosrock/common/validator/EnumValidator.java similarity index 95% rename from DuDoong-Common/src/main/java/band/gosrock/common/annotation/validator/EnumValidator.java rename to DuDoong-Common/src/main/java/band/gosrock/common/validator/EnumValidator.java index e3f6b744..a909ab97 100644 --- a/DuDoong-Common/src/main/java/band/gosrock/common/annotation/validator/EnumValidator.java +++ b/DuDoong-Common/src/main/java/band/gosrock/common/validator/EnumValidator.java @@ -1,4 +1,4 @@ -package band.gosrock.common.annotation.validator; +package band.gosrock.common.validator; import band.gosrock.common.annotation.Enum; diff --git a/DuDoong-Common/src/main/java/band/gosrock/common/annotation/validator/PhoneValidator.java b/DuDoong-Common/src/main/java/band/gosrock/common/validator/PhoneValidator.java similarity index 88% rename from DuDoong-Common/src/main/java/band/gosrock/common/annotation/validator/PhoneValidator.java rename to DuDoong-Common/src/main/java/band/gosrock/common/validator/PhoneValidator.java index f88ee452..5aca6b5e 100644 --- a/DuDoong-Common/src/main/java/band/gosrock/common/annotation/validator/PhoneValidator.java +++ b/DuDoong-Common/src/main/java/band/gosrock/common/validator/PhoneValidator.java @@ -1,4 +1,4 @@ -package band.gosrock.common.annotation.validator; +package band.gosrock.common.validator; import band.gosrock.common.annotation.Phone; diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/dto/ProfileViewDto.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/dto/ProfileViewDto.java index 3e207f2a..f3663e59 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/dto/ProfileViewDto.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/dto/ProfileViewDto.java @@ -1,6 +1,7 @@ package band.gosrock.domain.common.dto; +import band.gosrock.domain.common.vo.ImageVo; import band.gosrock.domain.domains.user.domain.User; import lombok.Builder; import lombok.Getter; @@ -8,12 +9,12 @@ @Getter public class ProfileViewDto { private final Long id; - private final String profileImage; + private final ImageVo profileImage; private final String name; @Builder public ProfileViewDto( - Long id, String email, String phoneNumber, String profileImage, String name) { + Long id, String email, String phoneNumber, ImageVo profileImage, String name) { this.id = id; this.profileImage = profileImage; this.name = name; diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/EventDetailVo.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/EventDetailVo.java index 4bee268e..806e8094 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/EventDetailVo.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/EventDetailVo.java @@ -11,7 +11,7 @@ @Builder public class EventDetailVo { // 포스터 이미지 - private String posterImage; + private ImageVo posterImage; // todo :: 디테일 이미지를 EventDetailImage 로 받기 diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/EventProfileVo.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/EventProfileVo.java index d74f9a82..1c49c1e6 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/EventProfileVo.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/EventProfileVo.java @@ -1,7 +1,8 @@ package band.gosrock.domain.common.vo; -import band.gosrock.domain.domains.event.domain.*; +import band.gosrock.domain.domains.event.domain.Event; +import band.gosrock.domain.domains.event.domain.EventStatus; import java.time.LocalDateTime; import lombok.Builder; import lombok.Getter; @@ -11,7 +12,7 @@ public class EventProfileVo { private Long eventId; - private String posterImage; + private ImageVo posterImage; private String name; diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/HostInfoVo.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/HostInfoVo.java index 74914696..72383214 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/HostInfoVo.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/HostInfoVo.java @@ -14,7 +14,7 @@ public class HostInfoVo { private final String introduce; - private final String profileImageUrl; + private final ImageVo profileImageUrl; private final String contactEmail; @@ -27,7 +27,7 @@ public static HostInfoVo from(Host host) { .hostId(host.getId()) .name(host.getProfile().getName()) .introduce(host.getProfile().getIntroduce()) - .profileImageUrl(host.getProfile().getProfileImageUrl()) + .profileImageUrl(host.getProfile().getProfileImage()) .contactEmail(host.getProfile().getContactEmail()) .contactNumber(host.getProfile().getContactNumber()) .build(); diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/ImageVo.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/ImageVo.java new file mode 100644 index 00000000..6828922d --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/ImageVo.java @@ -0,0 +1,39 @@ +package band.gosrock.domain.common.vo; + +import static band.gosrock.common.consts.DuDoongStatic.assetDomain; + +import com.fasterxml.jackson.annotation.JsonValue; +import javax.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Embeddable +public class ImageVo { + + private String imageKey; + + @JsonValue + public String generateImageUrl() { + // imageKey 널값 대응 + if (imageKey == null) { + return null; + } + // 카카오 이미지로 회원가입한경우 대응 + if (imageKey.contains("kakao")) { + return imageKey; + } + // 현재 도메인 대응 + return assetDomain + imageKey; + } + + public ImageVo(String key) { + this.imageKey = key; + } + + public static ImageVo valueOf(String key) { + return new ImageVo(key); + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/IssuedTicketInfoVo.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/IssuedTicketInfoVo.java index fa81d97b..0e7e05cb 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/IssuedTicketInfoVo.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/IssuedTicketInfoVo.java @@ -1,9 +1,10 @@ package band.gosrock.domain.common.vo; +import band.gosrock.common.annotation.DateFormat; import band.gosrock.domain.domains.issuedTicket.domain.IssuedTicket; import band.gosrock.domain.domains.issuedTicket.domain.IssuedTicketStatus; -import com.fasterxml.jackson.annotation.JsonFormat; +import band.gosrock.domain.domains.issuedTicket.domain.IssuedTicketUserInfoVo; import java.time.LocalDateTime; import lombok.Builder; import lombok.Getter; @@ -40,11 +41,7 @@ public class IssuedTicketInfoVo { /* 티켓 발급 시간 */ - @JsonFormat( - shape = JsonFormat.Shape.STRING, - pattern = "yyyy-MM-dd HH:mm:ss", - timezone = "Asia/Seoul") - private final LocalDateTime createdAt; + @DateFormat private final LocalDateTime createdAt; /* 발급 티켓 상태 @@ -56,16 +53,19 @@ public class IssuedTicketInfoVo { */ private final Money optionPrice; + private final IssuedTicketUserInfoVo userInfo; + public static IssuedTicketInfoVo from(IssuedTicket issuedTicket) { return IssuedTicketInfoVo.builder() .issuedTicketId(issuedTicket.getId()) .issuedTicketNo(issuedTicket.getIssuedTicketNo()) .uuid(issuedTicket.getUuid()) - .ticketName(issuedTicket.getTicketItem().getName()) + .ticketName(issuedTicket.getItemInfo().getTicketName()) .ticketPrice(issuedTicket.getPrice()) .createdAt(issuedTicket.getCreatedAt()) .issuedTicketStatus(issuedTicket.getIssuedTicketStatus()) .optionPrice(issuedTicket.sumOptionPrice()) + .userInfo(issuedTicket.getUserInfo()) .build(); } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/UserInfoVo.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/UserInfoVo.java index 92846552..b1bf081e 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/UserInfoVo.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/UserInfoVo.java @@ -2,6 +2,7 @@ import band.gosrock.domain.domains.user.domain.User; +import java.time.LocalDateTime; import lombok.Builder; import lombok.Getter; @@ -17,7 +18,9 @@ public class UserInfoVo { private final String phoneNumber; - private final String profileImage; + private final ImageVo profileImage; + + private final LocalDateTime createdAt; public static UserInfoVo from(User user) { return UserInfoVo.builder() @@ -26,6 +29,7 @@ public static UserInfoVo from(User user) { .email(user.getProfile().getEmail()) .profileImage(user.getProfile().getProfileImage()) .phoneNumber(user.getProfile().getPhoneNumber()) + .createdAt(user.getCreatedAt()) .build(); } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/UserProfileVo.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/UserProfileVo.java index 1b0b9ac0..324f7958 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/UserProfileVo.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/common/vo/UserProfileVo.java @@ -15,7 +15,7 @@ public class UserProfileVo { private final String email; - private final String profileImage; + private final ImageVo profileImage; public static UserProfileVo from(User user) { return UserProfileVo.builder() diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/cart/domain/CartValidator.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/cart/domain/CartValidator.java index 38fa4ef4..da6522fb 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/cart/domain/CartValidator.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/cart/domain/CartValidator.java @@ -40,7 +40,7 @@ public void validItemPurchaseLimit(Cart cart, TicketItem item) { /** 티켓팅을 할 수 있는 시간을 안지났는지 검증합니다. */ public void validTicketingTime(Event event) { - event.validTicketingTime(); + event.validateTicketingTime(); } /** 아이템의 재고가 충분한지 확인합니다. */ @@ -50,7 +50,7 @@ public void validItemStockEnough(Cart cart, TicketItem item) { /** 이벤트가 현재 열려있는 상태인지 확인합니다. */ public void validEventIsOpen(Event event) { - event.validStatusOpen(); + event.validateStatusOpen(); } /** 카트에 담길때 아이템이 한 종류인지 확인합니다. */ diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/adaptor/EventAdaptor.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/adaptor/EventAdaptor.java index 361b3e80..956a0b1e 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/adaptor/EventAdaptor.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/adaptor/EventAdaptor.java @@ -26,6 +26,10 @@ public Page findAllByHostId(Long hostId, Pageable pageable) { return eventRepository.findAllByHostId(hostId, pageable); } + public Page findAllByHostIdIn(List hostId, Pageable pageable) { + return eventRepository.findAllByHostIdIn(hostId, pageable); + } + public List findAllByIds(List ids) { return eventRepository.findAllByIdIn(ids); } 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 05f5bff8..17d8d5b9 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 @@ -5,7 +5,7 @@ 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.EventIsNotOpenStatusException; +import band.gosrock.domain.domains.event.exception.EventNotOpenException; import band.gosrock.domain.domains.event.exception.EventTicketingTimeIsPassedException; import java.time.LocalDateTime; import javax.persistence.*; @@ -36,7 +36,7 @@ public class Event extends BaseTimeEntity { @Enumerated(EnumType.STRING) private EventStatus status = EventStatus.PREPARING; - private Boolean updated = false; + private Boolean isUpdated = false; /*********** 미확정된 정보 ***********/ // 공연 진행 시간 @@ -62,6 +62,22 @@ public LocalDateTime getEndAt() { return this.getEventBasic().getStartAt().plusMinutes(getEventBasic().getRunTime()); } + public Boolean hasEventBasic() { + return this.eventBasic != null && this.eventBasic.isUpdated(); + } + + public Boolean hasEventPlace() { + return this.eventPlace != null && this.eventPlace.isUpdated(); + } + + public Boolean hasEventDetail() { + return this.eventDetail != null && this.eventDetail.isUpdated(); + } + + public Boolean isPreparing() { + return this.status == EventStatus.PREPARING; + } + /** 티켓팅 시작과 종료 시간을 지정 */ public void setTicketingTime(LocalDateTime startAt, LocalDateTime endAt) { // 이벤트 종료가 시작보다 빠르면 안됨 @@ -73,10 +89,10 @@ public void setTicketingTime(LocalDateTime startAt, LocalDateTime endAt) { } public void setEventBasic(EventBasic eventBasic) { - if (updated) { + if (isUpdated) { throw CannotModifyEventBasicException.EXCEPTION; } - this.updated = true; + this.isUpdated = true; this.eventBasic = eventBasic; } @@ -95,34 +111,34 @@ public Event(Long hostId, String name, LocalDateTime startAt, Long runTime) { this.eventBasic = EventBasic.builder().name(name).startAt(startAt).runTime(runTime).build(); } - public RefundInfoVo getRefundInfoVo() { - return RefundInfoVo.from(getEndAt()); - } - - public Boolean isRefundDateNotPassed() { - return getRefundInfoVo().getAvailAble(); - } - - public EventInfoVo toEventInfoVo() { - return EventInfoVo.from(this); - } - - public void validStatusOpen() { + public void validateStatusOpen() { if (status != EventStatus.OPEN) { - throw EventIsNotOpenStatusException.EXCEPTION; + throw EventNotOpenException.EXCEPTION; } } - public void validTicketingTime() { + public void validateTicketingTime() { if (!isTimeBeforeStartAt()) { throw EventTicketingTimeIsPassedException.EXCEPTION; } } + public Boolean isRefundDateNotPassed() { + return toRefundInfoVo().getAvailAble(); + } + public boolean isTimeBeforeStartAt() { return LocalDateTime.now().isBefore(getStartAt()); } + public RefundInfoVo toRefundInfoVo() { + return RefundInfoVo.from(getEndAt()); + } + + public EventInfoVo toEventInfoVo() { + return EventInfoVo.from(this); + } + public EventDetailVo toEventDetailVo() { return EventDetailVo.from(this); } @@ -139,8 +155,18 @@ public EventPlaceVo toEventPlaceVo() { return EventPlaceVo.from(this); } + public void prepare() { + // TODO : 오픈할수 있는 상태인지 검증필요함. + this.status = EventStatus.PREPARING; + } + public void open() { // TODO : 오픈할수 있는 상태인지 검증필요함. this.status = EventStatus.OPEN; } + + public void close() { + // TODO : 오픈할수 있는 상태인지 검증필요함. + this.status = EventStatus.OPEN; + } } 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 45dbeb06..146c4c14 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 @@ -16,6 +16,10 @@ public class EventBasic { private LocalDateTime startAt; private Long runTime; + protected Boolean isUpdated() { + return this.name != null && this.startAt != null && this.runTime != null; + } + @Builder public EventBasic(String name, LocalDateTime startAt, Long runTime) { this.name = name; diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/EventDetail.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/EventDetail.java index 8c2f6b1b..fdec4f60 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/EventDetail.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/EventDetail.java @@ -1,10 +1,13 @@ package band.gosrock.domain.domains.event.domain; +import band.gosrock.domain.common.vo.ImageVo; import java.util.ArrayList; import java.util.List; +import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Embeddable; +import javax.persistence.Embedded; import javax.persistence.FetchType; import lombok.AccessLevel; import lombok.Builder; @@ -16,7 +19,7 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class EventDetail { // 포스터 이미지 - private String posterImage; + @Embedded private ImageVo posterImage; // todo :: 디테일 이미지를 EventDetailImage 로 받기 @@ -25,11 +28,16 @@ public class EventDetail { private List detailImages = new ArrayList<>(); // (마크다운) 공연 상세 내용 + @Column(columnDefinition = "TEXT") private String content; + protected Boolean isUpdated() { + return this.posterImage != null && this.content != null && !this.detailImages.isEmpty(); + } + @Builder - public EventDetail(String posterImage, List detailImages, String content) { - this.posterImage = posterImage; + public EventDetail(String posterImageKey, List detailImages, String content) { + this.posterImage = ImageVo.valueOf(posterImageKey); this.detailImages = detailImages; this.content = content; } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/EventPlace.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/EventPlace.java index f4dac600..03c468ad 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/EventPlace.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/EventPlace.java @@ -24,6 +24,13 @@ public class EventPlace { // 공연 상세 주소 private String placeAddress; + protected Boolean isUpdated() { + return this.latitude != null + && this.longitude != null + && this.placeName != null + && this.placeAddress != null; + } + @Builder public EventPlace(Double latitude, Double longitude, String placeName, String placeAddress) { this.latitude = latitude; diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/EventStatus.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/EventStatus.java index e68cb7b6..485abd9f 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/EventStatus.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/EventStatus.java @@ -1,6 +1,7 @@ package band.gosrock.domain.domains.event.domain; +import com.fasterxml.jackson.annotation.JsonCreator; import lombok.AllArgsConstructor; import lombok.Getter; @@ -15,4 +16,15 @@ public enum EventStatus { CLOSED("CLOSED"); private final String value; + + // Enum Validation 을 위한 코드, enum 에 속하지 않으면 null 리턴 + @JsonCreator + public static EventStatus fromEventStatus(String val) { + for (EventStatus eventStatus : EventStatus.values()) { + if (eventStatus.name().equals(val)) { + return eventStatus; + } + } + return null; + } } 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 0deb9ba8..90b9f8f9 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 @@ -21,7 +21,7 @@ public enum EventErrorCode implements BaseErrorCode { 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_NOT_OPEN(BAD_REQUEST, "Event_400_5", "아직 오픈되지 않은 이벤트에는 접근할 수 없습니다."), EVENT_TICKETING_TIME_IS_PASSED(BAD_REQUEST, "Event_400_6", "이벤트 시작시간이 지나 티켓팅을 할 수 없습니다."); private Integer status; private String code; diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/EventIsNotOpenStatusException.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/EventNotOpenException.java similarity index 61% rename from DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/EventIsNotOpenStatusException.java rename to DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/EventNotOpenException.java index 94729ef3..4489785e 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/EventIsNotOpenStatusException.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/exception/EventNotOpenException.java @@ -3,11 +3,11 @@ import band.gosrock.common.exception.DuDoongCodeException; -public class EventIsNotOpenStatusException extends DuDoongCodeException { +public class EventNotOpenException extends DuDoongCodeException { - public static final DuDoongCodeException EXCEPTION = new EventIsNotOpenStatusException(); + public static final DuDoongCodeException EXCEPTION = new EventNotOpenException(); - private EventIsNotOpenStatusException() { + private EventNotOpenException() { super(EventErrorCode.EVENT_NOT_OPEN); } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/repository/EventRepository.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/repository/EventRepository.java index 1f4db9e1..266a0395 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/repository/EventRepository.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/repository/EventRepository.java @@ -13,4 +13,6 @@ public interface EventRepository extends CrudRepository { Page findAllByHostId(Long hostId, Pageable pageable); List findAllByIdIn(List ids); + + Page findAllByHostIdIn(List hostIds, Pageable pageable); } 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 1ecfd9f3..a98dac76 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 @@ -3,10 +3,7 @@ import band.gosrock.common.annotation.DomainService; import band.gosrock.domain.domains.event.adaptor.EventAdaptor; -import band.gosrock.domain.domains.event.domain.Event; -import band.gosrock.domain.domains.event.domain.EventBasic; -import band.gosrock.domain.domains.event.domain.EventDetail; -import band.gosrock.domain.domains.event.domain.EventPlace; +import band.gosrock.domain.domains.event.domain.*; import band.gosrock.domain.domains.event.exception.HostNotAuthEventException; import band.gosrock.domain.domains.event.repository.EventRepository; import lombok.RequiredArgsConstructor; @@ -39,6 +36,14 @@ public Event updateEventPlace(Event event, EventPlace eventPlace) { 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(); + 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)) { diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/adaptor/HostAdaptor.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/adaptor/HostAdaptor.java index 13d1f704..6db6c85e 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/adaptor/HostAdaptor.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/adaptor/HostAdaptor.java @@ -28,4 +28,8 @@ public List findAllByMasterUserId(Long userId) { public Page findAllByHostUsers_UserId(Long userId, Pageable pageable) { return hostRepository.findAllByHostUsers_UserId(userId, pageable); } + + public List findAllByHostUsers_UserId(Long userId) { + return hostRepository.findAllByHostUsers_UserId(userId); + } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/domain/Host.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/domain/Host.java index 00d187a0..f0246a81 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/domain/Host.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/domain/Host.java @@ -60,12 +60,12 @@ public void setSlackUrl(String slackUrl) { this.slackUrl = slackUrl; } - public Boolean isSuperHostUserId(Long userId) { + public Boolean isManagerHostUserId(Long userId) { return this.hostUsers.stream() .anyMatch( hostUser -> hostUser.getUserId().equals(userId) - && hostUser.getRole().equals(HostRole.SUPER_HOST)); + && hostUser.getRole().equals(HostRole.MANAGER)); } public Boolean isActiveHostUserId(Long userId) { @@ -100,11 +100,11 @@ public void validateActiveHostUser(Long userId) { } } - /** 해당 유저가 슈퍼 호스트인지 확인하는 검증 로직입니다 */ - public void validateSuperHostUser(Long userId) { + /** 해당 유저가 매니저 이상인지 확인하는 검증 로직입니다 */ + public void validateManagerHostUser(Long userId) { this.validateActiveHostUser(userId); - if (!this.isSuperHostUserId(userId)) { - throw NotSuperHostException.EXCEPTION; + if (!this.isManagerHostUserId(userId) && !this.getMasterUserId().equals(userId)) { + throw NotManagerHostException.EXCEPTION; } } @@ -124,7 +124,7 @@ public HostInfoVo toHostInfoVo() { public Host( String name, String introduce, - String profileImageUrl, + String profileImageKey, String contactEmail, String contactNumber, String slackUrl, @@ -133,7 +133,7 @@ public Host( HostProfile.builder() .name(name) .introduce(introduce) - .profileImageUrl(profileImageUrl) + .profileImageKey(profileImageKey) .contactEmail(contactEmail) .contactNumber(contactNumber) .build(); 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 98b4681a..1152c338 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 @@ -1,8 +1,10 @@ package band.gosrock.domain.domains.host.domain; +import band.gosrock.domain.common.vo.ImageVo; import javax.persistence.Column; import javax.persistence.Embeddable; +import javax.persistence.Embedded; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -19,7 +21,7 @@ public class HostProfile { private String introduce; // 프로필 이미지 url - private String profileImageUrl; + @Embedded private ImageVo profileImage; // 대표자 이메일 private String contactEmail; @@ -29,7 +31,7 @@ public class HostProfile { private String contactNumber; protected void updateProfile(HostProfile hostProfile) { - this.profileImageUrl = hostProfile.getProfileImageUrl(); + this.profileImage = hostProfile.getProfileImage(); this.introduce = hostProfile.getIntroduce(); this.contactEmail = hostProfile.getContactEmail(); this.contactNumber = hostProfile.getContactNumber(); @@ -39,12 +41,12 @@ protected void updateProfile(HostProfile hostProfile) { public HostProfile( String name, String introduce, - String profileImageUrl, + String profileImageKey, String contactEmail, String contactNumber) { this.name = name; this.introduce = introduce; - this.profileImageUrl = profileImageUrl; + this.profileImage = ImageVo.valueOf(profileImageKey); this.contactEmail = contactEmail; this.contactNumber = contactNumber; } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/domain/HostRole.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/domain/HostRole.java index 36267438..d98ae585 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/domain/HostRole.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/domain/HostRole.java @@ -8,10 +8,12 @@ @Getter @AllArgsConstructor public enum HostRole { + // 마스터 (모든 권한) + MASTER("MASTER", "마스터"), // 슈퍼 호스트 (조회, 변경 가능) - SUPER_HOST("SUPER_HOST", "매니저"), + MANAGER("MANAGER", "매니저"), // 일반 호스트 (조회만 가능) - HOST("HOST", "게스트"); + GUEST("GUEST", "게스트"); private final String name; private final String value; diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/domain/HostUser.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/domain/HostUser.java index cf3312b2..6d8efee0 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/domain/HostUser.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/domain/HostUser.java @@ -34,7 +34,7 @@ public class HostUser extends BaseTimeEntity { // 유저의 권한 @Enumerated(EnumType.STRING) - private HostRole role = HostRole.HOST; + private HostRole role = HostRole.GUEST; public void setHostRole(HostRole role) { this.role = role; diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/exception/ForbiddenHostOperationException.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/exception/ForbiddenHostOperationException.java index 0e1010c5..9feeb940 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/exception/ForbiddenHostOperationException.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/exception/ForbiddenHostOperationException.java @@ -7,6 +7,6 @@ public class ForbiddenHostOperationException extends DuDoongCodeException { public static final DuDoongCodeException EXCEPTION = new ForbiddenHostOperationException(); private ForbiddenHostOperationException() { - super(HostErrorCode.FORBIDDEN_HOST_OPERATION); + super(HostErrorCode.CANNOT_MODIFY_MASTER_HOST_ROLE); } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/exception/HostErrorCode.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/exception/HostErrorCode.java index b5cafae3..e2cc56e1 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/exception/HostErrorCode.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/exception/HostErrorCode.java @@ -14,11 +14,11 @@ @Getter @AllArgsConstructor public enum HostErrorCode implements BaseErrorCode { - NOT_SUPER_HOST(BAD_REQUEST, "HOST_400_1", "슈퍼 호스트 권한이 없는 유저입니다."), + NOT_MANAGER_HOST(BAD_REQUEST, "HOST_400_1", "매니저 권한이 없는 유저입니다."), FORBIDDEN_HOST(BAD_REQUEST, "HOST_400_2", "해당 호스트에 대한 접근 권한이 없습니다."), ALREADY_JOINED_HOST(BAD_REQUEST, "HOST_400_3", "이미 가입되어 있는 유저입니다."), NOT_MASTER_HOST(BAD_REQUEST, "HOST_400_4", "마스터 호스트 권한이 없는 유저입니다."), - FORBIDDEN_HOST_OPERATION(BAD_REQUEST, "HOST_400_5", "마스터 호스트의 권한은 변경할 수 없습니다."), + CANNOT_MODIFY_MASTER_HOST_ROLE(BAD_REQUEST, "HOST_400_5", "마스터 호스트의 권한은 변경할 수 없습니다."), NOT_ACCEPTED_HOST(BAD_REQUEST, "HOST_400_6", "아직 초대를 수락하지 않은 유저입니다."), HOST_NOT_FOUND(NOT_FOUND, "Host_404_1", "해당 호스트를 찾을 수 없습니다."), HOST_USER_NOT_FOUND(NOT_FOUND, "HOST_404_2", "가입된 호스트 유저가 아닙니다."); diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/exception/NotSuperHostException.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/exception/NotManagerHostException.java similarity index 51% rename from DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/exception/NotSuperHostException.java rename to DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/exception/NotManagerHostException.java index e653887f..9740b076 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/exception/NotSuperHostException.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/exception/NotManagerHostException.java @@ -3,10 +3,10 @@ import band.gosrock.common.exception.DuDoongCodeException; -public class NotSuperHostException extends DuDoongCodeException { - public static final DuDoongCodeException EXCEPTION = new NotSuperHostException(); +public class NotManagerHostException extends DuDoongCodeException { + public static final DuDoongCodeException EXCEPTION = new NotManagerHostException(); - private NotSuperHostException() { - super(HostErrorCode.NOT_SUPER_HOST); + private NotManagerHostException() { + super(HostErrorCode.NOT_MANAGER_HOST); } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/repository/HostRepository.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/repository/HostRepository.java index 65e88acc..1a388710 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/repository/HostRepository.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/repository/HostRepository.java @@ -10,5 +10,7 @@ public interface HostRepository extends CrudRepository { List findAllByMasterUserId(Long userId); + List findAllByHostUsers_UserId(Long userId); + Page findAllByHostUsers_UserId(Long userId, Pageable pageable); } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/service/HostService.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/service/HostService.java index e1cbc20f..ced1b33f 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/service/HostService.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/host/service/HostService.java @@ -63,8 +63,8 @@ public void validateMasterHostUser(Host host, Long userId) { } /** 해당 유저가 슈퍼 호스트인지 확인하는 검증 로직입니다 */ - public void validateSuperHostUser(Long hostId, Long userId) { + public void validateManagerHostUser(Long hostId, Long userId) { Host host = hostAdaptor.findById(hostId); - host.validateSuperHostUser(userId); + host.validateManagerHostUser(userId); } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/adaptor/IssuedTicketAdaptor.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/adaptor/IssuedTicketAdaptor.java index ce3fd16c..6638ef52 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/adaptor/IssuedTicketAdaptor.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/adaptor/IssuedTicketAdaptor.java @@ -34,13 +34,13 @@ public IssuedTicket findForUser(Long currentUserId, Long issuedTicketId) { issuedTicketRepository .find(issuedTicketId) .orElseThrow(() -> IssuedTicketNotFoundException.EXCEPTION); - if (!Objects.equals(issuedTicket.getUser().getId(), currentUserId)) { + if (!Objects.equals(issuedTicket.getUserInfo().getUserId(), currentUserId)) { throw IssuedTicketUserNotMatchedException.EXCEPTION; } return issuedTicket; } - public IssuedTicket find(Long issuedTicketId) { + public IssuedTicket queryIssuedTicket(Long issuedTicketId) { return issuedTicketRepository .find(issuedTicketId) .orElseThrow(() -> IssuedTicketNotFoundException.EXCEPTION); diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/domain/IssuedTicket.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/domain/IssuedTicket.java index 54d68516..353c2dac 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/domain/IssuedTicket.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/domain/IssuedTicket.java @@ -17,6 +17,7 @@ import java.util.UUID; import javax.persistence.CascadeType; import javax.persistence.Column; +import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; @@ -25,7 +26,6 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.PostPersist; import javax.persistence.PrePersist; @@ -45,12 +45,11 @@ public class IssuedTicket extends BaseTimeEntity { private String issuedTicketNo; - /* - 발급 티켓의 이벤트 (양방향) - */ - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "event_id") - private Event event; + private Long eventId; + + @Embedded private IssuedTicketUserInfoVo userInfo; + + @Embedded private IssuedTicketItemInfoVo itemInfo; /* 발급 티켓 주문 id (단방향) @@ -62,20 +61,6 @@ public class IssuedTicket extends BaseTimeEntity { */ private Long orderLineId; - /* - 티켓 발급 유저 id - */ - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "userId") - private User user; - - /* - 발급 티켓의 item (양방향) - */ - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "ticket_item_id") - private TicketItem ticketItem; - /* 발급 티켓의 옵션들 (단방향) */ @@ -96,7 +81,7 @@ public void addOptionAnswers(List answers) { /* 발급 티켓 가격 */ - private Money price; + @Embedded private Money price; /* 발급 티켓 상태 @@ -117,41 +102,17 @@ public IssuedTicket( TicketItem ticketItem, Money price, List issuedTicketOptionAnswers) { - this.event = event; - this.user = user; + this.eventId = event.getId(); + this.userInfo = IssuedTicketUserInfoVo.from(user); + this.itemInfo = IssuedTicketItemInfoVo.from(ticketItem); this.orderUuid = orderUuid; this.orderLineId = orderLineId; - this.ticketItem = ticketItem; this.price = price; this.issuedTicketOptionAnswers.addAll(issuedTicketOptionAnswers); } /** ---------------------------- 생성 관련 메서드 ---------------------------------- */ - /* - 개발 및 테스트 용도로 사용되는 티켓 발급 정적 메서드 - */ - public static IssuedTicket createForDev( - Event event, - User user, - Long orderLineId, - TicketItem ticketItem, - Money price, - List issuedTicketOptionAnswers) { - IssuedTicket createIssuedTicket = - IssuedTicket.builder() - .event(event) - .user(user) - .orderUuid("test") - .orderLineId(orderLineId) - .ticketItem(ticketItem) - .price(price) - .issuedTicketOptionAnswers(new ArrayList<>()) - .build(); - createIssuedTicket.getIssuedTicketOptionAnswers().addAll(issuedTicketOptionAnswers); - return createIssuedTicket; - } - /* issuedTicket 생성하면서 UUID 생성 */ diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/domain/IssuedTicketCancelReason.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/domain/IssuedTicketCancelReason.java new file mode 100644 index 00000000..0ccc9f4e --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/domain/IssuedTicketCancelReason.java @@ -0,0 +1,16 @@ +package band.gosrock.domain.domains.issuedTicket.domain; + + +import com.fasterxml.jackson.annotation.JsonValue; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum IssuedTicketCancelReason { + REFUND("REFUND", "사용자에 의한 환불"); + + private final String value; + + @JsonValue private final String kr; +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/domain/IssuedTicketItemInfoVo.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/domain/IssuedTicketItemInfoVo.java new file mode 100644 index 00000000..f27a75cc --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/domain/IssuedTicketItemInfoVo.java @@ -0,0 +1,36 @@ +package band.gosrock.domain.domains.issuedTicket.domain; + + +import band.gosrock.domain.domains.ticket_item.domain.TicketItem; +import band.gosrock.domain.domains.ticket_item.domain.TicketType; +import javax.persistence.Embeddable; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Embeddable +@NoArgsConstructor +public class IssuedTicketItemInfoVo { + + private Long ticketItemId; + + private TicketType ticketType; + + private String ticketName; + + @Builder + public IssuedTicketItemInfoVo(Long ticketItemId, TicketType ticketType, String ticketName) { + this.ticketItemId = ticketItemId; + this.ticketType = ticketType; + this.ticketName = ticketName; + } + + public static IssuedTicketItemInfoVo from(TicketItem item) { + return IssuedTicketItemInfoVo.builder() + .ticketItemId(item.getId()) + .ticketType(item.getType()) + .ticketName(item.getName()) + .build(); + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/domain/IssuedTicketUserInfoVo.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/domain/IssuedTicketUserInfoVo.java new file mode 100644 index 00000000..d288edb8 --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/domain/IssuedTicketUserInfoVo.java @@ -0,0 +1,35 @@ +package band.gosrock.domain.domains.issuedTicket.domain; + + +import band.gosrock.domain.domains.user.domain.User; +import javax.persistence.Embeddable; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Embeddable +@NoArgsConstructor +public class IssuedTicketUserInfoVo { + + private Long userId; + + private String userName; + + private String phoneNumber; + + @Builder + public IssuedTicketUserInfoVo(Long userId, String userName, String phoneNumber) { + this.userId = userId; + this.userName = userName; + this.phoneNumber = phoneNumber; + } + + public static IssuedTicketUserInfoVo from(User user) { + return IssuedTicketUserInfoVo.builder() + .userId(user.getId()) + .userName(user.getProfile().getName()) + .phoneNumber(user.getProfile().getPhoneNumber()) + .build(); + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/domain/IssuedTickets.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/domain/IssuedTickets.java index 4ff78eeb..eb33be8b 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/domain/IssuedTickets.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/domain/IssuedTickets.java @@ -23,7 +23,7 @@ public List getNos() { public String getItemName() { IssuedTicket issuedTicket = issuedTickets.stream().findFirst().orElseThrow(); - return issuedTicket.getTicketItem().getName(); + return issuedTicket.getItemInfo().getTicketName(); } public int getTotalQuantity() { diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/exception/IssuedTicketErrorCode.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/exception/IssuedTicketErrorCode.java index 9925ec1c..a699c87f 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/exception/IssuedTicketErrorCode.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/exception/IssuedTicketErrorCode.java @@ -14,13 +14,15 @@ @Getter @AllArgsConstructor public enum IssuedTicketErrorCode implements BaseErrorCode { - ISSUED_TICKET_NOT_FOUND(NOT_FOUND, "IssuedTicket_404_1", "IssuedTicket Not Found"), + ISSUED_TICKET_NOT_FOUND(NOT_FOUND, "IssuedTicket_404_1", "티켓을 찾을 수 없습니다."), ISSUED_TICKET_NOT_MATCHED_USER( BAD_REQUEST, "IssuedTicket_400_1", "IssuedTicket User Not Matched"), CAN_NOT_CANCEL(BAD_REQUEST, "IssuedTicket_400_2", "티켓을 취소 할 수 있는 상태가 아닙니다."), CAN_NOT_CANCEL_ENTRANCE(BAD_REQUEST, "IssuedTicket_400_3", "티켓이 입장 취소 할 수 있는 상태가 아닙니다."), CAN_NOT_ENTRANCE(BAD_REQUEST, "IssuedTicket_400_4", "티켓이 입장 할 수 있는 상태가 아닙니다."), - ISSUED_TICKET_ALREADY_ENTRANCE(BAD_REQUEST, "IssuedTicket_400_5", "이미 입장 처리된 티켓입니다."); + ISSUED_TICKET_ALREADY_ENTRANCE(BAD_REQUEST, "IssuedTicket_400_5", "이미 입장 처리된 티켓입니다."), + ISSUED_TICKET_NOT_MATCHED_EVENT( + BAD_REQUEST, "IssuedTicket_400_6", "이 티켓은 해당 이벤트에서 발급된 티켓이 아닙니다."); private Integer status; private String code; diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/exception/IssuedTicketNotMatchedEventException.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/exception/IssuedTicketNotMatchedEventException.java new file mode 100644 index 00000000..971d4076 --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/exception/IssuedTicketNotMatchedEventException.java @@ -0,0 +1,13 @@ +package band.gosrock.domain.domains.issuedTicket.exception; + + +import band.gosrock.common.exception.DuDoongCodeException; + +public class IssuedTicketNotMatchedEventException extends DuDoongCodeException { + + public static final DuDoongCodeException EXCEPTION = new IssuedTicketNotMatchedEventException(); + + private IssuedTicketNotMatchedEventException() { + super(IssuedTicketErrorCode.ISSUED_TICKET_NOT_MATCHED_EVENT); + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/repository/IssuedTicketCustomRepositoryImpl.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/repository/IssuedTicketCustomRepositoryImpl.java index 4743d31e..7c7028fa 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/repository/IssuedTicketCustomRepositoryImpl.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/repository/IssuedTicketCustomRepositoryImpl.java @@ -1,10 +1,7 @@ package band.gosrock.domain.domains.issuedTicket.repository; -import static band.gosrock.domain.domains.event.domain.QEvent.event; import static band.gosrock.domain.domains.issuedTicket.domain.QIssuedTicket.issuedTicket; import static band.gosrock.domain.domains.issuedTicket.domain.QIssuedTicketOptionAnswer.issuedTicketOptionAnswer; -import static band.gosrock.domain.domains.ticket_item.domain.QTicketItem.ticketItem; -import static band.gosrock.domain.domains.user.domain.QUser.user; import band.gosrock.domain.domains.issuedTicket.domain.IssuedTicket; import band.gosrock.domain.domains.issuedTicket.domain.IssuedTicketStatus; @@ -29,20 +26,11 @@ public Page searchToPage(IssuedTicketCondition condition, Pageable List issuedTickets = queryFactory .selectFrom(issuedTicket) - .leftJoin(issuedTicket.event, event) - .fetchJoin() - .leftJoin(issuedTicket.user, user) - .fetchJoin() - .leftJoin(issuedTicket.ticketItem, ticketItem) - .fetchJoin() .where( eventIdEq(condition.getEventId()), userNameContains(condition.getUserName()), phoneNumberContains(condition.getPhoneNumber()), - issuedTicket - .issuedTicketStatus - .eq(IssuedTicketStatus.CANCELED) - .not()) + issuedTicketStatusNotCanceled()) .orderBy(issuedTicket.id.desc()) .offset(pageable.getOffset()) .limit(pageable.getPageSize()) @@ -55,7 +43,8 @@ public Page searchToPage(IssuedTicketCondition condition, Pageable .where( eventIdEq(condition.getEventId()), userNameContains(condition.getUserName()), - phoneNumberContains(condition.getPhoneNumber())); + phoneNumberContains(condition.getPhoneNumber()), + issuedTicketStatusNotCanceled()); return PageableExecutionUtils.getPage(issuedTickets, pageable, countQuery::fetchOne); } @@ -65,38 +54,26 @@ public Optional find(Long issuedTicketId) { IssuedTicket findIssuedTicket = queryFactory .selectFrom(issuedTicket) - .leftJoin(issuedTicket.event, event) - .fetchJoin() - .leftJoin(issuedTicket.user, user) - .fetchJoin() - .leftJoin(issuedTicket.ticketItem, ticketItem) - .fetchJoin() .leftJoin(issuedTicket.issuedTicketOptionAnswers, issuedTicketOptionAnswer) .fetchJoin() - .where( - issuedTicket - .id - .eq(issuedTicketId) - .and( - issuedTicket - .issuedTicketStatus - .eq(IssuedTicketStatus.CANCELED) - .not())) + .where(issuedTicket.id.eq(issuedTicketId), issuedTicketStatusNotCanceled()) .fetchOne(); return Optional.ofNullable(findIssuedTicket); } private BooleanExpression eventIdEq(Long eventId) { - return eventId == null ? null : issuedTicket.event.id.eq(eventId); + return eventId == null ? null : issuedTicket.eventId.eq(eventId); } private BooleanExpression userNameContains(String userName) { - return userName == null ? null : issuedTicket.user.profile.name.contains(userName); + return userName == null ? null : issuedTicket.userInfo.userName.contains(userName); } private BooleanExpression phoneNumberContains(String phoneNumber) { - return phoneNumber == null - ? null - : issuedTicket.user.profile.phoneNumber.contains(phoneNumber); + return phoneNumber == null ? null : issuedTicket.userInfo.phoneNumber.contains(phoneNumber); + } + + private BooleanExpression issuedTicketStatusNotCanceled() { + return issuedTicket.issuedTicketStatus.eq(IssuedTicketStatus.CANCELED).not(); } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/service/IssuedTicketDomainService.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/service/IssuedTicketDomainService.java index c408b3b1..672d1cf1 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/service/IssuedTicketDomainService.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/service/IssuedTicketDomainService.java @@ -4,13 +4,13 @@ import band.gosrock.common.annotation.DomainService; import band.gosrock.domain.common.aop.redissonLock.RedissonLock; import band.gosrock.domain.common.vo.IssuedTicketInfoVo; -import band.gosrock.domain.domains.event.exception.HostNotAuthEventException; +import band.gosrock.domain.domains.event.adaptor.EventAdaptor; import band.gosrock.domain.domains.issuedTicket.adaptor.IssuedTicketAdaptor; import band.gosrock.domain.domains.issuedTicket.domain.IssuedTicket; +import band.gosrock.domain.domains.issuedTicket.validator.IssuedTicketValidator; import band.gosrock.domain.domains.ticket_item.adaptor.TicketItemAdaptor; import band.gosrock.domain.domains.ticket_item.domain.TicketItem; import java.util.List; -import java.util.Objects; import lombok.RequiredArgsConstructor; import org.springframework.transaction.annotation.Transactional; @@ -20,31 +20,36 @@ public class IssuedTicketDomainService { private final IssuedTicketAdaptor issuedTicketAdaptor; private final TicketItemAdaptor ticketItemAdaptor; + private final EventAdaptor eventAdaptor; + + private final IssuedTicketValidator issuedTicketValidator; private final OrderToIssuedTicketService orderToIssuedTicketService; - @RedissonLock(LockName = "티켓재고관리", identifier = "itemId") - @Transactional - public void withDrawIssuedTicket(Long itemId, List issuedTickets) { + @RedissonLock(LockName = "티켓관리", identifier = "itemId") + public void withdrawIssuedTicket(Long itemId, List issuedTickets) { + // itemId로 티켓 아이템 찾아서 (해당 락에선 ticketItem이 하나로 정해지기 때문에) + TicketItem ticketItem = ticketItemAdaptor.queryTicketItem(itemId); issuedTickets.forEach( issuedTicket -> { - issuedTicket.getTicketItem().increaseQuantity(1L); - issuedTicketAdaptor.cancel(issuedTicket); + // 재고 복구하고 + ticketItem.increaseQuantity(1L); + // 발급된 티켓 취소 + issuedTicket.cancel(); }); } @Transactional public IssuedTicketInfoVo processingEntranceIssuedTicket( - Long currentUserId, Long issuedTicketId) { - IssuedTicket issuedTicket = issuedTicketAdaptor.find(issuedTicketId); - if (!Objects.equals(issuedTicket.getEvent().getHostId(), currentUserId)) { - throw HostNotAuthEventException.EXCEPTION; - } + Long eventId, Long currentUserId, Long issuedTicketId) { + IssuedTicket issuedTicket = issuedTicketAdaptor.queryIssuedTicket(issuedTicketId); + issuedTicketValidator.validIssuedTicketEventIdEqualEvent(issuedTicket, eventId); + issuedTicketValidator.validCanModifyIssuedTicketUser(issuedTicket, currentUserId); issuedTicket.entrance(); return issuedTicket.toIssuedTicketInfoVo(); } - @RedissonLock(LockName = "티켓재고관리", identifier = "itemId") + @RedissonLock(LockName = "티켓관리", identifier = "itemId") public void createIssuedTicket(Long itemId, String orderUuid, Long userId) { TicketItem ticketItem = ticketItemAdaptor.queryTicketItem(itemId); List issuedTickets = diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/service/handlers/WithDrawOrderEventHandler.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/service/handlers/WithDrawOrderEventHandler.java index 09b75337..df6e21c5 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/service/handlers/WithDrawOrderEventHandler.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/service/handlers/WithDrawOrderEventHandler.java @@ -24,11 +24,11 @@ public class WithDrawOrderEventHandler { @TransactionalEventListener( classes = WithDrawOrderEvent.class, phase = TransactionPhase.BEFORE_COMMIT) - public void handleWithDrawOrderEvent(WithDrawOrderEvent withDrawOrderEvent) { + public void handleWithdrawOrderEvent(WithDrawOrderEvent withDrawOrderEvent) { log.info(withDrawOrderEvent.getOrderUuid() + "주문 상태 철회 , 티켓 철회 필요"); List issuedTickets = issuedTicketAdaptor.findAllByOrderUuid(withDrawOrderEvent.getOrderUuid()); - issuedTicketDomainService.withDrawIssuedTicket( + issuedTicketDomainService.withdrawIssuedTicket( withDrawOrderEvent.getItemId(), issuedTickets); } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/validator/IssuedTicketValidator.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/validator/IssuedTicketValidator.java new file mode 100644 index 00000000..5b06a878 --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/issuedTicket/validator/IssuedTicketValidator.java @@ -0,0 +1,32 @@ +package band.gosrock.domain.domains.issuedTicket.validator; + + +import band.gosrock.common.annotation.Validator; +import band.gosrock.domain.domains.event.adaptor.EventAdaptor; +import band.gosrock.domain.domains.event.domain.Event; +import band.gosrock.domain.domains.host.adaptor.HostAdaptor; +import band.gosrock.domain.domains.host.domain.Host; +import band.gosrock.domain.domains.issuedTicket.domain.IssuedTicket; +import band.gosrock.domain.domains.issuedTicket.exception.IssuedTicketNotMatchedEventException; +import java.util.Objects; +import lombok.RequiredArgsConstructor; + +@Validator +@RequiredArgsConstructor +public class IssuedTicketValidator { + + private final EventAdaptor eventAdaptor; + private final HostAdaptor hostAdaptor; + + public void validCanModifyIssuedTicketUser(IssuedTicket issuedTicket, Long currentUserId) { + Event event = eventAdaptor.findById(issuedTicket.getEventId()); + Host host = hostAdaptor.findById(event.getHostId()); + host.validateHostUser(currentUserId); + } + + public void validIssuedTicketEventIdEqualEvent(IssuedTicket issuedTicket, Long eventId) { + if (!Objects.equals(issuedTicket.getEventId(), eventId)) { + throw IssuedTicketNotMatchedEventException.EXCEPTION; + } + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/adaptor/OrderAdaptor.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/adaptor/OrderAdaptor.java index bb796632..01cdc0d9 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/adaptor/OrderAdaptor.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/adaptor/OrderAdaptor.java @@ -5,6 +5,7 @@ import band.gosrock.domain.domains.order.domain.Order; import band.gosrock.domain.domains.order.exception.OrderNotFoundException; import band.gosrock.domain.domains.order.repository.OrderRepository; +import band.gosrock.domain.domains.order.repository.condition.FindEventOrdersCondition; import band.gosrock.domain.domains.order.repository.condition.FindMyPageOrderCondition; import java.util.Optional; import lombok.RequiredArgsConstructor; @@ -35,8 +36,11 @@ public Optional findRecentOrderByUserId(Long userId) { return orderRepository.findFirstByUserIdOrderByIdDesc(userId); } - public Page findOrdersWithPagination( - FindMyPageOrderCondition condition, Pageable pageable) { - return orderRepository.getMyPageOrders(condition, pageable); + public Page findMyOrders(FindMyPageOrderCondition condition, Pageable pageable) { + return orderRepository.findMyOrders(condition, pageable); + } + + public Page findEventOrders(FindEventOrdersCondition condition, Pageable pageable) { + return orderRepository.findEventOrders(condition, pageable); } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/domain/Order.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/domain/Order.java index b6665be2..67d9d180 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/domain/Order.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/domain/Order.java @@ -72,6 +72,9 @@ public class Order extends BaseTimeEntity { // 결제 완료 된시간 승인 결제등. private LocalDateTime approvedAt; + // 철회된 시간 + private LocalDateTime withDrawAt; + @Enumerated(EnumType.STRING) @Column(nullable = false) private OrderMethod orderMethod; @@ -131,6 +134,7 @@ public static Order createPaymentOrder( .eventId(item.getEventId()) .build(); orderValidator.validCanCreate(order); + order.calculatePaymentInfo(); return order; } @@ -223,6 +227,7 @@ public void freeConfirm(Long currentUserId, OrderValidator orderValidator) { public void cancel(OrderValidator orderValidator) { orderValidator.validCanCancel(this); this.orderStatus = OrderStatus.CANCELED; + this.withDrawAt = LocalDateTime.now(); Events.raise(WithDrawOrderEvent.from(this)); } @@ -231,6 +236,7 @@ public void refund(Long currentUserId, OrderValidator orderValidator) { orderValidator.validOwner(this, currentUserId); orderValidator.validCanRefund(this); this.orderStatus = OrderStatus.REFUND; + this.withDrawAt = LocalDateTime.now(); Events.raise(WithDrawOrderEvent.from(this)); } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/domain/validator/OrderValidator.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/domain/validator/OrderValidator.java index 62b57ec7..d01031b3 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/domain/validator/OrderValidator.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/domain/validator/OrderValidator.java @@ -141,7 +141,7 @@ public void validItemPurchaseLimit(Order order, TicketItem item) { /** 이벤트가 열려있는 상태인지 */ public void validEventIsOpen(Event event) { - event.validStatusOpen(); + event.validateStatusOpen(); } /** 아이템의 종류가 1종류인지. */ @@ -154,7 +154,7 @@ public void validItemKindIsOneType(Order order) { /** 티켓 예매 가능 시간이 아직 안지났는지. */ public void validTicketingTime(Event event) { - event.validTicketingTime(); + event.validateTicketingTime(); } /** 아이템의 재고가 충분한지 확인합니다. */ diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/repository/OrderCustomRepository.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/repository/OrderCustomRepository.java index eaff6fed..6942a6d6 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/repository/OrderCustomRepository.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/repository/OrderCustomRepository.java @@ -2,11 +2,14 @@ import band.gosrock.domain.domains.order.domain.Order; +import band.gosrock.domain.domains.order.repository.condition.FindEventOrdersCondition; import band.gosrock.domain.domains.order.repository.condition.FindMyPageOrderCondition; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; public interface OrderCustomRepository { - Page getMyPageOrders(FindMyPageOrderCondition condition, Pageable pageable); + Page findMyOrders(FindMyPageOrderCondition condition, Pageable pageable); + + Page findEventOrders(FindEventOrdersCondition condition, Pageable pageable); } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/repository/OrderCustomRepositoryImpl.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/repository/OrderCustomRepositoryImpl.java index d8e930b5..efcf17f9 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/repository/OrderCustomRepositoryImpl.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/repository/OrderCustomRepositoryImpl.java @@ -2,8 +2,10 @@ import static band.gosrock.domain.domains.event.domain.QEvent.event; import static band.gosrock.domain.domains.order.domain.QOrder.order; +import static band.gosrock.domain.domains.user.domain.QUser.user; import band.gosrock.domain.domains.order.domain.Order; +import band.gosrock.domain.domains.order.repository.condition.FindEventOrdersCondition; import band.gosrock.domain.domains.order.repository.condition.FindMyPageOrderCondition; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.core.types.dsl.DateTemplate; @@ -23,15 +25,15 @@ public class OrderCustomRepositoryImpl implements OrderCustomRepository { private final JPAQueryFactory queryFactory; @Override - public Page getMyPageOrders(FindMyPageOrderCondition condition, Pageable pageable) { + public Page findMyOrders(FindMyPageOrderCondition condition, Pageable pageable) { - List issuedTickets = + List orders = queryFactory .selectFrom(order) .join(event) .on(order.eventId.eq(event.id)) .where( - userIdEq(condition.getUserId()), + eqUserId(condition.getUserId()), openingState(condition.getShowing())) .orderBy(order.id.desc()) .offset(pageable.getOffset()) @@ -45,16 +47,50 @@ public Page getMyPageOrders(FindMyPageOrderCondition condition, Pageable .on(order.eventId.eq(event.id)) .from(order) .where( - userIdEq(condition.getUserId()), + eqUserId(condition.getUserId()), openingState(condition.getShowing())); - return PageableExecutionUtils.getPage(issuedTickets, pageable, countQuery::fetchOne); + return PageableExecutionUtils.getPage(orders, pageable, countQuery::fetchOne); } - private BooleanExpression userIdEq(Long userId) { + @Override + public Page findEventOrders(FindEventOrdersCondition condition, Pageable pageable) { + List orders = + queryFactory + .selectFrom(order) + .join(user) + .on(user.id.eq(order.userId)) + .where( + eqEventId(condition.getEventId()), + condition.getOrderStatusFilter(), + condition.getSearchStringFilter()) + .orderBy(order.id.desc()) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); + + JPAQuery countQuery = + queryFactory + .select(order.count()) + .from(order) + .join(user) + .on(user.id.eq(order.userId)) + .where( + eqEventId(condition.getEventId()), + condition.getOrderStatusFilter(), + condition.getSearchStringFilter()); + + return PageableExecutionUtils.getPage(orders, pageable, countQuery::fetchOne); + } + + private BooleanExpression eqUserId(Long userId) { return userId == null ? null : order.userId.eq(userId); } + private BooleanExpression eqEventId(Long eventId) { + return eventId == null ? null : order.eventId.eq(eventId); + } + private BooleanExpression openingState(Boolean isShowing) { DateTemplate eventEndAtTemplate = Expressions.dateTemplate( diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/repository/condition/AdminTableOrderFilterType.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/repository/condition/AdminTableOrderFilterType.java new file mode 100644 index 00000000..9cab0c62 --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/repository/condition/AdminTableOrderFilterType.java @@ -0,0 +1,26 @@ +package band.gosrock.domain.domains.order.repository.condition; + +import static band.gosrock.domain.domains.order.domain.OrderStatus.APPROVED; +import static band.gosrock.domain.domains.order.domain.OrderStatus.CANCELED; +import static band.gosrock.domain.domains.order.domain.OrderStatus.CONFIRM; +import static band.gosrock.domain.domains.order.domain.OrderStatus.PENDING_APPROVE; +import static band.gosrock.domain.domains.order.domain.OrderStatus.REFUND; +import static band.gosrock.domain.domains.order.domain.QOrder.order; + +import com.querydsl.core.types.dsl.BooleanExpression; + +/** 어드민 테이블의 주문 상태 검색 조건 지정을 위함. */ +public enum AdminTableOrderFilterType { + APPROVE_WAITING(order.orderStatus.eq(PENDING_APPROVE)), + CONFIRMED(order.orderStatus.in(CONFIRM, APPROVED, CANCELED, REFUND)); + + private final BooleanExpression expression; + + AdminTableOrderFilterType(BooleanExpression expression) { + this.expression = expression; + } + + public BooleanExpression getFilter() { + return expression; + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/repository/condition/AdminTableSearchType.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/repository/condition/AdminTableSearchType.java new file mode 100644 index 00000000..fbbb6731 --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/repository/condition/AdminTableSearchType.java @@ -0,0 +1,22 @@ +package band.gosrock.domain.domains.order.repository.condition; + +import static band.gosrock.domain.domains.user.domain.QUser.user; + +import com.querydsl.core.types.dsl.BooleanExpression; +import java.util.function.Function; + +/** 어드민 테이블의 검색어 지정 ( 전화번호 이름 검색 ) 을 지원하기 위함. */ +public enum AdminTableSearchType { + PHONE(user.profile.phoneNumber::contains), + NAME(user.profile.name::contains); + + private final Function expression; + + AdminTableSearchType(Function expression) { + this.expression = expression; + } + + public BooleanExpression getContains(String keyWord) { + return expression.apply(keyWord); + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/repository/condition/FindEventOrdersCondition.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/repository/condition/FindEventOrdersCondition.java new file mode 100644 index 00000000..456a56ea --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/order/repository/condition/FindEventOrdersCondition.java @@ -0,0 +1,38 @@ +package band.gosrock.domain.domains.order.repository.condition; + + +import com.querydsl.core.types.dsl.BooleanExpression; +import lombok.Builder; +import lombok.Getter; + +@Getter +public class FindEventOrdersCondition { + private final Long eventId; + // + private final String searchString; + + private final AdminTableSearchType searchType; + + private final AdminTableOrderFilterType filterType; + + @Builder + public FindEventOrdersCondition( + Long eventId, + String searchString, + AdminTableSearchType searchType, + AdminTableOrderFilterType filterType) { + this.eventId = eventId; + this.searchString = searchString; + this.searchType = searchType; + this.filterType = filterType; + } + + public BooleanExpression getOrderStatusFilter() { + return filterType.getFilter(); + } + + public BooleanExpression getSearchStringFilter() { + if (searchType == null) return null; + return searchType.getContains(searchString); + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/adaptor/OptionGroupAdaptor.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/adaptor/OptionGroupAdaptor.java index 490294e3..c1b1dd23 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/adaptor/OptionGroupAdaptor.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/adaptor/OptionGroupAdaptor.java @@ -6,6 +6,7 @@ import band.gosrock.domain.domains.ticket_item.domain.OptionGroupStatus; import band.gosrock.domain.domains.ticket_item.exception.OptionGroupNotFoundException; import band.gosrock.domain.domains.ticket_item.repository.OptionGroupRepository; +import java.util.List; import lombok.RequiredArgsConstructor; @Adaptor @@ -20,6 +21,11 @@ public OptionGroup queryOptionGroup(Long optionGroupId) { .orElseThrow(() -> OptionGroupNotFoundException.EXCEPTION); } + public List findAllByEventId(Long eventId) { + return optionGroupRepository.findAllByEvent_IdAndOptionGroupStatus( + eventId, OptionGroupStatus.VALID); + } + public OptionGroup save(OptionGroup optionGroup) { return optionGroupRepository.save(optionGroup); } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/adaptor/TicketItemAdaptor.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/adaptor/TicketItemAdaptor.java index 23873339..1fe71a13 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/adaptor/TicketItemAdaptor.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/adaptor/TicketItemAdaptor.java @@ -26,6 +26,10 @@ public List findAllByEventId(Long eventId) { eventId, TicketItemStatus.VALID); } + public Boolean existsByEventId(Long eventId) { + return ticketItemRepository.existsByEvent_Id(eventId); + } + public TicketItem save(TicketItem ticketItem) { return ticketItemRepository.save(ticketItem); } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/domain/OptionGroup.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/domain/OptionGroup.java index c5735834..db31fd32 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/domain/OptionGroup.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/domain/OptionGroup.java @@ -7,6 +7,7 @@ import band.gosrock.domain.common.vo.Money; import band.gosrock.domain.domains.event.domain.Event; +import band.gosrock.domain.domains.ticket_item.exception.ForbiddenOptionGroupDeleteException; import band.gosrock.domain.domains.ticket_item.exception.InvalidOptionGroupException; import java.util.ArrayList; import java.util.List; @@ -70,12 +71,18 @@ public OptionGroup( options.forEach(option -> option.setOptionGroup(this)); } - public void checkEventId(Long eventId) { + public void validateEventId(Long eventId) { if (!this.getEvent().getId().equals(eventId)) { throw InvalidOptionGroupException.EXCEPTION; } } + public Boolean hasApplication(List ticketItems) { + return ticketItems.stream() + .map(ticketItem -> ticketItem.hasItemOptionGroup(this.id)) + .reduce(Boolean.FALSE, Boolean::logicalOr); + } + public OptionGroup createTicketOption(Money additionalPrice) { OptionGroupType type = this.getType(); if (type == TRUE_FALSE) { @@ -86,4 +93,12 @@ public OptionGroup createTicketOption(Money additionalPrice) { } return this; } + + public void softDeleteOptionGroup(List ticketItems) { + // 적용된 옵션은 삭제 불가 + if (this.hasApplication(ticketItems)) { + throw ForbiddenOptionGroupDeleteException.EXCEPTION; + } + this.optionGroupStatus = OptionGroupStatus.DELETED; + } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/domain/TicketItem.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/domain/TicketItem.java index 747e2167..c2e3dc48 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/domain/TicketItem.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/domain/TicketItem.java @@ -118,20 +118,28 @@ public Boolean hasItemOptionGroup(Long optionGroupId) { itemOptionGroup.getOptionGroup().getId().equals(optionGroupId)); } - public void checkEventId(Long eventId) { + public void softDeleteTicketItem() { + // 재고 감소된 티켓상품은 삭제 불가 + if (this.isQuantityReduced()) { + throw ForbiddenTicketItemDeleteException.EXCEPTION; + } + this.ticketItemStatus = TicketItemStatus.DELETED; + } + + public void validateEventId(Long eventId) { if (!this.getEvent().getId().equals(eventId)) { throw InvalidTicketItemException.EXCEPTION; } } - public void checkTicketPrice() { + public void validateTicketPrice() { if (!Money.ZERO.equals(this.price)) { throw InvalidTicketPriceException.EXCEPTION; } } public RefundInfoVo getRefundInfoVo() { - return event.getRefundInfoVo(); + return event.toRefundInfoVo(); } /** 선착순 결제인지 확인하는 메서드 */ diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/exception/ForbiddenOptionGroupDeleteException.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/exception/ForbiddenOptionGroupDeleteException.java new file mode 100644 index 00000000..bab853a1 --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/exception/ForbiddenOptionGroupDeleteException.java @@ -0,0 +1,13 @@ +package band.gosrock.domain.domains.ticket_item.exception; + + +import band.gosrock.common.exception.DuDoongCodeException; + +public class ForbiddenOptionGroupDeleteException extends DuDoongCodeException { + + public static final DuDoongCodeException EXCEPTION = new ForbiddenOptionGroupDeleteException(); + + private ForbiddenOptionGroupDeleteException() { + super(TicketItemErrorCode.FORBIDDEN_OPTION_GROUP_DELETE); + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/exception/ForbiddenTicketItemDeleteException.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/exception/ForbiddenTicketItemDeleteException.java new file mode 100644 index 00000000..dbc3367d --- /dev/null +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/exception/ForbiddenTicketItemDeleteException.java @@ -0,0 +1,13 @@ +package band.gosrock.domain.domains.ticket_item.exception; + + +import band.gosrock.common.exception.DuDoongCodeException; + +public class ForbiddenTicketItemDeleteException extends DuDoongCodeException { + + public static final DuDoongCodeException EXCEPTION = new ForbiddenTicketItemDeleteException(); + + private ForbiddenTicketItemDeleteException() { + super(TicketItemErrorCode.FORBIDDEN_TICKET_ITEM_DELETE); + } +} diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/exception/TicketItemErrorCode.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/exception/TicketItemErrorCode.java index bfe2c4e2..055d1129 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/exception/TicketItemErrorCode.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/exception/TicketItemErrorCode.java @@ -38,8 +38,13 @@ public enum TicketItemErrorCode implements BaseErrorCode { OPTION_ANSWER_NOT_CORRECT( BAD_REQUEST, "Option_400_1", "옵션에 대한 답변이 올바르지 않습니다. T/F형일 경우 예 아니요 로 보내주세요."), TICKET_ITEM_PURCHASE_LIMIT(BAD_REQUEST, "Ticket_Item_400_6", "해당 티켓상품 최대 구매 가능 갯수를 넘었습니다."), + @ExplainError("이미 재고가 감소되어 옵션 변경이 불가능할 경우 발생하는 오류입니다.") + FORBIDDEN_OPTION_CHANGE(BAD_REQUEST, "Item_Option_Group_400_2", "옵션 변경이 불가능한 상태입니다."), + @ExplainError("이미 재고가 감소되어 티켓상품 삭제가 불가능할 경우 발생하는 오류입니다.") + FORBIDDEN_TICKET_ITEM_DELETE(BAD_REQUEST, "Ticket_Item_400_7", "티켓상품 삭제가 불가능한 상태입니다."), + @ExplainError("이미 적용되어 옵션그룹 삭제가 불가능할 경우 발생하는 오류입니다.") + FORBIDDEN_OPTION_GROUP_DELETE(BAD_REQUEST, "Option_Group_400_2", "옵션그룹 삭제가 불가능한 상태입니다."); - FORBIDDEN_OPTION_CHANGE(BAD_REQUEST, "Item_Option_Group_400_2", "옵션 변경이 불가능한 상태입니다."); private Integer status; private String code; private String reason; diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/repository/OptionGroupRepository.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/repository/OptionGroupRepository.java index 70f8d0f8..3d131885 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/repository/OptionGroupRepository.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/repository/OptionGroupRepository.java @@ -3,6 +3,7 @@ import band.gosrock.domain.domains.ticket_item.domain.OptionGroup; import band.gosrock.domain.domains.ticket_item.domain.OptionGroupStatus; +import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; @@ -10,4 +11,6 @@ public interface OptionGroupRepository extends JpaRepository Optional findByIdAndOptionGroupStatus( Long optionGroupId, OptionGroupStatus status); + + List findAllByEvent_IdAndOptionGroupStatus(Long eventId, OptionGroupStatus status); } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/repository/TicketItemRepository.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/repository/TicketItemRepository.java index 1644824d..4d072dba 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/repository/TicketItemRepository.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/repository/TicketItemRepository.java @@ -11,5 +11,7 @@ public interface TicketItemRepository extends JpaRepository { List findAllByEvent_IdAndTicketItemStatus(Long eventId, TicketItemStatus status); + Boolean existsByEvent_Id(Long eventId); + Optional findByIdAndTicketItemStatus(Long ticketItemId, TicketItemStatus status); } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/service/ItemOptionGroupService.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/service/ItemOptionGroupService.java index e08f9a1e..e5c3c39d 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/service/ItemOptionGroupService.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/service/ItemOptionGroupService.java @@ -3,7 +3,6 @@ import band.gosrock.common.annotation.DomainService; import band.gosrock.domain.common.aop.redissonLock.RedissonLock; -import band.gosrock.domain.domains.ticket_item.adaptor.OptionAdaptor; import band.gosrock.domain.domains.ticket_item.adaptor.OptionGroupAdaptor; import band.gosrock.domain.domains.ticket_item.adaptor.TicketItemAdaptor; import band.gosrock.domain.domains.ticket_item.domain.OptionGroup; @@ -18,11 +17,10 @@ public class ItemOptionGroupService { private final TicketItemAdaptor ticketItemAdaptor; - private final OptionAdaptor optionAdaptor; private final OptionGroupAdaptor optionGroupAdaptor; private final TicketItemRepository ticketItemRepository; - @RedissonLock(LockName = "티켓재고관리", identifier = "ticketItemId") + @RedissonLock(LockName = "티켓관리", identifier = "ticketItemId") @Transactional public TicketItem addItemOptionGroup(Long ticketItemId, Long optionGroupId, Long eventId) { @@ -30,8 +28,8 @@ public TicketItem addItemOptionGroup(Long ticketItemId, Long optionGroupId, Long OptionGroup optionGroup = optionGroupAdaptor.queryOptionGroup(optionGroupId); // 해당 eventId에 속해 있는 티켓 아이템, 옵션그룹이 맞는지 확인 - ticketItem.checkEventId(eventId); - optionGroup.checkEventId(eventId); + ticketItem.validateEventId(eventId); + optionGroup.validateEventId(eventId); ticketItem.addItemOptionGroup(optionGroup); return ticketItemRepository.save(ticketItem); 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 86efdbe8..fdabd704 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 @@ -2,6 +2,7 @@ import band.gosrock.common.annotation.DomainService; +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 lombok.RequiredArgsConstructor; @@ -17,8 +18,19 @@ public class TicketItemService { @Transactional public TicketItem createTicketItem(TicketItem ticketItem, Boolean isPartner) { if (!isPartner) { - ticketItem.checkTicketPrice(); + ticketItem.validateTicketPrice(); } return ticketItemAdaptor.save(ticketItem); } + + @RedissonLock(LockName = "티켓관리", identifier = "ticketItemId") + public void softDeleteTicketItem(Long eventId, Long ticketItemId) { + + TicketItem ticketItem = ticketItemAdaptor.queryTicketItem(ticketItemId); + // 해당 eventId에 속해 있는 티켓 아이템이 맞는지 확인 + ticketItem.validateEventId(eventId); + + ticketItem.softDeleteTicketItem(); + ticketItemAdaptor.save(ticketItem); + } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/service/TicketOptionService.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/service/TicketOptionService.java index 852e6717..cdcb9b93 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/service/TicketOptionService.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/ticket_item/service/TicketOptionService.java @@ -3,7 +3,10 @@ import band.gosrock.common.annotation.DomainService; import band.gosrock.domain.domains.ticket_item.adaptor.OptionGroupAdaptor; +import band.gosrock.domain.domains.ticket_item.adaptor.TicketItemAdaptor; import band.gosrock.domain.domains.ticket_item.domain.OptionGroup; +import band.gosrock.domain.domains.ticket_item.domain.TicketItem; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.transaction.annotation.Transactional; @@ -13,9 +16,22 @@ public class TicketOptionService { private final OptionGroupAdaptor optionGroupAdaptor; + private final TicketItemAdaptor ticketItemAdaptor; @Transactional public OptionGroup createTicketOption(OptionGroup optionGroup) { return optionGroupAdaptor.save(optionGroup); } + + @Transactional + public void softDeleteOptionGroup(Long eventId, Long optionGroupId) { + + OptionGroup optionGroup = optionGroupAdaptor.queryOptionGroup(optionGroupId); + // 해당 eventId에 속해 있는 옵션그룹이 맞는지 확인 + optionGroup.validateEventId(eventId); + + List ticketItems = ticketItemAdaptor.findAllByEventId(eventId); + optionGroup.softDeleteOptionGroup(ticketItems); + optionGroupAdaptor.save(optionGroup); + } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/user/domain/Profile.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/user/domain/Profile.java index 86e6549b..67519950 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/user/domain/Profile.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/user/domain/Profile.java @@ -1,7 +1,9 @@ package band.gosrock.domain.domains.user.domain; +import band.gosrock.domain.common.vo.ImageVo; import javax.persistence.Embeddable; +import javax.persistence.Embedded; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -15,14 +17,13 @@ public class Profile { private String email; private String phoneNumber; - - private String profileImage; + @Embedded private ImageVo profileImage; @Builder public Profile(String name, String email, String phoneNumber, String profileImage) { this.name = name; this.email = email; this.phoneNumber = phoneNumber; - this.profileImage = profileImage; + this.profileImage = ImageVo.valueOf(profileImage); } } diff --git a/DuDoong-Domain/src/test/java/band/gosrock/domain/domains/cart/domain/CartValidatorTest.java b/DuDoong-Domain/src/test/java/band/gosrock/domain/domains/cart/domain/CartValidatorTest.java index 0485986a..a38c79e1 100644 --- a/DuDoong-Domain/src/test/java/band/gosrock/domain/domains/cart/domain/CartValidatorTest.java +++ b/DuDoong-Domain/src/test/java/band/gosrock/domain/domains/cart/domain/CartValidatorTest.java @@ -10,7 +10,7 @@ import band.gosrock.domain.domains.cart.exception.CartItemNotOneTypeException; import band.gosrock.domain.domains.cart.exception.CartNotAnswerAllOptionGroupException; import band.gosrock.domain.domains.event.domain.Event; -import band.gosrock.domain.domains.event.exception.EventIsNotOpenStatusException; +import band.gosrock.domain.domains.event.exception.EventNotOpenException; import band.gosrock.domain.domains.event.exception.EventTicketingTimeIsPassedException; import band.gosrock.domain.domains.ticket_item.adaptor.OptionAdaptor; import band.gosrock.domain.domains.ticket_item.adaptor.TicketItemAdaptor; @@ -52,7 +52,7 @@ void setUp() { public void 카트_티켓팅_가능시간검증_실패() { // given given(event.isTimeBeforeStartAt()).willReturn(Boolean.FALSE); - willCallRealMethod().given(event).validTicketingTime(); + willCallRealMethod().given(event).validateTicketingTime(); // when // then assertThrows( @@ -64,7 +64,7 @@ void setUp() { public void 카트_티켓팅_가능시간검증_성공() { // given given(event.isTimeBeforeStartAt()).willReturn(Boolean.TRUE); - willCallRealMethod().given(event).validTicketingTime(); + willCallRealMethod().given(event).validateTicketingTime(); // when cartValidator.validTicketingTime(event); // then @@ -93,7 +93,7 @@ void setUp() { @Test public void 카트_티켓팅_이벤트_상태검증_성공() { // given - willDoNothing().given(event).validStatusOpen(); + willDoNothing().given(event).validateStatusOpen(); // when cartValidator.validEventIsOpen(event); // then @@ -102,11 +102,10 @@ void setUp() { @Test public void 카트_티켓팅_이벤트_상태검증_실패() { // given - willThrow(EventIsNotOpenStatusException.class).given(event).validStatusOpen(); + willThrow(EventNotOpenException.class).given(event).validateStatusOpen(); // when // then - assertThrows( - EventIsNotOpenStatusException.class, () -> cartValidator.validEventIsOpen(event)); + assertThrows(EventNotOpenException.class, () -> cartValidator.validEventIsOpen(event)); } @Test diff --git a/DuDoong-Domain/src/test/java/band/gosrock/domain/domains/order/domain/validator/OrderValidatorTest.java b/DuDoong-Domain/src/test/java/band/gosrock/domain/domains/order/domain/validator/OrderValidatorTest.java index 4e8281c5..eee81809 100644 --- a/DuDoong-Domain/src/test/java/band/gosrock/domain/domains/order/domain/validator/OrderValidatorTest.java +++ b/DuDoong-Domain/src/test/java/band/gosrock/domain/domains/order/domain/validator/OrderValidatorTest.java @@ -10,7 +10,7 @@ import band.gosrock.domain.common.vo.Money; import band.gosrock.domain.domains.event.adaptor.EventAdaptor; import band.gosrock.domain.domains.event.domain.Event; -import band.gosrock.domain.domains.event.exception.EventIsNotOpenStatusException; +import band.gosrock.domain.domains.event.exception.EventNotOpenException; import band.gosrock.domain.domains.event.exception.EventTicketingTimeIsPassedException; import band.gosrock.domain.domains.order.domain.Order; import band.gosrock.domain.domains.order.domain.OrderLineItem; @@ -338,7 +338,7 @@ void setUp() { public void 주문_티켓팅_가능시간검증_실패() { // given given(event.isTimeBeforeStartAt()).willReturn(Boolean.FALSE); - willCallRealMethod().given(event).validTicketingTime(); + willCallRealMethod().given(event).validateTicketingTime(); // when // then assertThrows( @@ -350,7 +350,7 @@ void setUp() { public void 주문_티켓팅_가능시간검증_성공() { // given given(event.isTimeBeforeStartAt()).willReturn(Boolean.TRUE); - willCallRealMethod().given(event).validTicketingTime(); + willCallRealMethod().given(event).validateTicketingTime(); // when orderValidator.validTicketingTime(event); // then @@ -379,7 +379,7 @@ void setUp() { @Test public void 주문_티켓팅_이벤트_상태검증_성공() { // given - willDoNothing().given(event).validStatusOpen(); + willDoNothing().given(event).validateStatusOpen(); // when orderValidator.validEventIsOpen(event); // then @@ -388,11 +388,10 @@ void setUp() { @Test public void 주문_티켓팅_이벤트_상태검증_실패() { // given - willThrow(EventIsNotOpenStatusException.class).given(event).validStatusOpen(); + willThrow(EventNotOpenException.class).given(event).validateStatusOpen(); // when // then - assertThrows( - EventIsNotOpenStatusException.class, () -> orderValidator.validEventIsOpen(event)); + assertThrows(EventNotOpenException.class, () -> orderValidator.validEventIsOpen(event)); } @Test diff --git a/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/s3/ImageFileExtension.java b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/s3/ImageFileExtension.java new file mode 100644 index 00000000..db51a6e1 --- /dev/null +++ b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/s3/ImageFileExtension.java @@ -0,0 +1,17 @@ +package band.gosrock.infrastructure.config.s3; + + +import lombok.Getter; + +@Getter +public enum ImageFileExtension { + JPEG("jpeg"), + JPG("jpeg"), + PNG("png"); + + ImageFileExtension(String uploadExtension) { + this.uploadExtension = uploadExtension; + } + + private final String uploadExtension; +} diff --git a/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/s3/ImageUrlDto.java b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/s3/ImageUrlDto.java new file mode 100644 index 00000000..b8efa25c --- /dev/null +++ b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/s3/ImageUrlDto.java @@ -0,0 +1,18 @@ +package band.gosrock.infrastructure.config.s3; + + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class ImageUrlDto { + + private final String url; + private final String key; + private final String baseUrl; + + public static ImageUrlDto of(String url, String key) { + return ImageUrlDto.builder().key(key).url(url).build(); + } +} diff --git a/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/s3/S3UploadPresignedUrlService.java b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/s3/S3UploadPresignedUrlService.java index f154a915..3ea76a3c 100644 --- a/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/s3/S3UploadPresignedUrlService.java +++ b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/s3/S3UploadPresignedUrlService.java @@ -28,23 +28,64 @@ public class S3UploadPresignedUrlService { @Value("${aws.s3.base-url}") private String baseUrl; - public String execute(Long userId, String fileExtension) { - validFileExtension(fileExtension); - String fixedFileExtension = changeJpgToJpeg(fileExtension); - String fileName = - baseUrl - + "/" - + "u" - + userId.toString() - + "/" - + UUID.randomUUID() - + "." - + fileExtension; + public ImageUrlDto forUser(Long userId, ImageFileExtension fileExtension) { + String fixedFileExtension = fileExtension.getUploadExtension(); + String fileName = getForUserFileName(userId, fixedFileExtension); log.info(fileName); - GeneratePresignedUrlRequest generatePresignedUrlRequest = - getGeneratePreSignedUrlRequest(bucket, fileName, fixedFileExtension); - URL url = amazonS3.generatePresignedUrl(generatePresignedUrlRequest); - return url.toString(); + URL url = + amazonS3.generatePresignedUrl( + getGeneratePreSignedUrlRequest(bucket, fileName, fixedFileExtension)); + return ImageUrlDto.of(url.toString(), fileName); + } + + public ImageUrlDto forHost(Long hostId, ImageFileExtension fileExtension) { + String fixedFileExtension = fileExtension.getUploadExtension(); + String fileName = getForHostFileName(hostId, fixedFileExtension); + log.info(fileName); + URL url = + amazonS3.generatePresignedUrl( + getGeneratePreSignedUrlRequest(bucket, fileName, fixedFileExtension)); + return ImageUrlDto.of(url.toString(), fileName); + } + + public ImageUrlDto forEvent(Long eventId, ImageFileExtension fileExtension) { + String fixedFileExtension = fileExtension.getUploadExtension(); + String fileName = getForEventFileName(eventId, fixedFileExtension); + log.info(fileName); + URL url = + amazonS3.generatePresignedUrl( + getGeneratePreSignedUrlRequest(bucket, fileName, fixedFileExtension)); + return ImageUrlDto.of(url.toString(), fileName); + } + + private String getForUserFileName(Long userId, String fileExtension) { + return baseUrl + + "/user/" + + userId.toString() + + "/" + + UUID.randomUUID() + + "." + + fileExtension; + } + + private String getForHostFileName(Long hostId, String fileExtension) { + return baseUrl + + "/host/" + + hostId.toString() + + "/" + + UUID.randomUUID() + + "." + + fileExtension; + } + + private String getForEventFileName(Long eventId, String fileExtension) { + return baseUrl + + "/event/" + + eventId.toString() + + "/" + + UUID.randomUUID() + + "." + + fileExtension; } private String changeJpgToJpeg(String fileExtension) { @@ -78,8 +119,8 @@ private GeneratePresignedUrlRequest getGeneratePreSignedUrlRequest( private Date getPreSignedUrlExpiration() { Date expiration = new Date(); long expTimeMillis = expiration.getTime(); - // 한시간 - expTimeMillis += 1000 * 60 * 60; + // 3분 + expTimeMillis += 1000 * 60 * 3; expiration.setTime(expTimeMillis); return expiration; } diff --git a/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/slack/SlackApiConfig.java b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/slack/SlackApiConfig.java new file mode 100644 index 00000000..4577e415 --- /dev/null +++ b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/slack/SlackApiConfig.java @@ -0,0 +1,21 @@ +package band.gosrock.infrastructure.config.slack; + + +import com.slack.api.Slack; +import com.slack.api.methods.MethodsClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SlackApiConfig { + + @Value("${slack.webhook.token}") + private String token; + + @Bean + public MethodsClient getClient() { + Slack slackClient = Slack.getInstance(); + return slackClient.methods(token); + } +} diff --git a/DuDoong-Infrastructure/src/main/resources/application-infrastructure.yml b/DuDoong-Infrastructure/src/main/resources/application-infrastructure.yml index dfee52b6..ec55a884 100644 --- a/DuDoong-Infrastructure/src/main/resources/application-infrastructure.yml +++ b/DuDoong-Infrastructure/src/main/resources/application-infrastructure.yml @@ -12,6 +12,9 @@ spring: port: ${REDIS_PORT:6379} password: ${REDIS_PASSWORD:} +slack: + webhook: + token: ${SLACK_WEBHOOK_TOKEN:} --- spring: config: