-
Notifications
You must be signed in to change notification settings - Fork 2
feat: admin 행사+티켓 등록 API - #117 #122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a3a36c9
c13fa9e
782313f
3b48f22
6ba9486
b699dd9
c0e0366
e709e17
230e8f0
00ec65c
bce43eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,32 +1,42 @@ | ||
| package com.permitseoul.permitserver.domain.admin.event.api.controller; | ||
|
|
||
| import com.permitseoul.permitserver.domain.admin.event.api.dto.req.AdminEventWithTicketCreateRequest; | ||
| import com.permitseoul.permitserver.domain.admin.event.api.service.AdminEventService; | ||
| import com.permitseoul.permitserver.global.response.ApiResponseUtil; | ||
| import com.permitseoul.permitserver.global.response.BaseResponse; | ||
| import com.permitseoul.permitserver.global.response.code.SuccessCode; | ||
| import jakarta.validation.Valid; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.http.ResponseEntity; | ||
| 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; | ||
| import org.springframework.web.bind.annotation.*; | ||
|
|
||
| @RestController | ||
| @RequestMapping("/api/admin/events") | ||
| @RequiredArgsConstructor | ||
| public class AdminEventController { | ||
| private final AdminEventService adminEventService; | ||
|
|
||
| //어드민 행사 리스트 조회 API | ||
| @GetMapping | ||
| public ResponseEntity<BaseResponse<?>> getEvents( | ||
| ) { | ||
| return ApiResponseUtil.success(SuccessCode.OK, adminEventService.getEvents()); | ||
| } | ||
|
|
||
| //어드민 행사 리스트 조회 API | ||
| @GetMapping("/{eventId}/details") | ||
| public ResponseEntity<BaseResponse<?>> getEventDetail( | ||
| @PathVariable(value = "eventId") long eventId | ||
| ) { | ||
| return ApiResponseUtil.success(SuccessCode.OK, adminEventService.getEventDetail(eventId)); | ||
| } | ||
|
|
||
| //어드민 행사+티켓 등록 API | ||
| @PostMapping | ||
| public ResponseEntity<BaseResponse<?>> createEvent( | ||
| @RequestBody @Valid final AdminEventWithTicketCreateRequest adminEventWithTicketCreateRequest | ||
| ) { | ||
| adminEventService.createEventWithTickets(adminEventWithTicketCreateRequest); | ||
| return ApiResponseUtil.success(SuccessCode.OK); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,125 @@ | ||||||||||||||||||||||||
| package com.permitseoul.permitserver.domain.admin.event.api.dto.req; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| import com.fasterxml.jackson.annotation.JsonFormat; | ||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.event.core.domain.EventType; | ||||||||||||||||||||||||
| import jakarta.validation.Valid; | ||||||||||||||||||||||||
| import jakarta.validation.constraints.*; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| import java.math.BigDecimal; | ||||||||||||||||||||||||
| import java.time.LocalDate; | ||||||||||||||||||||||||
| import java.time.LocalTime; | ||||||||||||||||||||||||
| import java.util.List; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| public record AdminEventWithTicketCreateRequest( | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotNull(message = "행사 노출 시작일은 필수입니다.") | ||||||||||||||||||||||||
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") | ||||||||||||||||||||||||
| LocalDate eventExposureStartDate, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotNull(message = "행사 노출 시작 시간은 필수입니다.") | ||||||||||||||||||||||||
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") | ||||||||||||||||||||||||
| LocalTime eventExposureStartTime, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotNull(message = "행사 노출 종료일은 필수입니다.") | ||||||||||||||||||||||||
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") | ||||||||||||||||||||||||
| LocalDate eventExposureEndDate, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotNull(message = "행사 노출 종료 시간은 필수입니다.") | ||||||||||||||||||||||||
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") | ||||||||||||||||||||||||
| LocalTime eventExposureEndTime, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotBlank(message = "검증 코드는 필수입니다.") | ||||||||||||||||||||||||
| @Size(max = 30, message = "검증 코드는 30자를 초과할 수 없습니다.") | ||||||||||||||||||||||||
| String verificationCode, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotBlank(message = "행사명은 필수입니다.") | ||||||||||||||||||||||||
| String name, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotNull(message = "행사 타입은 필수입니다.") | ||||||||||||||||||||||||
| EventType eventType, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotNull(message = "행사 시작일은 필수입니다.") | ||||||||||||||||||||||||
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") | ||||||||||||||||||||||||
| LocalDate startDate, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotNull(message = "행사 시작 시간은 필수입니다.") | ||||||||||||||||||||||||
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") | ||||||||||||||||||||||||
| LocalTime startTime, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotNull(message = "행사 종료일은 필수입니다.") | ||||||||||||||||||||||||
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") | ||||||||||||||||||||||||
| LocalDate endDate, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotNull(message = "행사 종료 시간은 필수입니다.") | ||||||||||||||||||||||||
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") | ||||||||||||||||||||||||
| LocalTime endTime, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotBlank(message = "행사 장소는 필수입니다.") | ||||||||||||||||||||||||
| String venue, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| String lineup, | ||||||||||||||||||||||||
| String details, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @Valid | ||||||||||||||||||||||||
| @NotEmpty(message = "행사 이미지는 최소 1개 이상이어야 합니다.") | ||||||||||||||||||||||||
| List<AdminEventImageInfo> images, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||
| @Min(value = 0, message = "최소 나이는 0 이상이어야 합니다.") | ||||||||||||||||||||||||
| int minAge, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotBlank(message = "티켓 차수 이름은 필수입니다.") | ||||||||||||||||||||||||
| String ticketRoundName, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotNull(message = "티켓 차수 시작일은 필수입니다.") | ||||||||||||||||||||||||
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") | ||||||||||||||||||||||||
| LocalDate roundSalesStartDate, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotNull(message = "티켓 차수 시작 시간은 필수입니다.") | ||||||||||||||||||||||||
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") | ||||||||||||||||||||||||
| LocalTime roundSalesStartTime, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotNull(message = "티켓 차수 종료일은 필수입니다.") | ||||||||||||||||||||||||
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") | ||||||||||||||||||||||||
| LocalDate roundSalesEndDate, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotNull(message = "티켓 차수 종료 시간은 필수입니다.") | ||||||||||||||||||||||||
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") | ||||||||||||||||||||||||
| LocalTime roundSalesEndTime, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotEmpty(message = "티켓 정보는 최소 1개 이상이어야 합니다.") | ||||||||||||||||||||||||
| @Valid | ||||||||||||||||||||||||
| List<TicketTypeRequest> ticketTypes | ||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||
| public record TicketTypeRequest( | ||||||||||||||||||||||||
| @NotBlank(message = "티켓 이름은 필수입니다.") | ||||||||||||||||||||||||
| String ticketName, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @Min(value = 1, message = "가격은 0원보다 커야합니다.") | ||||||||||||||||||||||||
| @NotNull(message = "가격은 필수입니다.") | ||||||||||||||||||||||||
| BigDecimal price, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @Min(value = 1, message = "티켓 개수는 1 이상이어야 합니다.") | ||||||||||||||||||||||||
| int ticketCount, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
Comment on lines
+98
to
+103
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 가격 음수 및 스케일 제약 부재 — 최소 검증 추가 권장 가격(BigDecimal)에 음수 입력이 허용되고 소수 자릿수 제약이 없습니다. 최소한 0 이상 제약은 필수로 보입니다. 적용 예: - @NotNull(message = "가격은 필수입니다.")
- BigDecimal price,
+ @NotNull(message = "가격은 필수입니다.")
+ @DecimalMin(value = "0", inclusive = true, message = "가격은 0 이상이어야 합니다.")
+ BigDecimal price,(정책상 원 단위만 허용한다면 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||
| @NotNull(message = "티켓 시작일은 필수입니다.") | ||||||||||||||||||||||||
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") | ||||||||||||||||||||||||
| LocalDate ticketStartDate, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotNull(message = "티켓 시작 시간은 필수입니다.") | ||||||||||||||||||||||||
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") | ||||||||||||||||||||||||
| LocalTime ticketStartTime, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotNull(message = "티켓 종료일은 필수입니다.") | ||||||||||||||||||||||||
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") | ||||||||||||||||||||||||
| LocalDate ticketEndDate, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @NotNull(message = "티켓 종료 시간은 필수입니다.") | ||||||||||||||||||||||||
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") | ||||||||||||||||||||||||
| LocalTime ticketEndTime | ||||||||||||||||||||||||
| ) { } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| public record AdminEventImageInfo( | ||||||||||||||||||||||||
| @NotBlank(message = "이미지 url은 필수입니다.") | ||||||||||||||||||||||||
| String imageUrl | ||||||||||||||||||||||||
| ) { } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,26 +1,35 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package com.permitseoul.permitserver.domain.admin.event.api.service; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.admin.base.AdminBaseException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.admin.base.api.exception.AdminApiException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.admin.event.api.dto.req.AdminEventWithTicketCreateRequest; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.admin.event.api.dto.res.AdminEventDetailResponse; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.admin.event.api.dto.res.AdminEventListResponse; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.admin.event.core.component.AdminEventRetriever; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.admin.event.core.component.AdminEventSaver; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.admin.event.core.exception.AdminEventNotFoundException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.admin.eventimage.core.component.AdminEventImageRetriever; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.admin.eventimage.core.component.AdminEventImageSaver; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.admin.ticketround.core.AdminTicketRoundRetriever; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.admin.ticketround.core.AdminTicketRoundSaver; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.admin.tickettype.core.component.AdminTicketTypeRetriever; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.admin.tickettype.core.component.AdminTicketTypeSaver; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.event.core.domain.Event; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.eventimage.core.domain.EventImage; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.eventimage.core.domain.entity.EventImageEntity; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.ticketround.core.domain.TicketRound; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.tickettype.core.domain.TicketType; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.domain.tickettype.core.domain.entity.TicketTypeEntity; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.global.response.code.ErrorCode; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.permitseoul.permitserver.global.util.DateFormatterUtil; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import lombok.RequiredArgsConstructor; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.stereotype.Service; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.transaction.annotation.Transactional; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.time.LocalDate; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.time.LocalDateTime; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.time.LocalTime; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.*; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.stream.IntStream; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Service | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -31,6 +40,10 @@ public class AdminEventService { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final AdminTicketRoundRetriever adminTicketRoundRetriever; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final AdminTicketTypeRetriever adminTicketTypeRetriever; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final AdminEventImageRetriever adminEventImageRetriever; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final AdminEventSaver adminEventSaver; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final AdminEventImageSaver adminEventImageSaver; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final AdminTicketRoundSaver adminTicketRoundSaver; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final AdminTicketTypeSaver adminTicketTypeSaver; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Transactional(readOnly = true) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public List<AdminEventListResponse> getEvents() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -59,7 +72,7 @@ public AdminEventDetailResponse getEventDetail(final long eventId) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final List<EventImage> eventImages = adminEventImageRetriever.findAllEventImagesByEventId(event.getEventId()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final List<AdminEventDetailResponse.AdminEventImageInfo> adminEventImageInfos = eventImages.stream() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .sorted(Comparator.comparingInt(EventImage::getSequence)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .sorted(Comparator.comparingInt(EventImage::getSequence)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map(eventImage -> AdminEventDetailResponse.AdminEventImageInfo.of(eventImage.getImageUrl())) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .toList(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -87,6 +100,90 @@ public AdminEventDetailResponse getEventDetail(final long eventId) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Transactional | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void createEventWithTickets(final AdminEventWithTicketCreateRequest req) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final LocalDateTime eventStartDateTime = combineDateTime(req.startDate(), req.startTime()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final LocalDateTime eventEndDateTime = combineDateTime(req.endDate(), req.endTime()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final LocalDateTime eventExposureStartDateTime = combineDateTime(req.eventExposureStartDate(), req.eventExposureStartTime()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final LocalDateTime eventExposureEndDateTime = combineDateTime(req.eventExposureEndDate(), req.eventExposureEndTime()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final LocalDateTime ticketRoundSalesStartDateTime = combineDateTime(req.roundSalesStartDate(), req.roundSalesStartTime()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final LocalDateTime ticketRoundSalesEndDateTime = combineDateTime(req.roundSalesEndDate(), req.roundSalesEndTime()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final Event savedEvent = saveEvent(req, eventStartDateTime, eventEndDateTime, eventExposureStartDateTime, eventExposureEndDateTime); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| saveEventImages(savedEvent.getEventId(), req.images()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final TicketRound savedTicketRound = saveTicketRound( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| savedEvent.getEventId(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| req.ticketRoundName(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ticketRoundSalesStartDateTime, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ticketRoundSalesEndDateTime | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| saveTicketTypes(req.ticketTypes(), savedTicketRound.getTicketRoundId()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+103
to
+124
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 생성 플로우의 날짜·시간 일관성 검증 추가 역전(시작>종료), 노출/판매기간 유효성 등 최소 검증을 권장합니다. 잘못된 데이터가 그대로 저장될 수 있습니다. 예시(간단 검증): @@
- public void createEventWithTickets(final AdminEventWithTicketCreateRequest req) {
+ public void createEventWithTickets(final AdminEventWithTicketCreateRequest req) {
final LocalDateTime eventStartDateTime = combineDateTime(req.startDate(), req.startTime());
final LocalDateTime eventEndDateTime = combineDateTime(req.endDate(), req.endTime());
@@
final LocalDateTime ticketRoundSalesStartDateTime = combineDateTime(req.roundSalesStartDate(), req.roundSalesStartTime());
final LocalDateTime ticketRoundSalesEndDateTime = combineDateTime(req.roundSalesEndDate(), req.roundSalesEndTime());
+
+ if (eventStartDateTime.isAfter(eventEndDateTime)) {
+ throw new AdminApiException(ErrorCode.INVALID_DATE_RANGE);
+ }
+ if (eventExposureStartDateTime.isAfter(eventExposureEndDateTime)) {
+ throw new AdminApiException(ErrorCode.INVALID_DATE_RANGE);
+ }
+ if (ticketRoundSalesStartDateTime.isAfter(ticketRoundSalesEndDateTime)) {
+ throw new AdminApiException(ErrorCode.INVALID_DATE_RANGE);
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
Comment on lines
+115
to
+124
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion images/ticketTypes null 처리 및 빈 컬렉션 정책 확정 req.images()/ticketTypes()가 null이면 NPE. 또한 티켓 타입이 없을 때 라운드 생성 여부 정책이 필요합니다. - saveEventImages(savedEvent.getEventId(), req.images());
+ final var images = java.util.Optional.ofNullable(req.images()).orElseGet(java.util.List::of);
+ saveEventImages(savedEvent.getEventId(), images);
@@
- final TicketRound savedTicketRound = saveTicketRound(
- savedEvent.getEventId(),
- req.ticketRoundName(),
- ticketRoundSalesStartDateTime,
- ticketRoundSalesEndDateTime
- );
- saveTicketTypes(req.ticketTypes(), savedTicketRound.getTicketRoundId());
+ final var ticketTypes = java.util.Optional.ofNullable(req.ticketTypes()).orElseGet(java.util.List::of);
+ if (!ticketTypes.isEmpty()) {
+ final TicketRound savedTicketRound = saveTicketRound(
+ savedEvent.getEventId(),
+ req.ticketRoundName(),
+ ticketRoundSalesStartDateTime,
+ ticketRoundSalesEndDateTime
+ );
+ saveTicketTypes(ticketTypes, savedTicketRound.getTicketRoundId());
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private void saveEventImages(final long eventId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| List<AdminEventWithTicketCreateRequest.AdminEventImageInfo> eventImages) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final List<EventImageEntity> eventImageEntityList = IntStream.range(0, eventImages.size()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .mapToObj(i -> EventImageEntity.create( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| eventId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| eventImages.get(i).imageUrl().trim(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| i+1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )).toList(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| adminEventImageSaver.saveEventImages(eventImageEntityList); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private void saveTicketTypes(final List<AdminEventWithTicketCreateRequest.TicketTypeRequest> ticketTypes, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final long ticketRoundId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final List<TicketTypeEntity> ticketTypeEntityList = ticketTypes.stream() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map(ticketType -> TicketTypeEntity.create( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ticketRoundId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ticketType.ticketName(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ticketType.price(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ticketType.ticketCount(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| LocalDateTime.of(ticketType.ticketStartDate(), ticketType.ticketStartTime()), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| LocalDateTime.of(ticketType.ticketEndDate(), ticketType.ticketEndTime()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )).toList(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| adminTicketTypeSaver.saveAllTicketTypes(ticketTypeEntityList); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+137
to
+149
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 티켓 타입 입력값 검증(가격/수량/기간) 권장
간단 예시: - final List<TicketTypeEntity> ticketTypeEntityList = ticketTypes.stream()
+ final List<TicketTypeEntity> ticketTypeEntityList = ticketTypes.stream()
.map(ticketType -> TicketTypeEntity.create(
ticketRoundId,
ticketType.ticketName(),
ticketType.price(),
ticketType.ticketCount(),
LocalDateTime.of(ticketType.ticketStartDate(), ticketType.ticketStartTime()),
LocalDateTime.of(ticketType.ticketEndDate(), ticketType.ticketEndTime())
)).toList();위 맵핑 전, validate 함수로 조건 위반 시 AdminApiException을 던지도록 하는 방식을 권장합니다.
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private TicketRound saveTicketRound(final long eventId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final String ticketRoundName, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final LocalDateTime salesStartDateTime, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final LocalDateTime salesEndDateTime) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return adminTicketRoundSaver.saveTicketRound( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| eventId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ticketRoundName, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| salesStartDateTime, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| salesEndDateTime | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private Event saveEvent(final AdminEventWithTicketCreateRequest req, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final LocalDateTime eventStartDateTime, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final LocalDateTime eventEndDateTime, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final LocalDateTime eventExposureStartDateTime, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final LocalDateTime eventExposureEndDateTime) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return adminEventSaver.saveEvent( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| req.name(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| req.eventType(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| eventStartDateTime, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| eventEndDateTime, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| req.venue(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| req.lineup(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| req.details(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| req.minAge(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| eventExposureStartDateTime, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| eventExposureEndDateTime, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| req.verificationCode() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private LocalDateTime combineDateTime(final LocalDate date, final LocalTime time) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return LocalDateTime.of(date, time); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private Map<Long, Integer> initSoldTicketCountZero(final List<Event> events) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final Map<Long, Integer> map = new HashMap<>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (Event e : events) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -185,7 +282,7 @@ private Map<String, List<AdminEventListResponse.AdminEventInfo>> groupEventsByYe | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return grouped; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private boolean isEmpty(final Collection<?> c) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return c == null || c.isEmpty(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private boolean isEmpty(final List<?> list) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return list == null || list.isEmpty(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package com.permitseoul.permitserver.domain.admin.event.core.component; | ||
|
|
||
| import com.permitseoul.permitserver.domain.event.core.domain.Event; | ||
| import com.permitseoul.permitserver.domain.event.core.domain.EventType; | ||
| import com.permitseoul.permitserver.domain.event.core.domain.entity.EventEntity; | ||
| import com.permitseoul.permitserver.domain.event.core.repository.EventRepository; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Component; | ||
|
|
||
| import java.time.LocalDateTime; | ||
|
|
||
| @Component | ||
| @RequiredArgsConstructor | ||
| public class AdminEventSaver { | ||
| private final EventRepository eventRepository; | ||
|
|
||
| public Event saveEvent(final String name, | ||
| final EventType eventType, | ||
| final LocalDateTime startDate, | ||
| final LocalDateTime endDate, | ||
| final String venue, | ||
| final String lineUp, | ||
| final String details, | ||
| final int minAge, | ||
| final LocalDateTime visibleStartDate, | ||
| final LocalDateTime visibleEndDate, | ||
| final String ticketCheckCode) { | ||
| return Event.fromEntity( | ||
| eventRepository.save(EventEntity.create(name, eventType, startDate, endDate, venue, lineUp, details, minAge, visibleStartDate, visibleEndDate, ticketCheckCode)) | ||
| ); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
❓ Verification inconclusive
교차 필드(기간) 검증 없음 — 데이터 무결성 위험
노출/행사/라운드/티켓 기간 간 선후관계가 보장되지 않습니다. 운영 데이터 오류로 직결됩니다.
권장: 클래스 레벨 커스텀 Validator를 추가해 다음을 보장하세요.
예시(새 파일 추가):
DTO에 애노테이션 부착:
검증 존재 여부 확인 스크립트:
Also applies to: 41-56, 72-87, 102-117
🏁 Script executed:
Length of output: 0
추가 검증을 위해 ConstraintValidator 구현체 및 애노테이션 존재 여부를 검색합니다.
🏁 Script executed:
Length of output: 0
클래스 레벨 교차 필드 검증 추가 필요
현재
AdminEventWithTicketCreateRequest및 연관 DTO에 노출·행사·라운드·티켓 기간 간 선후관계를 보장하는 검증 로직이 없어 데이터 무결성에 위험이 있습니다. 다음을 구현하세요:@ValidAdminEventWithTicketCreate커스텀 애노테이션AdminEventWithTicketCreateRequestValidator implements ConstraintValidator<ValidAdminEventWithTicketCreate, AdminEventWithTicketCreateRequest>DTO 선언부 상단에 애노테이션을 추가합니다:
🤖 Prompt for AI Agents