diff --git a/.github/workflows/showpot-dev-ci.yml b/.github/workflows/showpot-dev-ci.yml index 1bde2023..8e77580d 100644 --- a/.github/workflows/showpot-dev-ci.yml +++ b/.github/workflows/showpot-dev-ci.yml @@ -4,6 +4,7 @@ on: pull_request: branches: - develop + - temp-develop jobs: build: diff --git a/app/api/common-api/src/main/java/org/example/dto/response/CursorApiResponse.java b/app/api/common-api/src/main/java/org/example/dto/response/CursorApiResponse.java new file mode 100644 index 00000000..ad9a17a4 --- /dev/null +++ b/app/api/common-api/src/main/java/org/example/dto/response/CursorApiResponse.java @@ -0,0 +1,22 @@ +package org.example.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.UUID; + +public record CursorApiResponse( + + @Schema(description = "조회한 데이터의 Cursor Id") + UUID id, + + @Schema(description = "조회한 데이터의 Cursor Value") + Object value +) { + public static CursorApiResponse toCursorResponse(UUID id, Object value) { + return new CursorApiResponse(id, value); + } + + public static CursorApiResponse toCursorId(UUID id) { + return new CursorApiResponse(id, ""); + } + +} diff --git a/app/api/common-api/src/main/java/org/example/util/ValidatorCursorSize.java b/app/api/common-api/src/main/java/org/example/util/ValidatorCursorSize.java new file mode 100644 index 00000000..aa6ff8ab --- /dev/null +++ b/app/api/common-api/src/main/java/org/example/util/ValidatorCursorSize.java @@ -0,0 +1,14 @@ +package org.example.util; + +public final class ValidatorCursorSize { + + private static final Integer DEFAULT_SIZE = 30; + + public static int getDefaultSize(Integer size) { + if (size == null) { + return DEFAULT_SIZE; + } + + return size; + } +} diff --git a/app/api/show-api/src/main/java/com/example/artist/controller/ArtistController.java b/app/api/show-api/src/main/java/com/example/artist/controller/ArtistController.java index 97749bc6..79d65bc6 100644 --- a/app/api/show-api/src/main/java/com/example/artist/controller/ArtistController.java +++ b/app/api/show-api/src/main/java/com/example/artist/controller/ArtistController.java @@ -12,6 +12,7 @@ import com.example.artist.controller.dto.response.ArtistFilterTotalCountApiResponse; import com.example.artist.controller.dto.response.ArtistSubscriptionApiResponse; import com.example.artist.controller.dto.response.ArtistUnsubscriptionApiResponse; +import com.example.artist.controller.dto.response.NumberOfSubscribedArtistApiResponse; import com.example.artist.service.ArtistService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -40,7 +41,7 @@ public class ArtistController { @Operation(summary = "구독하지 않은 아티스트 목록 조회") public ResponseEntity> getUnsubscribedArtists( @AuthenticationPrincipal AuthenticatedUser user, - @ParameterObject ArtistUnsubscriptionPaginationApiRequest request + @Valid @ParameterObject ArtistUnsubscriptionPaginationApiRequest request ) { var response = (user == null) @@ -67,7 +68,7 @@ public ResponseEntity> getSubscribedArtists( @AuthenticationPrincipal AuthenticatedUser user, - @ParameterObject ArtistSubscriptionPaginationApiRequest request + @Valid @ParameterObject ArtistSubscriptionPaginationApiRequest request ) { var response = artistService.findArtistSubscriptions( request.toServiceRequest(user.userId())); @@ -83,6 +84,18 @@ public ResponseEntity getNumberOfSubscribedArtist( + @AuthenticationPrincipal AuthenticatedUser user + ) { + return ResponseEntity.ok( + NumberOfSubscribedArtistApiResponse.from( + artistService.countSubscribedArtists(user.userId()) + ) + ); + } + @PostMapping("/subscribe") @Operation(summary = "구독하기") public ResponseEntity subscribe( @@ -113,7 +126,7 @@ public ResponseEntity unsubscribe( @Operation(summary = "검색하기") public ResponseEntity> search( @AuthenticationPrincipal AuthenticatedUser user, - @ParameterObject ArtistSearchPaginationApiRequest request + @Valid @ParameterObject ArtistSearchPaginationApiRequest request ) { var response = artistService.searchArtist(request.toServiceRequest(user)); var data = response.data().stream() diff --git a/app/api/show-api/src/main/java/com/example/artist/controller/dto/param/ArtistSearchPaginationApiParam.java b/app/api/show-api/src/main/java/com/example/artist/controller/dto/param/ArtistSearchPaginationApiParam.java index c7c1f26f..cf6b0178 100644 --- a/app/api/show-api/src/main/java/com/example/artist/controller/dto/param/ArtistSearchPaginationApiParam.java +++ b/app/api/show-api/src/main/java/com/example/artist/controller/dto/param/ArtistSearchPaginationApiParam.java @@ -2,11 +2,11 @@ import com.example.artist.service.dto.param.ArtistSearchPaginationServiceParam; import io.swagger.v3.oas.annotations.media.Schema; -import java.util.UUID; +import org.example.dto.response.CursorApiResponse; public record ArtistSearchPaginationApiParam( - @Schema(description = "아티스트 ID") - UUID id, + @Schema(description = "아티스트 Cursor") + CursorApiResponse cursor, @Schema(description = "아티스트 이미지 URL") String imageURL, @@ -23,7 +23,7 @@ public record ArtistSearchPaginationApiParam( public static ArtistSearchPaginationApiParam from(ArtistSearchPaginationServiceParam param) { return new ArtistSearchPaginationApiParam( - param.artistId(), + CursorApiResponse.toCursorId(param.artistId()), param.artistImageUrl(), param.artistKoreanName(), param.artistEnglishName(), diff --git a/app/api/show-api/src/main/java/com/example/artist/controller/dto/param/ArtistSubscriptionPaginationApiParam.java b/app/api/show-api/src/main/java/com/example/artist/controller/dto/param/ArtistSubscriptionPaginationApiParam.java index 348d90a8..10f339b0 100644 --- a/app/api/show-api/src/main/java/com/example/artist/controller/dto/param/ArtistSubscriptionPaginationApiParam.java +++ b/app/api/show-api/src/main/java/com/example/artist/controller/dto/param/ArtistSubscriptionPaginationApiParam.java @@ -2,11 +2,11 @@ import com.example.artist.service.dto.param.ArtistSubscriptionPaginationServiceParam; import io.swagger.v3.oas.annotations.media.Schema; -import java.util.UUID; +import org.example.dto.response.CursorApiResponse; public record ArtistSubscriptionPaginationApiParam( - @Schema(description = "아티스트 ID") - UUID id, + @Schema(description = "아티스트 Cursor") + CursorApiResponse cursor, @Schema(description = "아티스트 이미지 URL") String imageURL, @Schema(description = "아티스트 한글 이름") @@ -17,7 +17,7 @@ public record ArtistSubscriptionPaginationApiParam( public static ArtistSubscriptionPaginationApiParam from(ArtistSubscriptionPaginationServiceParam param) { return new ArtistSubscriptionPaginationApiParam( - param.artistId(), + CursorApiResponse.toCursorId(param.artistId()), param.artistImageUrl(), param.artistKoreanName(), param.artistEnglishName() diff --git a/app/api/show-api/src/main/java/com/example/artist/controller/dto/param/ArtistUnsubscriptionPaginationApiParam.java b/app/api/show-api/src/main/java/com/example/artist/controller/dto/param/ArtistUnsubscriptionPaginationApiParam.java index 84644e0d..e08fd2de 100644 --- a/app/api/show-api/src/main/java/com/example/artist/controller/dto/param/ArtistUnsubscriptionPaginationApiParam.java +++ b/app/api/show-api/src/main/java/com/example/artist/controller/dto/param/ArtistUnsubscriptionPaginationApiParam.java @@ -2,11 +2,11 @@ import com.example.artist.service.dto.param.ArtistUnsubscriptionPaginationServiceParam; import io.swagger.v3.oas.annotations.media.Schema; -import java.util.UUID; +import org.example.dto.response.CursorApiResponse; public record ArtistUnsubscriptionPaginationApiParam( - @Schema(description = "아티스트 ID") - UUID id, + @Schema(description = "아티스트 Cursor") + CursorApiResponse cursor, @Schema(description = "아티스트 이미지 URL") String imageURL, @Schema(description = "아티스트 한글 이름") @@ -19,7 +19,7 @@ public static ArtistUnsubscriptionPaginationApiParam from( ArtistUnsubscriptionPaginationServiceParam param ) { return new ArtistUnsubscriptionPaginationApiParam( - param.artistId(), + CursorApiResponse.toCursorId(param.artistId()), param.artistImageUrl(), param.artistKoreanName(), param.artistEnglishName() diff --git a/app/api/show-api/src/main/java/com/example/artist/controller/dto/request/ArtistSearchPaginationApiRequest.java b/app/api/show-api/src/main/java/com/example/artist/controller/dto/request/ArtistSearchPaginationApiRequest.java index c632dd20..4d3a898f 100644 --- a/app/api/show-api/src/main/java/com/example/artist/controller/dto/request/ArtistSearchPaginationApiRequest.java +++ b/app/api/show-api/src/main/java/com/example/artist/controller/dto/request/ArtistSearchPaginationApiRequest.java @@ -4,8 +4,10 @@ import com.example.artist.vo.ArtistSortApiType; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Max; import java.util.UUID; import org.example.security.dto.AuthenticatedUser; +import org.example.util.ValidatorCursorSize; public record ArtistSearchPaginationApiRequest( @@ -15,11 +17,12 @@ public record ArtistSearchPaginationApiRequest( ) ArtistSortApiType sortStandard, - @Parameter(description = "이전 페이지네이션 마지막 데이터의 ID / 최초 조회라면 null") - UUID cursor, + @Parameter(description = "이전 페이지네이션 마지막 데이터의 cursorId / 최초 조회라면 null") + UUID cursorId, @Parameter(description = "조회하는 데이터 개수", required = true) - int size, + @Max(value = 30, message = "조회하는 데이터 개수는 최대 30개 이어야 합니다.") + Integer size, @Parameter(description = "검색어", required = true) String search @@ -40,8 +43,8 @@ public ArtistSearchPaginationServiceRequest toServiceRequest(AuthenticatedUser u return ArtistSearchPaginationServiceRequest.builder() .userId(userId) .sortStandard(sortStandard) - .cursor(cursor) - .size(size) + .cursor(cursorId) + .size(ValidatorCursorSize.getDefaultSize(size)) .search(search) .build(); } diff --git a/app/api/show-api/src/main/java/com/example/artist/controller/dto/request/ArtistSubscriptionPaginationApiRequest.java b/app/api/show-api/src/main/java/com/example/artist/controller/dto/request/ArtistSubscriptionPaginationApiRequest.java index d71c76e0..d1b4bbe5 100644 --- a/app/api/show-api/src/main/java/com/example/artist/controller/dto/request/ArtistSubscriptionPaginationApiRequest.java +++ b/app/api/show-api/src/main/java/com/example/artist/controller/dto/request/ArtistSubscriptionPaginationApiRequest.java @@ -5,7 +5,9 @@ import com.example.vo.SubscriptionStatusApiType; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Max; import java.util.UUID; +import org.example.util.ValidatorCursorSize; @Schema public record ArtistSubscriptionPaginationApiRequest( @@ -16,21 +18,22 @@ public record ArtistSubscriptionPaginationApiRequest( ) ArtistSortApiType sort, - @Parameter(description = "이전 페이지네이션 마지막 데이터의 ID / 최초 조회라면 null") - UUID cursor, + @Parameter(description = "이전 페이지네이션 마지막 데이터의 cursorId / 최초 조회라면 null") + UUID cursorId, @Parameter(description = "조회하는 데이터 개수", required = true) - int size + @Max(value = 30, message = "조회하는 데이터 개수는 최대 30개 이어야 합니다.") + Integer size ) { public ArtistSubscriptionPaginationApiRequest( ArtistSortApiType sort, - UUID cursor, - int size + UUID cursorId, + Integer size ) { this.sort = sort == null ? ArtistSortApiType.ENGLISH_NAME_ASC : sort; - this.cursor = cursor; - this.size = size; + this.cursorId = cursorId; + this.size = ValidatorCursorSize.getDefaultSize(size); } public ArtistSubscriptionPaginationServiceRequest toServiceRequest(UUID userId) { @@ -38,7 +41,7 @@ public ArtistSubscriptionPaginationServiceRequest toServiceRequest(UUID userId) .subscriptionStatusApiType(SubscriptionStatusApiType.SUBSCRIBED) .size(size) .sortStandard(sort) - .cursor(cursor) + .cursor(cursorId) .userId(userId) .build(); } diff --git a/app/api/show-api/src/main/java/com/example/artist/controller/dto/request/ArtistUnsubscriptionPaginationApiRequest.java b/app/api/show-api/src/main/java/com/example/artist/controller/dto/request/ArtistUnsubscriptionPaginationApiRequest.java index df75d182..e4c08c22 100644 --- a/app/api/show-api/src/main/java/com/example/artist/controller/dto/request/ArtistUnsubscriptionPaginationApiRequest.java +++ b/app/api/show-api/src/main/java/com/example/artist/controller/dto/request/ArtistUnsubscriptionPaginationApiRequest.java @@ -7,11 +7,12 @@ import com.example.vo.SubscriptionStatusApiType; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Max; import java.util.List; import java.util.UUID; import org.example.util.ValidateStatus; +import org.example.util.ValidatorCursorSize; -@Schema public record ArtistUnsubscriptionPaginationApiRequest( @Parameter( description = "정렬 기준, default: ENGLISH_NAME_ASC", @@ -28,11 +29,12 @@ public record ArtistUnsubscriptionPaginationApiRequest( @Parameter(description = "장르 ID 목록") List genreIds, - @Parameter(description = "이전 페이지네이션 마지막 데이터의 ID / 최초 조회라면 null") - UUID cursor, + @Parameter(description = "이전 페이지네이션 마지막 데이터의 cursorId / 최초 조회라면 null") + UUID cursorId, @Parameter(description = "조회하는 데이터 개수", required = true) - int size + @Max(value = 30, message = "조회하는 데이터 개수는 최대 30개 이어야 합니다.") + Integer size ) { public ArtistUnsubscriptionPaginationApiRequest( @@ -40,16 +42,16 @@ public ArtistUnsubscriptionPaginationApiRequest( List artistGenderApiTypes, List artistApiTypes, List genreIds, - UUID cursor, - int size + UUID cursorId, + Integer size ) { this.sortStandard = sortStandard == null ? ArtistSortApiType.ENGLISH_NAME_ASC : sortStandard; this.artistGenderApiTypes = ValidateStatus.checkNullOrEmpty(artistGenderApiTypes); this.artistApiTypes = ValidateStatus.checkNullOrEmpty(artistApiTypes); this.genreIds = ValidateStatus.checkNullOrEmpty(genreIds); - this.cursor = cursor; - this.size = size; + this.cursorId = cursorId; + this.size = ValidatorCursorSize.getDefaultSize(size); } @@ -61,7 +63,7 @@ public ArtistUnsubscriptionPaginationServiceRequest toServiceRequest(UUID userId .artistApiTypes(artistApiTypes) .genreIds(genreIds) .userId(userId) - .cursor(cursor) + .cursor(cursorId) .size(size) .build(); } @@ -74,7 +76,7 @@ public ArtistUnsubscriptionPaginationServiceRequest toNonUserServiceRequest() { .artistApiTypes(artistApiTypes) .genreIds(genreIds) .userId(null) - .cursor(cursor) + .cursor(cursorId) .size(size) .build(); } diff --git a/app/api/show-api/src/main/java/com/example/artist/controller/dto/response/NumberOfSubscribedArtistApiResponse.java b/app/api/show-api/src/main/java/com/example/artist/controller/dto/response/NumberOfSubscribedArtistApiResponse.java new file mode 100644 index 00000000..5c993d35 --- /dev/null +++ b/app/api/show-api/src/main/java/com/example/artist/controller/dto/response/NumberOfSubscribedArtistApiResponse.java @@ -0,0 +1,15 @@ +package com.example.artist.controller.dto.response; + + +import com.example.artist.service.dto.response.NumberOfSubscribedArtistServiceResponse; + +public record NumberOfSubscribedArtistApiResponse( + long count +) { + + public static NumberOfSubscribedArtistApiResponse from( + NumberOfSubscribedArtistServiceResponse response + ) { + return new NumberOfSubscribedArtistApiResponse(response.count()); + } +} diff --git a/app/api/show-api/src/main/java/com/example/artist/service/ArtistService.java b/app/api/show-api/src/main/java/com/example/artist/service/ArtistService.java index 8d59185b..dc10b0cd 100644 --- a/app/api/show-api/src/main/java/com/example/artist/service/ArtistService.java +++ b/app/api/show-api/src/main/java/com/example/artist/service/ArtistService.java @@ -12,6 +12,7 @@ import com.example.artist.service.dto.response.ArtistFilterTotalCountServiceResponse; import com.example.artist.service.dto.response.ArtistSubscriptionServiceResponse; import com.example.artist.service.dto.response.ArtistUnsubscriptionServiceResponse; +import com.example.artist.service.dto.response.NumberOfSubscribedArtistServiceResponse; import com.example.publish.MessagePublisher; import com.example.publish.message.ArtistServiceMessage; import com.example.publish.message.ArtistSubscriptionServiceMessage; @@ -22,10 +23,9 @@ import org.example.dto.response.PaginationServiceResponse; import org.example.entity.ArtistSubscription; import org.example.entity.artist.Artist; -import org.example.usecase.ArtistSubscriptionUseCase; -import org.example.usecase.UserShowUseCase; -import org.example.usecase.UserUseCase; import org.example.usecase.artist.ArtistUseCase; +import org.example.usecase.subscription.ArtistSubscriptionUseCase; +import org.example.usecase.user.UserUseCase; import org.springframework.stereotype.Service; @Service @@ -35,7 +35,6 @@ public class ArtistService { private final ArtistUseCase artistUseCase; private final ArtistSubscriptionUseCase artistSubscriptionUseCase; - private final UserShowUseCase userShowUseCase; private final UserUseCase userUseCase; private final MessagePublisher messagePublisher; @@ -46,7 +45,7 @@ public PaginationServiceResponse searchArtis List subscribedArtistIds = request.userId() == null ? List.of() - : userShowUseCase.findArtistSubscriptionByUserId(request.userId()).stream() + : artistSubscriptionUseCase.findArtistSubscriptionByUserId(request.userId()).stream() .map(ArtistSubscription::getArtistId) .toList(); @@ -123,7 +122,6 @@ public ArtistUnsubscriptionServiceResponse unsubscribe( .map(ArtistServiceMessage::toUnsubscribe) .toList(); - var userFcmToken = userUseCase.findUserFcmTokensByUserId(request.userId()); messagePublisher.publishArtistSubscription( @@ -191,6 +189,12 @@ public PaginationServiceResponse fin return PaginationServiceResponse.of(data, response.hasNext()); } + public NumberOfSubscribedArtistServiceResponse countSubscribedArtists(UUID userId) { + return NumberOfSubscribedArtistServiceResponse.from( + artistSubscriptionUseCase.countSubscribedArtists(userId) + ); + } + private List getSubscriptionArtistIds(UUID userId) { List subscriptions = artistSubscriptionUseCase.findSubscriptionList( userId); diff --git a/app/api/user-api/src/main/java/org/example/service/dto/response/NumberOfSubscribedArtistServiceResponse.java b/app/api/show-api/src/main/java/com/example/artist/service/dto/response/NumberOfSubscribedArtistServiceResponse.java similarity index 82% rename from app/api/user-api/src/main/java/org/example/service/dto/response/NumberOfSubscribedArtistServiceResponse.java rename to app/api/show-api/src/main/java/com/example/artist/service/dto/response/NumberOfSubscribedArtistServiceResponse.java index 6b4d3872..ee8a0477 100644 --- a/app/api/user-api/src/main/java/org/example/service/dto/response/NumberOfSubscribedArtistServiceResponse.java +++ b/app/api/show-api/src/main/java/com/example/artist/service/dto/response/NumberOfSubscribedArtistServiceResponse.java @@ -1,4 +1,4 @@ -package org.example.service.dto.response; +package com.example.artist.service.dto.response; public record NumberOfSubscribedArtistServiceResponse( long count diff --git a/app/api/show-api/src/main/java/com/example/genre/controller/GenreController.java b/app/api/show-api/src/main/java/com/example/genre/controller/GenreController.java index 9641f02a..ebb6f31e 100644 --- a/app/api/show-api/src/main/java/com/example/genre/controller/GenreController.java +++ b/app/api/show-api/src/main/java/com/example/genre/controller/GenreController.java @@ -10,6 +10,7 @@ import com.example.genre.controller.dto.request.GenreUnsubscriptionPaginationApiRequest; import com.example.genre.controller.dto.response.GenreSubscriptionApiResponse; import com.example.genre.controller.dto.response.GenreUnsubscriptionApiResponse; +import com.example.genre.controller.dto.response.NumberOfSubscribedGenreApiResponse; import com.example.genre.service.GenreService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -38,7 +39,7 @@ public class GenreController { @Operation(summary = "장르 전체 목록 조회") public ResponseEntity> getGenres( @AuthenticationPrincipal AuthenticatedUser user, - @ParameterObject GenrePaginationApiRequest request + @Valid @ParameterObject GenrePaginationApiRequest request ) { var response = genreService.findGenres(request.toServiceRequest(user)); var data = response.data().stream() @@ -57,7 +58,7 @@ public ResponseEntity> getGenres( @Operation(summary = "구독하지 않은 장르 목록 조회") public ResponseEntity> getUnsubscribedGenres( @AuthenticationPrincipal AuthenticatedUser user, - @ParameterObject GenreUnsubscriptionPaginationApiRequest request + @Valid @ParameterObject GenreUnsubscriptionPaginationApiRequest request ) { var response = genreService.findGenreUnSubscriptions( request.toServiceRequest(user.userId())); @@ -77,7 +78,7 @@ public ResponseEntity> getSubscribedGenres( @AuthenticationPrincipal AuthenticatedUser user, - @ParameterObject GenreSubscriptionPaginationApiRequest request + @Valid @ParameterObject GenreSubscriptionPaginationApiRequest request ) { var response = genreService.findGenreSubscriptions(request.toServiceRequest(user.userId())); var data = response.data().stream() @@ -92,6 +93,18 @@ public ResponseEntity ); } + @GetMapping("/subscriptions/count") + @Operation(summary = "구독한 장르 수") + public ResponseEntity getNumberOfSubscribedGenre( + @AuthenticationPrincipal AuthenticatedUser user + ) { + return ResponseEntity.ok( + NumberOfSubscribedGenreApiResponse.from( + genreService.countSubscribedGenres(user.userId()) + ) + ); + } + @PostMapping("/subscribe") @Operation(summary = "구독하기") public ResponseEntity subscribe( diff --git a/app/api/show-api/src/main/java/com/example/genre/controller/dto/param/GenrePaginationApiParam.java b/app/api/show-api/src/main/java/com/example/genre/controller/dto/param/GenrePaginationApiParam.java index 84c2e16c..e06de53b 100644 --- a/app/api/show-api/src/main/java/com/example/genre/controller/dto/param/GenrePaginationApiParam.java +++ b/app/api/show-api/src/main/java/com/example/genre/controller/dto/param/GenrePaginationApiParam.java @@ -2,12 +2,12 @@ import com.example.genre.service.dto.param.GenrePaginationServiceParam; import io.swagger.v3.oas.annotations.media.Schema; -import java.util.UUID; +import org.example.dto.response.CursorApiResponse; public record GenrePaginationApiParam( - @Schema(description = "장르 ID") - UUID id, + @Schema(description = "장르 Cursor") + CursorApiResponse cursor, @Schema(description = "장르 이름") String name, @@ -18,7 +18,7 @@ public record GenrePaginationApiParam( public GenrePaginationApiParam(GenrePaginationServiceParam param) { this( - param.id(), + CursorApiResponse.toCursorId(param.id()), param.name(), param.isSubscribed() ); diff --git a/app/api/show-api/src/main/java/com/example/genre/controller/dto/param/GenreSubscriptionPaginationApiParam.java b/app/api/show-api/src/main/java/com/example/genre/controller/dto/param/GenreSubscriptionPaginationApiParam.java index 81f350af..ccfaaae9 100644 --- a/app/api/show-api/src/main/java/com/example/genre/controller/dto/param/GenreSubscriptionPaginationApiParam.java +++ b/app/api/show-api/src/main/java/com/example/genre/controller/dto/param/GenreSubscriptionPaginationApiParam.java @@ -1,10 +1,13 @@ package com.example.genre.controller.dto.param; import com.example.genre.service.dto.param.GenreSubscriptionPaginationServiceParam; -import java.util.UUID; +import io.swagger.v3.oas.annotations.media.Schema; +import org.example.dto.response.CursorApiResponse; public record GenreSubscriptionPaginationApiParam( - UUID id, + @Schema(description = "장르 Cursor") + CursorApiResponse cursor, + @Schema(description = "장르 이름") String name ) { @@ -12,7 +15,7 @@ public GenreSubscriptionPaginationApiParam( GenreSubscriptionPaginationServiceParam response ) { this( - response.id(), + CursorApiResponse.toCursorId(response.id()), response.name() ); } diff --git a/app/api/show-api/src/main/java/com/example/genre/controller/dto/param/GenreUnsubscriptionPaginationApiParam.java b/app/api/show-api/src/main/java/com/example/genre/controller/dto/param/GenreUnsubscriptionPaginationApiParam.java index 5e9f0451..23a7aa93 100644 --- a/app/api/show-api/src/main/java/com/example/genre/controller/dto/param/GenreUnsubscriptionPaginationApiParam.java +++ b/app/api/show-api/src/main/java/com/example/genre/controller/dto/param/GenreUnsubscriptionPaginationApiParam.java @@ -1,10 +1,13 @@ package com.example.genre.controller.dto.param; import com.example.genre.service.dto.param.GenreUnsubscriptionPaginationServiceParam; -import java.util.UUID; +import io.swagger.v3.oas.annotations.media.Schema; +import org.example.dto.response.CursorApiResponse; public record GenreUnsubscriptionPaginationApiParam( - UUID id, + @Schema(description = "장르 Cursor") + CursorApiResponse cursor, + @Schema(description = "장르 이름") String name ) { @@ -12,7 +15,7 @@ public GenreUnsubscriptionPaginationApiParam( GenreUnsubscriptionPaginationServiceParam response ) { this( - response.id(), + CursorApiResponse.toCursorId(response.id()), response.name() ); } diff --git a/app/api/show-api/src/main/java/com/example/genre/controller/dto/request/GenrePaginationApiRequest.java b/app/api/show-api/src/main/java/com/example/genre/controller/dto/request/GenrePaginationApiRequest.java index 9c74fe71..57cfbc1d 100644 --- a/app/api/show-api/src/main/java/com/example/genre/controller/dto/request/GenrePaginationApiRequest.java +++ b/app/api/show-api/src/main/java/com/example/genre/controller/dto/request/GenrePaginationApiRequest.java @@ -3,15 +3,18 @@ import com.example.genre.service.dto.request.GenrePaginationServiceRequest; import com.example.vo.SubscriptionStatusApiType; import io.swagger.v3.oas.annotations.Parameter; +import jakarta.validation.constraints.Max; import java.util.UUID; import org.example.security.dto.AuthenticatedUser; +import org.example.util.ValidatorCursorSize; public record GenrePaginationApiRequest( - @Parameter(description = "이전 페이지네이션 마지막 데이터의 ID / 최초 조회라면 null") - UUID cursor, + @Parameter(description = "이전 페이지네이션 마지막 데이터의 cursorId / 최초 조회라면 null") + UUID cursorId, @Parameter(description = "조회하는 데이터 개수", required = true) - int size + @Max(value = 30, message = "조회하는 데이터 개수는 최대 30개 이어야 합니다.") + Integer size ) { public GenrePaginationServiceRequest toServiceRequest(AuthenticatedUser user) { @@ -19,8 +22,8 @@ public GenrePaginationServiceRequest toServiceRequest(AuthenticatedUser user) { return GenrePaginationServiceRequest.builder() .type(SubscriptionStatusApiType.DEFAULTED) - .cursor(cursor) - .size(size) + .cursor(cursorId) + .size(ValidatorCursorSize.getDefaultSize(size)) .userId(userId) .build(); } diff --git a/app/api/show-api/src/main/java/com/example/genre/controller/dto/request/GenreSubscriptionPaginationApiRequest.java b/app/api/show-api/src/main/java/com/example/genre/controller/dto/request/GenreSubscriptionPaginationApiRequest.java index daad5791..89c0f2cb 100644 --- a/app/api/show-api/src/main/java/com/example/genre/controller/dto/request/GenreSubscriptionPaginationApiRequest.java +++ b/app/api/show-api/src/main/java/com/example/genre/controller/dto/request/GenreSubscriptionPaginationApiRequest.java @@ -3,21 +3,24 @@ import com.example.genre.service.dto.request.GenreSubscriptionPaginationServiceRequest; import com.example.vo.SubscriptionStatusApiType; import io.swagger.v3.oas.annotations.Parameter; +import jakarta.validation.constraints.Max; import java.util.UUID; +import org.example.util.ValidatorCursorSize; public record GenreSubscriptionPaginationApiRequest( - @Parameter(description = "이전 페이지네이션 마지막 데이터의 ID / 최초 조회라면 null") - UUID cursor, + @Parameter(description = "이전 페이지네이션 마지막 데이터의 cursorId / 최초 조회라면 null") + UUID cursorId, @Parameter(description = "조회하는 데이터 개수") - int size + @Max(value = 30, message = "조회하는 데이터 개수는 최대 30개 이어야 합니다.") + Integer size ) { public GenreSubscriptionPaginationServiceRequest toServiceRequest(UUID userId) { return GenreSubscriptionPaginationServiceRequest.builder() .subscriptionStatusApiType(SubscriptionStatusApiType.SUBSCRIBED) - .cursor(cursor) - .size(size) + .cursor(cursorId) + .size(ValidatorCursorSize.getDefaultSize(size)) .userId(userId) .build(); } diff --git a/app/api/show-api/src/main/java/com/example/genre/controller/dto/request/GenreUnsubscriptionPaginationApiRequest.java b/app/api/show-api/src/main/java/com/example/genre/controller/dto/request/GenreUnsubscriptionPaginationApiRequest.java index ef3e0476..4db736c5 100644 --- a/app/api/show-api/src/main/java/com/example/genre/controller/dto/request/GenreUnsubscriptionPaginationApiRequest.java +++ b/app/api/show-api/src/main/java/com/example/genre/controller/dto/request/GenreUnsubscriptionPaginationApiRequest.java @@ -3,21 +3,24 @@ import com.example.genre.service.dto.request.GenreUnsubscriptionPaginationServiceRequest; import com.example.vo.SubscriptionStatusApiType; import io.swagger.v3.oas.annotations.Parameter; +import jakarta.validation.constraints.Max; import java.util.UUID; +import org.example.util.ValidatorCursorSize; public record GenreUnsubscriptionPaginationApiRequest( - @Parameter(description = "이전 페이지네이션 마지막 데이터의 ID / 최초 조회라면 null") - UUID cursor, + @Parameter(description = "이전 페이지네이션 마지막 데이터의 cursorId / 최초 조회라면 null") + UUID cursorId, @Parameter(description = "조회하는 데이터 개수", required = true) - int size + @Max(value = 30, message = "조회하는 데이터 개수는 최대 30개 이어야 합니다.") + Integer size ) { public GenreUnsubscriptionPaginationServiceRequest toServiceRequest(UUID userId) { return GenreUnsubscriptionPaginationServiceRequest.builder() .subscriptionStatusApiType(SubscriptionStatusApiType.UNSUBSCRIBED) - .cursor(cursor) - .size(size) + .cursor(cursorId) + .size(ValidatorCursorSize.getDefaultSize(size)) .userId(userId) .build(); } diff --git a/app/api/show-api/src/main/java/com/example/genre/controller/dto/response/NumberOfSubscribedGenreApiResponse.java b/app/api/show-api/src/main/java/com/example/genre/controller/dto/response/NumberOfSubscribedGenreApiResponse.java new file mode 100644 index 00000000..448ed099 --- /dev/null +++ b/app/api/show-api/src/main/java/com/example/genre/controller/dto/response/NumberOfSubscribedGenreApiResponse.java @@ -0,0 +1,15 @@ +package com.example.genre.controller.dto.response; + + +import com.example.genre.service.dto.response.NumberOfSubscribedGenreServiceResponse; + +public record NumberOfSubscribedGenreApiResponse( + long count +) { + + public static NumberOfSubscribedGenreApiResponse from( + NumberOfSubscribedGenreServiceResponse response + ) { + return new NumberOfSubscribedGenreApiResponse(response.count()); + } +} diff --git a/app/api/show-api/src/main/java/com/example/genre/service/GenreService.java b/app/api/show-api/src/main/java/com/example/genre/service/GenreService.java index 2819975b..68047b59 100644 --- a/app/api/show-api/src/main/java/com/example/genre/service/GenreService.java +++ b/app/api/show-api/src/main/java/com/example/genre/service/GenreService.java @@ -10,6 +10,7 @@ import com.example.genre.service.dto.request.GenreUnsubscriptionServiceRequest; import com.example.genre.service.dto.response.GenreSubscriptionServiceResponse; import com.example.genre.service.dto.response.GenreUnsubscriptionServiceResponse; +import com.example.genre.service.dto.response.NumberOfSubscribedGenreServiceResponse; import com.example.publish.MessagePublisher; import com.example.publish.message.GenreServiceMessage; import com.example.publish.message.GenreSubscriptionServiceMessage; @@ -20,9 +21,9 @@ import org.example.dto.response.PaginationServiceResponse; import org.example.entity.GenreSubscription; import org.example.entity.genre.Genre; -import org.example.usecase.GenreSubscriptionUseCase; -import org.example.usecase.UserUseCase; import org.example.usecase.genre.GenreUseCase; +import org.example.usecase.subscription.GenreSubscriptionUseCase; +import org.example.usecase.user.UserUseCase; import org.springframework.stereotype.Service; @Service @@ -100,7 +101,9 @@ public GenreUnsubscriptionServiceResponse unsubscribe( .build(); } - public PaginationServiceResponse findGenres(GenrePaginationServiceRequest request) { + public PaginationServiceResponse findGenres( + GenrePaginationServiceRequest request + ) { List subscriptionGenreIds = request.userId() == null ? List.of() : getSubscriptionGenreIds(request.userId()); @@ -146,6 +149,12 @@ public PaginationServiceResponse find return PaginationServiceResponse.of(data, response.hasNext()); } + public NumberOfSubscribedGenreServiceResponse countSubscribedGenres(UUID uuid) { + return NumberOfSubscribedGenreServiceResponse.from( + genreSubscriptionUseCase.countSubscribedGenres(uuid) + ); + } + private List getSubscriptionGenreIds(UUID userId) { List subscriptions = genreSubscriptionUseCase.findSubscriptions(userId); diff --git a/app/api/user-api/src/main/java/org/example/service/dto/response/NumberOfSubscribedGenreServiceResponse.java b/app/api/show-api/src/main/java/com/example/genre/service/dto/response/NumberOfSubscribedGenreServiceResponse.java similarity index 82% rename from app/api/user-api/src/main/java/org/example/service/dto/response/NumberOfSubscribedGenreServiceResponse.java rename to app/api/show-api/src/main/java/com/example/genre/service/dto/response/NumberOfSubscribedGenreServiceResponse.java index dac0cd56..8d36f0f5 100644 --- a/app/api/user-api/src/main/java/org/example/service/dto/response/NumberOfSubscribedGenreServiceResponse.java +++ b/app/api/show-api/src/main/java/com/example/genre/service/dto/response/NumberOfSubscribedGenreServiceResponse.java @@ -1,4 +1,4 @@ -package org.example.service.dto.response; +package com.example.genre.service.dto.response; public record NumberOfSubscribedGenreServiceResponse( long count diff --git a/app/api/show-api/src/main/java/com/example/show/controller/ShowController.java b/app/api/show-api/src/main/java/com/example/show/controller/ShowController.java index 67b04279..6cdcc222 100644 --- a/app/api/show-api/src/main/java/com/example/show/controller/ShowController.java +++ b/app/api/show-api/src/main/java/com/example/show/controller/ShowController.java @@ -1,27 +1,15 @@ package com.example.show.controller; -import com.example.show.controller.dto.param.ShowAlertPaginationApiParam; import com.example.show.controller.dto.param.ShowSearchPaginationApiParam; -import com.example.show.controller.dto.request.ShowAlertPaginationApiRequest; -import com.example.show.controller.dto.request.ShowInterestPaginationApiRequest; import com.example.show.controller.dto.request.ShowPaginationApiRequest; import com.example.show.controller.dto.request.ShowSearchPaginationApiRequest; -import com.example.show.controller.dto.request.TicketingAlertReservationApiRequest; -import com.example.show.controller.dto.response.InterestShowPaginationApiResponse; import com.example.show.controller.dto.response.ShowDetailApiResponse; -import com.example.show.controller.dto.response.ShowInterestApiResponse; import com.example.show.controller.dto.response.ShowPaginationApiParam; -import com.example.show.controller.dto.response.TerminatedTicketingShowCountApiResponse; -import com.example.show.controller.dto.response.TicketingAlertReservationApiResponse; -import com.example.show.controller.vo.TicketingApiType; import com.example.show.service.ShowService; -import com.example.show.service.dto.param.ShowAlertPaginationServiceParam; -import com.example.show.service.dto.request.ShowInterestServiceRequest; import com.example.show.service.dto.response.ShowPaginationServiceResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -import java.util.List; import java.util.UUID; import lombok.RequiredArgsConstructor; import org.example.dto.response.PaginationApiResponse; @@ -33,11 +21,8 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal; 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.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @@ -51,7 +36,7 @@ public class ShowController { @GetMapping @Operation(summary = "공연 목록 조회") public ResponseEntity> getShows( - @ParameterObject ShowPaginationApiRequest request + @Valid @ParameterObject ShowPaginationApiRequest request ) { PaginationServiceResponse response = showService.findShows( request.toServiceRequest() @@ -70,46 +55,6 @@ public ResponseEntity> getShows( } - @PostMapping("/{showId}/interests") - @Operation(summary = "공연 관심 등록 / 취소") - public ResponseEntity interest( - @PathVariable("showId") UUID showId, - @AuthenticationPrincipal AuthenticatedUser user - ) { - return ResponseEntity.ok( - ShowInterestApiResponse.from( - showService.interest( - ShowInterestServiceRequest.builder() - .showId(showId) - .userId(user.userId()) - .build() - ) - ) - ); - } - - @GetMapping("/interests") - @Operation(summary = "공연 관심 목록 조회") - public ResponseEntity> getInterests( - @ParameterObject ShowInterestPaginationApiRequest request, - @AuthenticationPrincipal AuthenticatedUser user - ) { - var serviceResponse = showService.findInterestShows( - request.toServiceRequest(user.userId()) - ); - - List response = serviceResponse.data().stream() - .map(InterestShowPaginationApiResponse::from) - .toList(); - - return ResponseEntity.ok( - PaginationApiResponse.builder() - .data(response) - .hasNext(serviceResponse.hasNext()) - .build() - ); - } - @GetMapping("/{showId}") @Operation(summary = "공연 상세 조회") public ResponseEntity getShow( @@ -124,59 +69,6 @@ public ResponseEntity getShow( ); } - @GetMapping("/{showId}/alert/reservations") - @Operation(summary = "공연 티켓팅 알림 예약 조회") - public ResponseEntity getAlertsReservations( - @AuthenticationPrincipal AuthenticatedUser user, - @PathVariable("showId") UUID showId, - @RequestParam("ticketingApiType") TicketingApiType type - ) { - return ResponseEntity.ok( - TicketingAlertReservationApiResponse.from( - showService.findAlertsReservations(user.userId(), showId, type) - ) - ); - } - - @PostMapping("/{showId}/alert") - @Operation( - summary = "공연 티켓팅 알림 등록 / 취소", - description = "요청한 알람 시간으로 기존 내용을 덮어쓴다." - ) - public ResponseEntity alert( - @AuthenticationPrincipal AuthenticatedUser user, - @PathVariable("showId") UUID showId, - @RequestParam("ticketingApiType") TicketingApiType type, - @Valid @RequestBody TicketingAlertReservationApiRequest ticketingAlertReservationRequest - ) { - showService.alertReservation( - ticketingAlertReservationRequest.toServiceRequest(user.userId(), showId, type) - ); - - return ResponseEntity.noContent().build(); - } - - @GetMapping("/alerts") - @Operation(summary = "공연 알림 목록 조회") - public ResponseEntity> getAlerts( - @AuthenticationPrincipal AuthenticatedUser user, - @ParameterObject ShowAlertPaginationApiRequest request - ) { - PaginationServiceResponse alertShows = showService.findAlertShows( - request.toServiceRequest(user.userId())); - - var showAlertPaginationApiParams = alertShows.data().stream() - .map(ShowAlertPaginationApiParam::from) - .toList(); - - return ResponseEntity.ok( - PaginationApiResponse.builder() - .data(showAlertPaginationApiParams) - .hasNext(alertShows.hasNext()) - .build() - ); - } - @GetMapping("/search") @Operation(summary = "검색하기") public ResponseEntity> search( @@ -195,16 +87,4 @@ public ResponseEntity> searc .build() ); } - - @GetMapping("/terminated/ticketing/count") - @Operation(summary = "티켓팅 알림 설정 후 공연이 종료된 개수") - public ResponseEntity getNumberOfTerminatedTicketingShowCount( - @AuthenticationPrincipal AuthenticatedUser user - ) { - return ResponseEntity.ok( - TerminatedTicketingShowCountApiResponse.from( - showService.countTerminatedTicketingShow(user.userId()) - ) - ); - } } diff --git a/app/api/show-api/src/main/java/com/example/show/controller/UserShowController.java b/app/api/show-api/src/main/java/com/example/show/controller/UserShowController.java new file mode 100644 index 00000000..4f68e203 --- /dev/null +++ b/app/api/show-api/src/main/java/com/example/show/controller/UserShowController.java @@ -0,0 +1,175 @@ +package com.example.show.controller; + +import com.example.show.controller.dto.param.ShowAlertPaginationApiParam; +import com.example.show.controller.dto.request.ShowAlertPaginationApiRequest; +import com.example.show.controller.dto.request.ShowInterestPaginationApiRequest; +import com.example.show.controller.dto.request.TicketingAlertReservationApiRequest; +import com.example.show.controller.dto.response.InterestShowPaginationApiResponse; +import com.example.show.controller.dto.response.ShowInterestApiResponse; +import com.example.show.controller.dto.response.TerminatedTicketingShowCountApiResponse; +import com.example.show.controller.dto.response.TicketingAlertReservationApiResponse; +import com.example.show.controller.dto.usershow.response.NumberOfInterestShowApiResponse; +import com.example.show.controller.dto.usershow.response.NumberOfTicketingAlertApiResponse; +import com.example.show.controller.vo.TicketingApiType; +import com.example.show.service.UserShowService; +import com.example.show.service.dto.param.ShowAlertPaginationServiceParam; +import com.example.show.service.dto.request.ShowInterestServiceRequest; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import java.time.LocalDateTime; +import java.util.List; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.example.dto.response.PaginationApiResponse; +import org.example.dto.response.PaginationServiceResponse; +import org.example.security.dto.AuthenticatedUser; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/shows") +@Tag(name = "공연") +public class UserShowController { + + private final UserShowService userShowService; + + @PostMapping("/{showId}/interests") + @Operation(summary = "공연 관심 등록 / 취소") + public ResponseEntity interest( + @PathVariable("showId") UUID showId, + @AuthenticationPrincipal AuthenticatedUser user + ) { + return ResponseEntity.ok( + ShowInterestApiResponse.from( + userShowService.interest( + ShowInterestServiceRequest.builder() + .showId(showId) + .userId(user.userId()) + .build() + ) + ) + ); + } + + @GetMapping("/interests") + @Operation(summary = "공연 관심 목록 조회") + public ResponseEntity> getInterests( + @AuthenticationPrincipal AuthenticatedUser user, + @Valid @ParameterObject ShowInterestPaginationApiRequest request + ) { + var serviceResponse = userShowService.findInterestShows( + request.toServiceRequest(user.userId()) + ); + + List response = serviceResponse.data().stream() + .map(InterestShowPaginationApiResponse::from) + .toList(); + + return ResponseEntity.ok( + PaginationApiResponse.builder() + .data(response) + .hasNext(serviceResponse.hasNext()) + .build() + ); + } + + @GetMapping("/interests/count") + @Operation(summary = "관심 공연 개수") + public ResponseEntity getNumberOfInterestShow( + @AuthenticationPrincipal AuthenticatedUser user + ) { + return ResponseEntity.ok( + NumberOfInterestShowApiResponse.from( + userShowService.countInterestShows(user.userId()) + ) + ); + } + + @PostMapping("/{showId}/alert") + @Operation( + summary = "공연 티켓팅 알림 등록 / 취소", + description = "요청한 알람 시간으로 기존 내용을 덮어쓴다." + ) + public ResponseEntity alert( + @AuthenticationPrincipal AuthenticatedUser user, + @PathVariable("showId") UUID showId, + @RequestParam("ticketingApiType") TicketingApiType type, + @Valid @RequestBody TicketingAlertReservationApiRequest ticketingAlertReservationRequest + ) { + userShowService.alertReservation( + ticketingAlertReservationRequest.toServiceRequest(user.userId(), showId, type) + ); + + return ResponseEntity.noContent().build(); + } + + @GetMapping("/alerts") + @Operation(summary = "공연 알림 목록 조회") + public ResponseEntity> getAlerts( + @AuthenticationPrincipal AuthenticatedUser user, + @ParameterObject ShowAlertPaginationApiRequest request + ) { + PaginationServiceResponse alertShows = userShowService.findAlertShows( + request.toServiceRequest(user.userId())); + + var showAlertPaginationApiParams = alertShows.data().stream() + .map(ShowAlertPaginationApiParam::from) + .toList(); + + return ResponseEntity.ok( + PaginationApiResponse.builder() + .data(showAlertPaginationApiParams) + .hasNext(alertShows.hasNext()) + .build() + ); + } + + @GetMapping("/{showId}/alert/reservations") + @Operation(summary = "공연 티켓팅 알림 예약 조회") + public ResponseEntity getAlertsReservations( + @AuthenticationPrincipal AuthenticatedUser user, + @PathVariable("showId") UUID showId, + @RequestParam("ticketingApiType") TicketingApiType type + ) { + return ResponseEntity.ok( + TicketingAlertReservationApiResponse.from( + userShowService.findAlertsReservations(user.userId(), showId, type) + ) + ); + } + + @GetMapping("/alerts/count") + @Operation(summary = "알림 설정한 공연 개수") + public ResponseEntity getNumberOfAlertShow( + @AuthenticationPrincipal AuthenticatedUser user + ) { + LocalDateTime now = LocalDateTime.now(); + return ResponseEntity.ok( + NumberOfTicketingAlertApiResponse.from( + userShowService.countAlertShows(user.userId(), now) + ) + ); + } + + @GetMapping("/terminated/ticketing/count") + @Operation(summary = "티켓팅 알림 설정 후 공연이 종료된 개수") + public ResponseEntity getNumberOfTerminatedTicketingShowCount( + @AuthenticationPrincipal AuthenticatedUser user + ) { + return ResponseEntity.ok( + TerminatedTicketingShowCountApiResponse.from( + userShowService.countTerminatedTicketingShow(user.userId()) + ) + ); + } +} diff --git a/app/api/show-api/src/main/java/com/example/show/controller/dto/param/ShowAlertPaginationApiParam.java b/app/api/show-api/src/main/java/com/example/show/controller/dto/param/ShowAlertPaginationApiParam.java index 2ef3f0db..85219b2e 100644 --- a/app/api/show-api/src/main/java/com/example/show/controller/dto/param/ShowAlertPaginationApiParam.java +++ b/app/api/show-api/src/main/java/com/example/show/controller/dto/param/ShowAlertPaginationApiParam.java @@ -2,8 +2,8 @@ import com.example.show.service.dto.param.ShowAlertPaginationServiceParam; import io.swagger.v3.oas.annotations.media.Schema; -import java.time.LocalDateTime; import java.util.UUID; +import org.example.dto.response.CursorApiResponse; import org.example.util.DateTimeUtil; public record ShowAlertPaginationApiParam( @@ -19,17 +19,17 @@ public record ShowAlertPaginationApiParam( @Schema(description = "공연 마지막 날짜") String endAt, + @Schema(description = "가장 근접한 티케팅 예매 시간") + String ticketingAt, + @Schema(description = "공연 장소") String location, @Schema(description = "공연 이미지 URL") String imageURL, - @Schema(description = "cursorID") - UUID cursorId, - - @Schema(description = "cursorValue") - LocalDateTime cursorValue + @Schema(description = "조회한 데이터의 Cursor") + CursorApiResponse cursor ) { public static ShowAlertPaginationApiParam from(ShowAlertPaginationServiceParam serviceParam) { @@ -38,10 +38,10 @@ public static ShowAlertPaginationApiParam from(ShowAlertPaginationServiceParam s serviceParam.title(), DateTimeUtil.formatDate(serviceParam.startAt()), DateTimeUtil.formatDate(serviceParam.endAt()), + DateTimeUtil.formatDateTime(serviceParam.ticketingAt()), serviceParam.location(), serviceParam.image(), - serviceParam.showTicketingTimeId(), - serviceParam.ticketingAt() + CursorApiResponse.toCursorResponse(serviceParam.showTicketingTimeId(), serviceParam.ticketingAt()) ); } } diff --git a/app/api/show-api/src/main/java/com/example/show/controller/dto/param/ShowSearchPaginationApiParam.java b/app/api/show-api/src/main/java/com/example/show/controller/dto/param/ShowSearchPaginationApiParam.java index 559e98ca..e9664c35 100644 --- a/app/api/show-api/src/main/java/com/example/show/controller/dto/param/ShowSearchPaginationApiParam.java +++ b/app/api/show-api/src/main/java/com/example/show/controller/dto/param/ShowSearchPaginationApiParam.java @@ -2,12 +2,12 @@ import com.example.show.service.dto.param.ShowSearchPaginationServiceParam; import io.swagger.v3.oas.annotations.media.Schema; -import java.util.UUID; +import org.example.dto.response.CursorApiResponse; import org.example.util.DateTimeUtil; public record ShowSearchPaginationApiParam( - @Schema(description = "공연 ID") - UUID id, + @Schema(description = "공연 Cursor") + CursorApiResponse cursor, @Schema(description = "공연 제목") String title, @@ -27,7 +27,7 @@ public record ShowSearchPaginationApiParam( public static ShowSearchPaginationApiParam from(ShowSearchPaginationServiceParam serviceParam) { return new ShowSearchPaginationApiParam( - serviceParam.id(), + CursorApiResponse.toCursorId(serviceParam.id()), serviceParam.title(), DateTimeUtil.formatDate(serviceParam.startAt()), DateTimeUtil.formatDate(serviceParam.endAt()), diff --git a/app/api/show-api/src/main/java/com/example/show/controller/dto/request/ShowAlertPaginationApiRequest.java b/app/api/show-api/src/main/java/com/example/show/controller/dto/request/ShowAlertPaginationApiRequest.java index ab7f7bc1..44c034a2 100644 --- a/app/api/show-api/src/main/java/com/example/show/controller/dto/request/ShowAlertPaginationApiRequest.java +++ b/app/api/show-api/src/main/java/com/example/show/controller/dto/request/ShowAlertPaginationApiRequest.java @@ -3,28 +3,31 @@ import com.example.show.service.dto.request.ShowAlertPaginationServiceRequest; import com.example.show.vo.ShowTicketingAtStatusApiType; import io.swagger.v3.oas.annotations.Parameter; +import jakarta.validation.constraints.Max; import java.time.LocalDateTime; import java.util.UUID; +import org.example.util.ValidatorCursorSize; public record ShowAlertPaginationApiRequest( @Parameter(description = "페이지네이션 데이터 개수", required = true) - int size, + @Max(value = 30, message = "조회하는 데이터 개수는 최대 30개 이어야 합니다.") + Integer size, @Parameter(description = "공연 티켓팅 상태 타입", required = true) ShowTicketingAtStatusApiType type, - @Parameter(description = "이전 페이지네이션 마지막 데이터의 showTicketingTimeId / 최초 조회라면 null") + @Parameter(description = "이전 페이지네이션 마지막 데이터의 cursorId / 최초 조회라면 null") UUID cursorId, - @Parameter(description = "이전 페이지네이션 마지막 데이터의 ticketingAt / 최초 조회라면 null") + @Parameter(description = "이전 페이지네이션 마지막 데이터의 cursorValue / 최초 조회라면 null") LocalDateTime cursorValue ) { public ShowAlertPaginationServiceRequest toServiceRequest(UUID userId) { return ShowAlertPaginationServiceRequest.builder() .userId(userId) - .size(size) + .size(ValidatorCursorSize.getDefaultSize(size)) .type(type) .cursorId(cursorId) .cursorValue(cursorValue) diff --git a/app/api/show-api/src/main/java/com/example/show/controller/dto/request/ShowInterestPaginationApiRequest.java b/app/api/show-api/src/main/java/com/example/show/controller/dto/request/ShowInterestPaginationApiRequest.java index d42300bc..9179a52c 100644 --- a/app/api/show-api/src/main/java/com/example/show/controller/dto/request/ShowInterestPaginationApiRequest.java +++ b/app/api/show-api/src/main/java/com/example/show/controller/dto/request/ShowInterestPaginationApiRequest.java @@ -2,24 +2,27 @@ import com.example.show.service.dto.request.InterestShowPaginationServiceRequest; import io.swagger.v3.oas.annotations.Parameter; +import jakarta.validation.constraints.Max; import java.time.LocalDateTime; import java.util.UUID; +import org.example.util.ValidatorCursorSize; public record ShowInterestPaginationApiRequest( @Parameter(description = "페이지네이션 데이터 개수", required = true) - int size, - @Parameter(description = "이전 페이지네이션 마지막 데이터의 interestShowId / 최초 조회라면 null") + @Max(value = 30, message = "조회하는 데이터 개수는 최대 30개 이어야 합니다.") + Integer size, + @Parameter(description = "이전 페이지네이션 마지막 데이터의 cursorId / 최초 조회라면 null") UUID cursorId, - @Parameter(description = "이전 페이지네이션 마지막 데이터의 interestedAt / 최초 조회라면 null") + @Parameter(description = "이전 페이지네이션 마지막 데이터의 cursorValue / 최초 조회라면 null") LocalDateTime cursorValue ) { public InterestShowPaginationServiceRequest toServiceRequest(UUID userId) { return InterestShowPaginationServiceRequest.builder() .userId(userId) - .size(size) + .size(ValidatorCursorSize.getDefaultSize(size)) .cursorId(cursorId) .cursorValue(cursorValue) .build(); diff --git a/app/api/show-api/src/main/java/com/example/show/controller/dto/request/ShowPaginationApiRequest.java b/app/api/show-api/src/main/java/com/example/show/controller/dto/request/ShowPaginationApiRequest.java index 4945c476..a8570404 100644 --- a/app/api/show-api/src/main/java/com/example/show/controller/dto/request/ShowPaginationApiRequest.java +++ b/app/api/show-api/src/main/java/com/example/show/controller/dto/request/ShowPaginationApiRequest.java @@ -3,7 +3,9 @@ import com.example.show.controller.vo.ShowSortApiType; import com.example.show.service.dto.request.ShowPaginationServiceRequest; import io.swagger.v3.oas.annotations.Parameter; +import jakarta.validation.constraints.Max; import java.util.UUID; +import org.example.util.ValidatorCursorSize; import org.springdoc.core.annotations.ParameterObject; @ParameterObject @@ -15,11 +17,12 @@ public record ShowPaginationApiRequest( @Parameter(required = true, description = "오픈예정 티켓만 보기") boolean onlyOpenSchedule, - @Parameter(description = "이전 페이지네이션 마지막 데이터의 ID / 최초 조회라면 null") + @Parameter(description = "이전 페이지네이션 마지막 데이터의 cursorId / 최초 조회라면 null") UUID cursorId, @Parameter(required = true, description = "조회하려는 데이터 개수") - int size + @Max(value = 30, message = "조회하는 데이터 개수는 최대 30개 이어야 합니다.") + Integer size ) { public ShowPaginationServiceRequest toServiceRequest() { @@ -27,7 +30,7 @@ public ShowPaginationServiceRequest toServiceRequest() { .sort(sort) .onlyOpenSchedule(onlyOpenSchedule) .cursorId(cursorId) - .size(size) + .size(ValidatorCursorSize.getDefaultSize(size)) .build(); } } diff --git a/app/api/show-api/src/main/java/com/example/show/controller/dto/request/ShowSearchPaginationApiRequest.java b/app/api/show-api/src/main/java/com/example/show/controller/dto/request/ShowSearchPaginationApiRequest.java index 4109a743..b89c2648 100644 --- a/app/api/show-api/src/main/java/com/example/show/controller/dto/request/ShowSearchPaginationApiRequest.java +++ b/app/api/show-api/src/main/java/com/example/show/controller/dto/request/ShowSearchPaginationApiRequest.java @@ -2,14 +2,17 @@ import com.example.show.service.dto.request.ShowSearchPaginationServiceRequest; import io.swagger.v3.oas.annotations.Parameter; +import jakarta.validation.constraints.Max; import java.util.UUID; +import org.example.util.ValidatorCursorSize; public record ShowSearchPaginationApiRequest( - @Parameter(description = "이전 페이지네이션 마지막 데이터의 ID / 최초 조회라면 null") - UUID cursor, + @Parameter(description = "이전 페이지네이션 마지막 데이터의 cursorId / 최초 조회라면 null") + UUID cursorId, @Parameter(description = "조회하는 데이터 개수", required = true) - int size, + @Max(value = 30, message = "조회하는 데이터 개수는 최대 30개 이어야 합니다.") + Integer size, @Parameter(description = "검색어", required = true) String search @@ -17,8 +20,8 @@ public record ShowSearchPaginationApiRequest( public ShowSearchPaginationServiceRequest toServiceRequest() { return ShowSearchPaginationServiceRequest.builder() - .cursor(cursor) - .size(size) + .cursor(cursorId) + .size(ValidatorCursorSize.getDefaultSize(size)) .search(search) .build(); } diff --git a/app/api/show-api/src/main/java/com/example/show/controller/dto/response/InterestShowPaginationApiResponse.java b/app/api/show-api/src/main/java/com/example/show/controller/dto/response/InterestShowPaginationApiResponse.java index a9b093d8..e3758b5c 100644 --- a/app/api/show-api/src/main/java/com/example/show/controller/dto/response/InterestShowPaginationApiResponse.java +++ b/app/api/show-api/src/main/java/com/example/show/controller/dto/response/InterestShowPaginationApiResponse.java @@ -2,9 +2,9 @@ import com.example.show.service.dto.response.InterestShowPaginationServiceResponse; import io.swagger.v3.oas.annotations.media.Schema; -import java.time.LocalDateTime; import java.util.UUID; import lombok.Builder; +import org.example.dto.response.CursorApiResponse; import org.example.util.DateTimeUtil; @Builder @@ -12,12 +12,6 @@ public record InterestShowPaginationApiResponse( @Schema(description = "공연 ID") UUID id, - @Schema(description = "cursorID로서 관심 공연 ID") - UUID interestShowId, - - @Schema(description = "cursorValue로서 관심 공연 지정 시간") - LocalDateTime interestedAt, - @Schema(description = "공연 이름") String title, @@ -31,7 +25,10 @@ public record InterestShowPaginationApiResponse( String location, @Schema(description = "공연 포스터 이미지 주소") - String posterImageURL + String posterImageURL, + + @Schema(description = "조회한 데이터의 Cursor") + CursorApiResponse cursor ) { public static InterestShowPaginationApiResponse from( @@ -39,13 +36,12 @@ public static InterestShowPaginationApiResponse from( ) { return InterestShowPaginationApiResponse.builder() .id(response.showId()) - .interestShowId(response.interestShowId()) - .interestedAt(response.interestedAt()) .title(response.title()) .startAt(DateTimeUtil.formatDate(response.startAt())) .endAt(DateTimeUtil.formatDate(response.endAt())) .location(response.location()) .posterImageURL(response.posterImageURL()) + .cursor(CursorApiResponse.toCursorResponse(response.interestShowId(), response.interestedAt())) .build(); } } diff --git a/app/api/show-api/src/main/java/com/example/show/controller/dto/response/ShowPaginationApiParam.java b/app/api/show-api/src/main/java/com/example/show/controller/dto/response/ShowPaginationApiParam.java index 11590c22..3a4aa186 100644 --- a/app/api/show-api/src/main/java/com/example/show/controller/dto/response/ShowPaginationApiParam.java +++ b/app/api/show-api/src/main/java/com/example/show/controller/dto/response/ShowPaginationApiParam.java @@ -2,15 +2,15 @@ import com.example.show.service.dto.response.ShowPaginationServiceResponse; import io.swagger.v3.oas.annotations.media.Schema; -import java.util.UUID; import lombok.Builder; +import org.example.dto.response.CursorApiResponse; import org.example.util.DateTimeUtil; @Builder public record ShowPaginationApiParam( - @Schema(description = "공연 ID") - UUID id, + @Schema(description = "공연 Cursor") + CursorApiResponse cursor, @Schema(description = "공연 이름") String title, @@ -30,7 +30,7 @@ public record ShowPaginationApiParam( public static ShowPaginationApiParam from(ShowPaginationServiceResponse response) { return ShowPaginationApiParam.builder() - .id(response.id()) + .cursor(CursorApiResponse.toCursorId(response.id())) .title(response.title()) .location(response.location()) .posterImageURL(response.image()) diff --git a/app/api/show-api/src/main/java/com/example/show/controller/dto/usershow/response/NumberOfInterestShowApiResponse.java b/app/api/show-api/src/main/java/com/example/show/controller/dto/usershow/response/NumberOfInterestShowApiResponse.java new file mode 100644 index 00000000..4e04d526 --- /dev/null +++ b/app/api/show-api/src/main/java/com/example/show/controller/dto/usershow/response/NumberOfInterestShowApiResponse.java @@ -0,0 +1,15 @@ +package com.example.show.controller.dto.usershow.response; + + +import com.example.show.service.dto.usershow.response.NumberOfInterestShowServiceResponse; + +public record NumberOfInterestShowApiResponse( + long count +) { + + public static NumberOfInterestShowApiResponse from( + NumberOfInterestShowServiceResponse response + ) { + return new NumberOfInterestShowApiResponse(response.count()); + } +} diff --git a/app/api/show-api/src/main/java/com/example/show/controller/dto/usershow/response/NumberOfTicketingAlertApiResponse.java b/app/api/show-api/src/main/java/com/example/show/controller/dto/usershow/response/NumberOfTicketingAlertApiResponse.java new file mode 100644 index 00000000..11732343 --- /dev/null +++ b/app/api/show-api/src/main/java/com/example/show/controller/dto/usershow/response/NumberOfTicketingAlertApiResponse.java @@ -0,0 +1,15 @@ +package com.example.show.controller.dto.usershow.response; + + +import com.example.show.service.dto.usershow.response.NumberOfTicketingAlertServiceResponse; + +public record NumberOfTicketingAlertApiResponse( + long count +) { + + public static NumberOfTicketingAlertApiResponse from( + NumberOfTicketingAlertServiceResponse response + ) { + return new NumberOfTicketingAlertApiResponse(response.count()); + } +} diff --git a/app/api/show-api/src/main/java/com/example/show/service/ShowService.java b/app/api/show-api/src/main/java/com/example/show/service/ShowService.java index ae8c9435..b44e267c 100644 --- a/app/api/show-api/src/main/java/com/example/show/service/ShowService.java +++ b/app/api/show-api/src/main/java/com/example/show/service/ShowService.java @@ -1,42 +1,18 @@ package com.example.show.service; import com.example.component.ViewCountComponent; -import com.example.publish.MessagePublisher; -import com.example.publish.message.TicketingAlertsToReserveServiceMessage; -import com.example.show.controller.vo.TicketingApiType; -import com.example.show.error.ShowError; -import com.example.show.service.dto.param.ShowAlertPaginationServiceParam; import com.example.show.service.dto.param.ShowSearchPaginationServiceParam; -import com.example.show.service.dto.request.InterestShowPaginationServiceRequest; -import com.example.show.service.dto.request.ShowAlertPaginationServiceRequest; -import com.example.show.service.dto.request.ShowInterestServiceRequest; import com.example.show.service.dto.request.ShowPaginationServiceRequest; import com.example.show.service.dto.request.ShowSearchPaginationServiceRequest; -import com.example.show.service.dto.request.TicketingAlertReservationServiceRequest; -import com.example.show.service.dto.response.InterestShowPaginationServiceResponse; import com.example.show.service.dto.response.ShowDetailServiceResponse; -import com.example.show.service.dto.response.ShowInterestServiceResponse; import com.example.show.service.dto.response.ShowPaginationServiceResponse; -import com.example.show.service.dto.response.TerminatedTicketingShowCountServiceResponse; -import com.example.show.service.dto.response.TicketingAlertReservationAvailabilityServiceResponse; -import com.example.show.service.dto.response.TicketingAlertReservationServiceResponse; -import com.example.show.service.dto.response.TicketingAlertReservationStatusServiceResponse; import java.time.LocalDateTime; import java.util.List; -import java.util.Map; import java.util.UUID; -import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.example.dto.response.PaginationServiceResponse; -import org.example.dto.show.response.ShowAlertPaginationDomainResponse; import org.example.dto.show.response.ShowDetailDomainResponse; -import org.example.entity.InterestShow; -import org.example.entity.TicketingAlert; -import org.example.entity.show.Show; -import org.example.entity.show.ShowTicketingTime; -import org.example.exception.BusinessException; -import org.example.usecase.TicketingAlertUseCase; -import org.example.usecase.UserShowUseCase; +import org.example.usecase.interest.InterestShowUseCase; import org.example.usecase.show.ShowUseCase; import org.springframework.stereotype.Service; @@ -45,16 +21,14 @@ public class ShowService { private final ShowUseCase showUseCase; - private final TicketingAlertUseCase ticketingAlertUseCase; - private final UserShowUseCase userShowUseCase; - private final MessagePublisher messagePublisher; + private final InterestShowUseCase interestShowUseCase; private final ViewCountComponent viewCountComponent; public ShowDetailServiceResponse getShow(UUID userId, UUID showId, String viewIdentifier) { ShowDetailDomainResponse showDetail = showUseCase.findShowDetail(showId); boolean isInterested = - userId != null && userShowUseCase.findInterestShow(showId, userId).isPresent(); + userId != null && interestShowUseCase.findInterestShow(showId, userId).isPresent(); if (viewCountComponent.validateViewCount(showId, viewIdentifier)) { showUseCase.view(showId); @@ -92,115 +66,4 @@ public PaginationServiceResponse findShows( response.hasNext() ); } - - public PaginationServiceResponse findInterestShows( - InterestShowPaginationServiceRequest request - ) { - var interestShows = userShowUseCase.findInterestShows(request.toDomainRequest()); - List showIds = interestShows.data().stream().map(InterestShow::getShowId).toList(); - Map showById = showUseCase.findShowsInIds(showIds).stream() - .collect(Collectors.toMap(Show::getId, s -> s)); - - return PaginationServiceResponse.of( - interestShows.data().stream() - .map(interestShow -> InterestShowPaginationServiceResponse.from( - showById.get(interestShow.getShowId()), - interestShow - )) - .toList(), - interestShows.hasNext() - ); - } - - public ShowInterestServiceResponse interest(ShowInterestServiceRequest request) { - Show show = showUseCase.findShowOrThrowNoSuchElementException(request.showId()); - - return ShowInterestServiceResponse.from( - userShowUseCase.interest(request.toDomainRequest(show.getId())) - ); - } - - public TicketingAlertReservationServiceResponse findAlertsReservations( - UUID userId, - UUID showId, - TicketingApiType type - ) { - var ticketingAt = showUseCase - .findTicketingAlertReservation(showId, type.toDomainType()) - .getTicketingAt(); - - var reservedAlerts = ticketingAlertUseCase.findTicketingAlerts(userId, showId) - .stream() - .map(TicketingAlert::getAlertTime) - .toList(); - - var status = TicketingAlertReservationStatusServiceResponse.as( - reservedAlerts, - ticketingAt - ); - var availability = TicketingAlertReservationAvailabilityServiceResponse.as(ticketingAt); - - return TicketingAlertReservationServiceResponse.as(status, availability); - } - - public void alertReservation( - TicketingAlertReservationServiceRequest ticketingAlertReservationRequest - ) { - ShowTicketingTime showTicketingTime = showUseCase.findTicketingTimeWithShow( - ticketingAlertReservationRequest.showId(), - ticketingAlertReservationRequest.type().toDomainType() - ); - - if (showTicketingTime.getTicketingAt().isBefore(LocalDateTime.now())) { - throw new BusinessException(ShowError.TICKETING_ALERT_RESERVED_ERROR); - } - - var domainResponse = ticketingAlertUseCase.alertReservation( - ticketingAlertReservationRequest.toDomainRequest( - showTicketingTime.getShow().getTitle(), - showTicketingTime.getTicketingAt() - ) - ); - messagePublisher.publishTicketingReservation( - "ticketingAlert", - TicketingAlertsToReserveServiceMessage.from(domainResponse) - ); - } - - public PaginationServiceResponse findAlertShows( - ShowAlertPaginationServiceRequest request - ) { - List ticketingAlerts = ticketingAlertUseCase.findTicketingAlertsByUserId( - request.userId()); - List showIdsToAlert = ticketingAlerts.stream() - .map(TicketingAlert::getShowId) - .distinct() - .toList(); - - ShowAlertPaginationDomainResponse alertShows = showUseCase.findAlertShows( - request.toDomainRequest(showIdsToAlert, LocalDateTime.now())); - - return PaginationServiceResponse.of(alertShows.data().stream() - .map(ShowAlertPaginationServiceParam::from) - .toList(), - alertShows.hasNext() - ); - } - - public TerminatedTicketingShowCountServiceResponse countTerminatedTicketingShow(UUID userId) { - List ticketingAlerts = ticketingAlertUseCase.findTicketingAlertsByUserId( - userId); - List showIdsToAlert = ticketingAlerts.stream() - .map(TicketingAlert::getShowId) - .distinct() - .toList(); - - if (showIdsToAlert.isEmpty()) { - return TerminatedTicketingShowCountServiceResponse.noCount(); - } - - return TerminatedTicketingShowCountServiceResponse.from( - showUseCase.findTerminatedTicketingShowsCount(showIdsToAlert, LocalDateTime.now()) - ); - } } diff --git a/app/api/show-api/src/main/java/com/example/show/service/UserShowService.java b/app/api/show-api/src/main/java/com/example/show/service/UserShowService.java new file mode 100644 index 00000000..6c7d7cf1 --- /dev/null +++ b/app/api/show-api/src/main/java/com/example/show/service/UserShowService.java @@ -0,0 +1,169 @@ +package com.example.show.service; + +import com.example.publish.MessagePublisher; +import com.example.publish.message.TicketingAlertsToReserveServiceMessage; +import com.example.show.controller.vo.TicketingApiType; +import com.example.show.error.ShowError; +import com.example.show.service.dto.param.ShowAlertPaginationServiceParam; +import com.example.show.service.dto.request.InterestShowPaginationServiceRequest; +import com.example.show.service.dto.request.ShowAlertPaginationServiceRequest; +import com.example.show.service.dto.request.ShowInterestServiceRequest; +import com.example.show.service.dto.request.TicketingAlertReservationServiceRequest; +import com.example.show.service.dto.response.InterestShowPaginationServiceResponse; +import com.example.show.service.dto.response.ShowInterestServiceResponse; +import com.example.show.service.dto.response.TerminatedTicketingShowCountServiceResponse; +import com.example.show.service.dto.response.TicketingAlertReservationAvailabilityServiceResponse; +import com.example.show.service.dto.response.TicketingAlertReservationServiceResponse; +import com.example.show.service.dto.response.TicketingAlertReservationStatusServiceResponse; +import com.example.show.service.dto.usershow.response.NumberOfInterestShowServiceResponse; +import com.example.show.service.dto.usershow.response.NumberOfTicketingAlertServiceResponse; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.example.dto.response.PaginationServiceResponse; +import org.example.dto.show.response.ShowAlertPaginationDomainResponse; +import org.example.entity.InterestShow; +import org.example.entity.TicketingAlert; +import org.example.entity.show.Show; +import org.example.entity.show.ShowTicketingTime; +import org.example.exception.BusinessException; +import org.example.usecase.interest.InterestShowUseCase; +import org.example.usecase.show.ShowUseCase; +import org.example.usecase.ticketing.TicketingAlertUseCase; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class UserShowService { + + private final ShowUseCase showUseCase; + private final TicketingAlertUseCase ticketingAlertUseCase; + private final InterestShowUseCase interestShowUseCase; + private final MessagePublisher messagePublisher; + + public ShowInterestServiceResponse interest(ShowInterestServiceRequest request) { + Show show = showUseCase.findShowOrThrowNoSuchElementException(request.showId()); + + return ShowInterestServiceResponse.from( + interestShowUseCase.interest(request.toDomainRequest(show.getId())) + ); + } + + public PaginationServiceResponse findInterestShows( + InterestShowPaginationServiceRequest request + ) { + var interestShows = interestShowUseCase.findInterestShows(request.toDomainRequest()); + List showIds = interestShows.data().stream().map(InterestShow::getShowId).toList(); + Map showById = showUseCase.findShowsInIds(showIds).stream() + .collect(Collectors.toMap(Show::getId, s -> s)); + + return PaginationServiceResponse.of( + interestShows.data().stream() + .map(interestShow -> InterestShowPaginationServiceResponse.from( + showById.get(interestShow.getShowId()), + interestShow + )) + .toList(), + interestShows.hasNext() + ); + } + + public NumberOfInterestShowServiceResponse countInterestShows(UUID uuid) { + return NumberOfInterestShowServiceResponse.from( + interestShowUseCase.countInterestShows(uuid) + ); + } + + public void alertReservation( + TicketingAlertReservationServiceRequest ticketingAlertReservationRequest + ) { + ShowTicketingTime showTicketingTime = showUseCase.findTicketingTimeWithShow( + ticketingAlertReservationRequest.showId(), + ticketingAlertReservationRequest.type().toDomainType() + ); + + if (showTicketingTime.getTicketingAt().isBefore(LocalDateTime.now())) { + throw new BusinessException(ShowError.TICKETING_ALERT_RESERVED_ERROR); + } + + var domainResponse = ticketingAlertUseCase.alertReservation( + ticketingAlertReservationRequest.toDomainRequest( + showTicketingTime.getShow().getTitle(), + showTicketingTime.getTicketingAt() + ) + ); + messagePublisher.publishTicketingReservation( + "ticketingAlert", + TicketingAlertsToReserveServiceMessage.from(domainResponse) + ); + } + + public PaginationServiceResponse findAlertShows( + ShowAlertPaginationServiceRequest request + ) { + List ticketingAlerts = ticketingAlertUseCase.findTicketingAlertsByUserId( + request.userId()); + List showIdsToAlert = ticketingAlerts.stream() + .map(TicketingAlert::getShowId) + .distinct() + .toList(); + + ShowAlertPaginationDomainResponse alertShows = showUseCase.findAlertShows( + request.toDomainRequest(showIdsToAlert, LocalDateTime.now())); + + return PaginationServiceResponse.of(alertShows.data().stream() + .map(ShowAlertPaginationServiceParam::from) + .toList(), + alertShows.hasNext() + ); + } + + public TicketingAlertReservationServiceResponse findAlertsReservations( + UUID userId, + UUID showId, + TicketingApiType type + ) { + var ticketingAt = showUseCase + .findTicketingAlertReservation(showId, type.toDomainType()) + .getTicketingAt(); + + var reservedAlerts = ticketingAlertUseCase.findTicketingAlerts(userId, showId) + .stream() + .map(TicketingAlert::getAlertTime) + .toList(); + + var status = TicketingAlertReservationStatusServiceResponse.as( + reservedAlerts, + ticketingAt + ); + var availability = TicketingAlertReservationAvailabilityServiceResponse.as(ticketingAt); + + return TicketingAlertReservationServiceResponse.as(status, availability); + } + + public NumberOfTicketingAlertServiceResponse countAlertShows(UUID userId, LocalDateTime now) { + long numberOfTicketingAlert = ticketingAlertUseCase.countAlertShows(userId, now); + + return NumberOfTicketingAlertServiceResponse.from(numberOfTicketingAlert); + } + + public TerminatedTicketingShowCountServiceResponse countTerminatedTicketingShow(UUID userId) { + List ticketingAlerts = ticketingAlertUseCase.findTicketingAlertsByUserId( + userId); + List showIdsToAlert = ticketingAlerts.stream() + .map(TicketingAlert::getShowId) + .distinct() + .toList(); + + if (showIdsToAlert.isEmpty()) { + return TerminatedTicketingShowCountServiceResponse.noCount(); + } + + return TerminatedTicketingShowCountServiceResponse.from( + showUseCase.findTerminatedTicketingShowsCount(showIdsToAlert, LocalDateTime.now()) + ); + } +} diff --git a/app/api/user-api/src/main/java/org/example/service/dto/response/NumberOfInterestShowServiceResponse.java b/app/api/show-api/src/main/java/com/example/show/service/dto/usershow/response/NumberOfInterestShowServiceResponse.java similarity index 79% rename from app/api/user-api/src/main/java/org/example/service/dto/response/NumberOfInterestShowServiceResponse.java rename to app/api/show-api/src/main/java/com/example/show/service/dto/usershow/response/NumberOfInterestShowServiceResponse.java index fbbd1c50..711bccbb 100644 --- a/app/api/user-api/src/main/java/org/example/service/dto/response/NumberOfInterestShowServiceResponse.java +++ b/app/api/show-api/src/main/java/com/example/show/service/dto/usershow/response/NumberOfInterestShowServiceResponse.java @@ -1,4 +1,4 @@ -package org.example.service.dto.response; +package com.example.show.service.dto.usershow.response; public record NumberOfInterestShowServiceResponse( long count diff --git a/app/api/user-api/src/main/java/org/example/service/dto/response/NumberOfTicketingAlertServiceResponse.java b/app/api/show-api/src/main/java/com/example/show/service/dto/usershow/response/NumberOfTicketingAlertServiceResponse.java similarity index 79% rename from app/api/user-api/src/main/java/org/example/service/dto/response/NumberOfTicketingAlertServiceResponse.java rename to app/api/show-api/src/main/java/com/example/show/service/dto/usershow/response/NumberOfTicketingAlertServiceResponse.java index 5b33ad33..9497e09e 100644 --- a/app/api/user-api/src/main/java/org/example/service/dto/response/NumberOfTicketingAlertServiceResponse.java +++ b/app/api/show-api/src/main/java/com/example/show/service/dto/usershow/response/NumberOfTicketingAlertServiceResponse.java @@ -1,4 +1,4 @@ -package org.example.service.dto.response; +package com.example.show.service.dto.usershow.response; public record NumberOfTicketingAlertServiceResponse( long count diff --git a/app/api/show-api/src/test/java/artist/service/ArtistServiceTest.java b/app/api/show-api/src/test/java/artist/service/ArtistServiceTest.java index b4a5b2d9..3c0369be 100644 --- a/app/api/show-api/src/test/java/artist/service/ArtistServiceTest.java +++ b/app/api/show-api/src/test/java/artist/service/ArtistServiceTest.java @@ -23,10 +23,9 @@ import org.example.entity.artist.Artist; import org.example.fixture.ArtistSubscriptionFixture; import org.example.fixture.domain.ArtistFixture; -import org.example.usecase.ArtistSubscriptionUseCase; -import org.example.usecase.UserShowUseCase; -import org.example.usecase.UserUseCase; import org.example.usecase.artist.ArtistUseCase; +import org.example.usecase.subscription.ArtistSubscriptionUseCase; +import org.example.usecase.user.UserUseCase; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -36,14 +35,12 @@ class ArtistServiceTest { private final ArtistSubscriptionUseCase artistSubscriptionUseCase = mock( ArtistSubscriptionUseCase.class ); - private final UserShowUseCase userShowUseCase = mock(UserShowUseCase.class); private final UserUseCase userUseCase = mock(UserUseCase.class); private final MessagePublisher messagePublisher = mock(MessagePublisher.class); private final ArtistService artistService = new ArtistService( artistUseCase, artistSubscriptionUseCase, - userShowUseCase, userUseCase, messagePublisher ); diff --git a/app/api/show-api/src/test/java/genre/service/GenreServiceTest.java b/app/api/show-api/src/test/java/genre/service/GenreServiceTest.java index f9a0b3b2..18f4a142 100644 --- a/app/api/show-api/src/test/java/genre/service/GenreServiceTest.java +++ b/app/api/show-api/src/test/java/genre/service/GenreServiceTest.java @@ -22,9 +22,9 @@ import org.example.entity.genre.Genre; import org.example.fixture.GenreSubscriptionFixture; import org.example.fixture.domain.GenreFixture; -import org.example.usecase.GenreSubscriptionUseCase; -import org.example.usecase.UserUseCase; import org.example.usecase.genre.GenreUseCase; +import org.example.usecase.subscription.GenreSubscriptionUseCase; +import org.example.usecase.user.UserUseCase; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/app/api/show-api/src/test/java/show/service/ShowServiceTest.java b/app/api/show-api/src/test/java/show/service/ShowServiceTest.java index 78fd4631..2b931818 100644 --- a/app/api/show-api/src/test/java/show/service/ShowServiceTest.java +++ b/app/api/show-api/src/test/java/show/service/ShowServiceTest.java @@ -7,12 +7,10 @@ import static org.mockito.Mockito.verify; import com.example.component.ViewCountComponent; -import com.example.publish.MessagePublisher; import com.example.show.service.ShowService; import java.util.UUID; import org.assertj.core.api.SoftAssertions; -import org.example.usecase.TicketingAlertUseCase; -import org.example.usecase.UserShowUseCase; +import org.example.usecase.interest.InterestShowUseCase; import org.example.usecase.show.ShowUseCase; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -22,15 +20,11 @@ class ShowServiceTest { private final ShowUseCase showUseCase = mock(ShowUseCase.class); - private final UserShowUseCase userShowUseCase = mock(UserShowUseCase.class); - private final TicketingAlertUseCase ticketingAlertUseCase = mock(TicketingAlertUseCase.class); - private final MessagePublisher messagePublisher = mock(MessagePublisher.class); + private final InterestShowUseCase interestShowUseCase = mock(InterestShowUseCase.class); private final ViewCountComponent viewCountComponent = mock(ViewCountComponent.class); private final ShowService showService = new ShowService( showUseCase, - ticketingAlertUseCase, - userShowUseCase, - messagePublisher, + interestShowUseCase, viewCountComponent ); diff --git a/app/api/user-api/src/main/java/org/example/controller/UserShowController.java b/app/api/user-api/src/main/java/org/example/controller/UserShowController.java deleted file mode 100644 index 72a50a84..00000000 --- a/app/api/user-api/src/main/java/org/example/controller/UserShowController.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.example.controller; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import java.time.LocalDateTime; -import lombok.RequiredArgsConstructor; -import org.example.controller.dto.response.NumberOfInterestShowApiResponse; -import org.example.controller.dto.response.NumberOfSubscribedArtistApiResponse; -import org.example.controller.dto.response.NumberOfSubscribedGenreApiResponse; -import org.example.controller.dto.response.NumberOfTicketingAlertApiResponse; -import org.example.security.dto.AuthenticatedUser; -import org.example.service.UserShowService; -import org.springframework.http.ResponseEntity; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/api/v1/users") -@Tag(name = "유저 공연") -public class UserShowController { - - private final UserShowService userShowService; - - @GetMapping("/shows/alerts/count") - @Operation(summary = "알림 설정한 공연 개수") - public ResponseEntity getNumberOfAlertShow( - @AuthenticationPrincipal AuthenticatedUser user - ) { - LocalDateTime now = LocalDateTime.now(); - return ResponseEntity.ok( - NumberOfTicketingAlertApiResponse.from( - userShowService.countAlertShows(user.userId(), now) - ) - ); - } - - @GetMapping("/artists/subscriptions/count") - @Operation(summary = "구독한 아티스트 수") - public ResponseEntity getNumberOfSubscribedArtist( - @AuthenticationPrincipal AuthenticatedUser user - ) { - return ResponseEntity.ok( - NumberOfSubscribedArtistApiResponse.from( - userShowService.countSubscribedArtists(user.userId()) - ) - ); - } - - @GetMapping("/genres/subscriptions/count") - @Operation(summary = "구독한 장르 수") - public ResponseEntity getNumberOfSubscribedGenre( - @AuthenticationPrincipal AuthenticatedUser user - ) { - return ResponseEntity.ok( - NumberOfSubscribedGenreApiResponse.from( - userShowService.countSubscribedGenres(user.userId()) - ) - ); - } - - @GetMapping("/shows/interests/count") - @Operation(summary = "관심 공연 개수") - public ResponseEntity getNumberOfInterestShow( - @AuthenticationPrincipal AuthenticatedUser user - ) { - return ResponseEntity.ok( - NumberOfInterestShowApiResponse.from( - userShowService.countInterestShows(user.userId()) - ) - ); - } -} diff --git a/app/api/user-api/src/main/java/org/example/controller/dto/response/NumberOfInterestShowApiResponse.java b/app/api/user-api/src/main/java/org/example/controller/dto/response/NumberOfInterestShowApiResponse.java deleted file mode 100644 index 13256dea..00000000 --- a/app/api/user-api/src/main/java/org/example/controller/dto/response/NumberOfInterestShowApiResponse.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.example.controller.dto.response; - -import org.example.service.dto.response.NumberOfInterestShowServiceResponse; - -public record NumberOfInterestShowApiResponse( - long count -) { - - public static NumberOfInterestShowApiResponse from(NumberOfInterestShowServiceResponse response) { - return new NumberOfInterestShowApiResponse(response.count()); - } -} diff --git a/app/api/user-api/src/main/java/org/example/controller/dto/response/NumberOfSubscribedArtistApiResponse.java b/app/api/user-api/src/main/java/org/example/controller/dto/response/NumberOfSubscribedArtistApiResponse.java deleted file mode 100644 index 7901df75..00000000 --- a/app/api/user-api/src/main/java/org/example/controller/dto/response/NumberOfSubscribedArtistApiResponse.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.example.controller.dto.response; - -import org.example.service.dto.response.NumberOfSubscribedArtistServiceResponse; - -public record NumberOfSubscribedArtistApiResponse( - long count -) { - - public static NumberOfSubscribedArtistApiResponse from(NumberOfSubscribedArtistServiceResponse response) { - return new NumberOfSubscribedArtistApiResponse(response.count()); - } -} diff --git a/app/api/user-api/src/main/java/org/example/controller/dto/response/NumberOfSubscribedGenreApiResponse.java b/app/api/user-api/src/main/java/org/example/controller/dto/response/NumberOfSubscribedGenreApiResponse.java deleted file mode 100644 index 9ac46b98..00000000 --- a/app/api/user-api/src/main/java/org/example/controller/dto/response/NumberOfSubscribedGenreApiResponse.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.example.controller.dto.response; - -import org.example.service.dto.response.NumberOfSubscribedGenreServiceResponse; - -public record NumberOfSubscribedGenreApiResponse( - long count -) { - - public static NumberOfSubscribedGenreApiResponse from(NumberOfSubscribedGenreServiceResponse response) { - return new NumberOfSubscribedGenreApiResponse(response.count()); - } -} diff --git a/app/api/user-api/src/main/java/org/example/controller/dto/response/NumberOfTicketingAlertApiResponse.java b/app/api/user-api/src/main/java/org/example/controller/dto/response/NumberOfTicketingAlertApiResponse.java deleted file mode 100644 index 48dda393..00000000 --- a/app/api/user-api/src/main/java/org/example/controller/dto/response/NumberOfTicketingAlertApiResponse.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.example.controller.dto.response; - -import org.example.service.dto.response.NumberOfTicketingAlertServiceResponse; - -public record NumberOfTicketingAlertApiResponse( - long count -) { - - public static NumberOfTicketingAlertApiResponse from(NumberOfTicketingAlertServiceResponse response) { - return new NumberOfTicketingAlertApiResponse(response.count()); - } -} diff --git a/app/api/user-api/src/main/java/org/example/service/AdminService.java b/app/api/user-api/src/main/java/org/example/service/AdminService.java index 60f75d66..cae95ab2 100644 --- a/app/api/user-api/src/main/java/org/example/service/AdminService.java +++ b/app/api/user-api/src/main/java/org/example/service/AdminService.java @@ -2,7 +2,7 @@ import lombok.RequiredArgsConstructor; import org.example.service.dto.request.AdminLoginServiceRequest; -import org.example.usecase.AdminUseCase; +import org.example.usecase.admin.AdminUseCase; import org.springframework.stereotype.Service; @Service diff --git a/app/api/user-api/src/main/java/org/example/service/UserService.java b/app/api/user-api/src/main/java/org/example/service/UserService.java index 133bfe1d..2ac878e6 100644 --- a/app/api/user-api/src/main/java/org/example/service/UserService.java +++ b/app/api/user-api/src/main/java/org/example/service/UserService.java @@ -16,7 +16,7 @@ import org.example.service.dto.request.ReissueServiceRequest; import org.example.service.dto.request.WithdrawalServiceRequest; import org.example.service.dto.response.UserProfileServiceResponse; -import org.example.usecase.UserUseCase; +import org.example.usecase.user.UserUseCase; import org.springframework.stereotype.Service; @Service diff --git a/app/api/user-api/src/main/java/org/example/service/UserShowService.java b/app/api/user-api/src/main/java/org/example/service/UserShowService.java deleted file mode 100644 index e1ab40d0..00000000 --- a/app/api/user-api/src/main/java/org/example/service/UserShowService.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.example.service; - -import java.time.LocalDateTime; -import java.util.UUID; -import lombok.RequiredArgsConstructor; -import org.example.service.dto.response.NumberOfInterestShowServiceResponse; -import org.example.service.dto.response.NumberOfSubscribedArtistServiceResponse; -import org.example.service.dto.response.NumberOfSubscribedGenreServiceResponse; -import org.example.service.dto.response.NumberOfTicketingAlertServiceResponse; -import org.example.usecase.UserShowUseCase; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class UserShowService { - - private final UserShowUseCase userShowUseCase; - - public NumberOfTicketingAlertServiceResponse countAlertShows(UUID userId, LocalDateTime now) { - long numberOfTicketingAlert = userShowUseCase.countAlertShows(userId, now); - - return NumberOfTicketingAlertServiceResponse.from(numberOfTicketingAlert); - } - - public NumberOfSubscribedArtistServiceResponse countSubscribedArtists(UUID userId) { - return NumberOfSubscribedArtistServiceResponse.from( - userShowUseCase.countSubscribedArtists(userId) - ); - } - - public NumberOfSubscribedGenreServiceResponse countSubscribedGenres(UUID uuid) { - return NumberOfSubscribedGenreServiceResponse.from( - userShowUseCase.countSubscribedGenres(uuid) - ); - } - - public NumberOfInterestShowServiceResponse countInterestShows(UUID uuid) { - return NumberOfInterestShowServiceResponse.from( - userShowUseCase.countInterestShows(uuid) - ); - } -} diff --git a/app/api/user-api/src/test/java/org/example/service/UserServiceTest.java b/app/api/user-api/src/test/java/org/example/service/UserServiceTest.java index 44b60d8b..1d14e7a8 100644 --- a/app/api/user-api/src/test/java/org/example/service/UserServiceTest.java +++ b/app/api/user-api/src/test/java/org/example/service/UserServiceTest.java @@ -15,7 +15,7 @@ import org.example.security.dto.UserParam; import org.example.security.token.JWTGenerator; import org.example.security.token.TokenProcessor; -import org.example.usecase.UserUseCase; +import org.example.usecase.user.UserUseCase; import org.example.vo.SocialLoginApiType; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/app/domain/user-domain/src/main/java/org/example/repository/interest/InterestShowQuerydslRepository.java b/app/domain/user-domain/src/main/java/org/example/repository/interest/InterestShowQuerydslRepository.java index 8e891acc..afdbed88 100644 --- a/app/domain/user-domain/src/main/java/org/example/repository/interest/InterestShowQuerydslRepository.java +++ b/app/domain/user-domain/src/main/java/org/example/repository/interest/InterestShowQuerydslRepository.java @@ -1,13 +1,11 @@ package org.example.repository.interest; -import java.time.LocalDateTime; -import java.util.UUID; import org.example.dto.request.InterestShowPaginationDomainRequest; import org.example.dto.response.InterestShowPaginationDomainResponse; public interface InterestShowQuerydslRepository { - InterestShowPaginationDomainResponse findInterestShowList(InterestShowPaginationDomainRequest request); - - long countValidTicketingAlerts(UUID userId, LocalDateTime now); + InterestShowPaginationDomainResponse findInterestShowList( + InterestShowPaginationDomainRequest request + ); } diff --git a/app/domain/user-domain/src/main/java/org/example/repository/interest/InterestShowQuerydslRepositoryImpl.java b/app/domain/user-domain/src/main/java/org/example/repository/interest/InterestShowQuerydslRepositoryImpl.java index 2c3c9010..465ed1ed 100644 --- a/app/domain/user-domain/src/main/java/org/example/repository/interest/InterestShowQuerydslRepositoryImpl.java +++ b/app/domain/user-domain/src/main/java/org/example/repository/interest/InterestShowQuerydslRepositoryImpl.java @@ -1,12 +1,9 @@ package org.example.repository.interest; import static org.example.entity.QInterestShow.interestShow; -import static org.example.entity.QTicketingAlert.ticketingAlert; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; -import java.time.LocalDateTime; -import java.util.UUID; import lombok.RequiredArgsConstructor; import org.example.dto.request.InterestShowPaginationDomainRequest; import org.example.dto.response.InterestShowPaginationDomainResponse; @@ -42,21 +39,9 @@ public InterestShowPaginationDomainResponse findInterestShowList( .build(); } - @Override - public long countValidTicketingAlerts(UUID userId, LocalDateTime now) { - Long result = jpaQueryFactory.select(ticketingAlert.showId.countDistinct()) - .from(ticketingAlert) - .where( - ticketingAlert.isDeleted.isFalse() - .and(ticketingAlert.userId.eq(userId)) - .and(ticketingAlert.alertTime.gt(now)) - ) - .fetchOne(); - - return result == null ? 0 : result; - } - - private BooleanExpression getInterestShowPaginationConditions(InterestShowPaginationDomainRequest request) { + private BooleanExpression getInterestShowPaginationConditions( + InterestShowPaginationDomainRequest request + ) { BooleanExpression whereConditions = interestShow.userId.eq(request.userId()) .and(interestShow.isDeleted.isFalse()); diff --git a/app/domain/user-domain/src/main/java/org/example/repository/ticketing/TicketingAlertQuerydslRepository.java b/app/domain/user-domain/src/main/java/org/example/repository/ticketing/TicketingAlertQuerydslRepository.java index 7737e38b..439bac10 100644 --- a/app/domain/user-domain/src/main/java/org/example/repository/ticketing/TicketingAlertQuerydslRepository.java +++ b/app/domain/user-domain/src/main/java/org/example/repository/ticketing/TicketingAlertQuerydslRepository.java @@ -1,5 +1,9 @@ package org.example.repository.ticketing; +import java.time.LocalDateTime; +import java.util.UUID; + public interface TicketingAlertQuerydslRepository { + long countValidTicketingAlerts(UUID userId, LocalDateTime now); } diff --git a/app/domain/user-domain/src/main/java/org/example/repository/ticketing/TicketingAlertQuerydslRepositoryImpl.java b/app/domain/user-domain/src/main/java/org/example/repository/ticketing/TicketingAlertQuerydslRepositoryImpl.java index e499a01f..0633965f 100644 --- a/app/domain/user-domain/src/main/java/org/example/repository/ticketing/TicketingAlertQuerydslRepositoryImpl.java +++ b/app/domain/user-domain/src/main/java/org/example/repository/ticketing/TicketingAlertQuerydslRepositoryImpl.java @@ -1,6 +1,10 @@ package org.example.repository.ticketing; +import static org.example.entity.QTicketingAlert.ticketingAlert; + import com.querydsl.jpa.impl.JPAQueryFactory; +import java.time.LocalDateTime; +import java.util.UUID; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @@ -10,4 +14,17 @@ public class TicketingAlertQuerydslRepositoryImpl implements TicketingAlertQuery private final JPAQueryFactory jpaQueryFactory; + @Override + public long countValidTicketingAlerts(UUID userId, LocalDateTime now) { + Long result = jpaQueryFactory.select(ticketingAlert.showId.countDistinct()) + .from(ticketingAlert) + .where( + ticketingAlert.isDeleted.isFalse() + .and(ticketingAlert.userId.eq(userId)) + .and(ticketingAlert.alertTime.gt(now)) + ) + .fetchOne(); + + return result == null ? 0 : result; + } } diff --git a/app/domain/user-domain/src/main/java/org/example/usecase/AdminUseCase.java b/app/domain/user-domain/src/main/java/org/example/usecase/admin/AdminUseCase.java similarity index 95% rename from app/domain/user-domain/src/main/java/org/example/usecase/AdminUseCase.java rename to app/domain/user-domain/src/main/java/org/example/usecase/admin/AdminUseCase.java index 8dfe79cc..f435ba71 100644 --- a/app/domain/user-domain/src/main/java/org/example/usecase/AdminUseCase.java +++ b/app/domain/user-domain/src/main/java/org/example/usecase/admin/AdminUseCase.java @@ -1,4 +1,4 @@ -package org.example.usecase; +package org.example.usecase.admin; import lombok.RequiredArgsConstructor; import org.example.entity.Admin; diff --git a/app/domain/user-domain/src/main/java/org/example/usecase/UserShowUseCase.java b/app/domain/user-domain/src/main/java/org/example/usecase/interest/InterestShowUseCase.java similarity index 58% rename from app/domain/user-domain/src/main/java/org/example/usecase/UserShowUseCase.java rename to app/domain/user-domain/src/main/java/org/example/usecase/interest/InterestShowUseCase.java index 7f600e91..d134d0c2 100644 --- a/app/domain/user-domain/src/main/java/org/example/usecase/UserShowUseCase.java +++ b/app/domain/user-domain/src/main/java/org/example/usecase/interest/InterestShowUseCase.java @@ -1,32 +1,28 @@ -package org.example.usecase; +package org.example.usecase.interest; -import java.time.LocalDateTime; -import java.util.List; import java.util.Optional; import java.util.UUID; import lombok.RequiredArgsConstructor; import org.example.dto.request.InterestShowDomainRequest; import org.example.dto.request.InterestShowPaginationDomainRequest; import org.example.dto.response.InterestShowPaginationDomainResponse; -import org.example.entity.ArtistSubscription; import org.example.entity.InterestShow; import org.example.repository.interest.InterestShowRepository; -import org.example.repository.subscription.artistsubscription.ArtistSubscriptionRepository; -import org.example.repository.subscription.genresubscription.GenreSubscriptionRepository; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @Component @RequiredArgsConstructor -public class UserShowUseCase { +public class InterestShowUseCase { private final InterestShowRepository interestShowRepository; - private final ArtistSubscriptionRepository artistSubscriptionRepository; - private final GenreSubscriptionRepository genreSubscriptionRepository; @Transactional public InterestShow interest(InterestShowDomainRequest request) { - Optional optInterestShow = findInterestShowByShowIdAndUserId(request.showId(), request.userId()); + Optional optInterestShow = findInterestShowByShowIdAndUserId( + request.showId(), + request.userId() + ); if (optInterestShow.isEmpty()) { return interestShowRepository.save( @@ -47,28 +43,11 @@ public Optional findInterestShow(UUID showId, UUID userId) { return interestShowRepository.findByShowIdAndUserIdAndIsDeletedFalse(showId, userId); } - public List findArtistSubscriptionByUserId(UUID userId) { - return artistSubscriptionRepository.findAllByUserIdAndIsDeletedFalse(userId); - } - - public InterestShowPaginationDomainResponse findInterestShows(InterestShowPaginationDomainRequest request) { + public InterestShowPaginationDomainResponse findInterestShows( + InterestShowPaginationDomainRequest request) { return interestShowRepository.findInterestShowList(request); } - public long countAlertShows(UUID userId, LocalDateTime now) { - return interestShowRepository.countValidTicketingAlerts(userId, now); - } - - public long countSubscribedArtists(UUID userId) { - Long result = artistSubscriptionRepository.countByUserIdAndIsDeletedFalse(userId); - return result == null ? 0 : result; - } - - public long countSubscribedGenres(UUID userId) { - Long result = genreSubscriptionRepository.countByUserIdAndIsDeletedFalse(userId); - return result == null ? 0 : result; - } - public long countInterestShows(UUID userId) { Long result = interestShowRepository.countInterestShowByUserIdAndIsDeletedFalse(userId); return result == null ? 0 : result; diff --git a/app/domain/user-domain/src/main/java/org/example/usecase/ArtistSubscriptionUseCase.java b/app/domain/user-domain/src/main/java/org/example/usecase/subscription/ArtistSubscriptionUseCase.java similarity index 84% rename from app/domain/user-domain/src/main/java/org/example/usecase/ArtistSubscriptionUseCase.java rename to app/domain/user-domain/src/main/java/org/example/usecase/subscription/ArtistSubscriptionUseCase.java index b2c3a3d2..980f1ce8 100644 --- a/app/domain/user-domain/src/main/java/org/example/usecase/ArtistSubscriptionUseCase.java +++ b/app/domain/user-domain/src/main/java/org/example/usecase/subscription/ArtistSubscriptionUseCase.java @@ -1,4 +1,4 @@ -package org.example.usecase; +package org.example.usecase.subscription; import java.util.ArrayList; import java.util.List; @@ -59,4 +59,14 @@ public List unsubscribe(List artistIds, UUID userId) { return filteredSubscription; } + + public List findArtistSubscriptionByUserId(UUID userId) { + return artistSubscriptionRepository.findAllByUserIdAndIsDeletedFalse(userId); + } + + + public long countSubscribedArtists(UUID userId) { + Long result = artistSubscriptionRepository.countByUserIdAndIsDeletedFalse(userId); + return result == null ? 0 : result; + } } diff --git a/app/domain/user-domain/src/main/java/org/example/usecase/GenreSubscriptionUseCase.java b/app/domain/user-domain/src/main/java/org/example/usecase/subscription/GenreSubscriptionUseCase.java similarity index 90% rename from app/domain/user-domain/src/main/java/org/example/usecase/GenreSubscriptionUseCase.java rename to app/domain/user-domain/src/main/java/org/example/usecase/subscription/GenreSubscriptionUseCase.java index ea840696..2a7fdb3a 100644 --- a/app/domain/user-domain/src/main/java/org/example/usecase/GenreSubscriptionUseCase.java +++ b/app/domain/user-domain/src/main/java/org/example/usecase/subscription/GenreSubscriptionUseCase.java @@ -1,4 +1,4 @@ -package org.example.usecase; +package org.example.usecase.subscription; import java.util.ArrayList; import java.util.List; @@ -59,4 +59,9 @@ public List unsubscribe(List genreIds, UUID userId) { return filteredSubscriptions; } + + public long countSubscribedGenres(UUID userId) { + Long result = genreSubscriptionRepository.countByUserIdAndIsDeletedFalse(userId); + return result == null ? 0 : result; + } } diff --git a/app/domain/user-domain/src/main/java/org/example/usecase/TicketingAlertUseCase.java b/app/domain/user-domain/src/main/java/org/example/usecase/ticketing/TicketingAlertUseCase.java similarity index 96% rename from app/domain/user-domain/src/main/java/org/example/usecase/TicketingAlertUseCase.java rename to app/domain/user-domain/src/main/java/org/example/usecase/ticketing/TicketingAlertUseCase.java index 62b429d9..5653e8f0 100644 --- a/app/domain/user-domain/src/main/java/org/example/usecase/TicketingAlertUseCase.java +++ b/app/domain/user-domain/src/main/java/org/example/usecase/ticketing/TicketingAlertUseCase.java @@ -1,4 +1,4 @@ -package org.example.usecase; +package org.example.usecase.ticketing; import java.time.LocalDateTime; import java.util.List; @@ -34,6 +34,10 @@ public List findTicketingAlertsByUserId(UUID userId) { return ticketingAlertRepository.findAllByUserIdAndIsDeletedFalse(userId); } + public long countAlertShows(UUID userId, LocalDateTime now) { + return ticketingAlertRepository.countValidTicketingAlerts(userId, now); + } + @Transactional public TicketingAlertsDomainResponse alertReservation( TicketingAlertReservationDomainRequest ticketingAlertReservation diff --git a/app/domain/user-domain/src/main/java/org/example/usecase/UserUseCase.java b/app/domain/user-domain/src/main/java/org/example/usecase/user/UserUseCase.java similarity index 98% rename from app/domain/user-domain/src/main/java/org/example/usecase/UserUseCase.java rename to app/domain/user-domain/src/main/java/org/example/usecase/user/UserUseCase.java index b9dafa1d..9ef0727f 100644 --- a/app/domain/user-domain/src/main/java/org/example/usecase/UserUseCase.java +++ b/app/domain/user-domain/src/main/java/org/example/usecase/user/UserUseCase.java @@ -1,4 +1,4 @@ -package org.example.usecase; +package org.example.usecase.user; import java.util.NoSuchElementException; import java.util.UUID;