From 8300d4fd2ecac97e018c7150a425d6118c09ba8c Mon Sep 17 00:00:00 2001 From: devmizz Date: Sun, 21 Jul 2024 03:35:23 +0900 Subject: [PATCH 1/6] feat: Update entity name --- .../{SubscribeArtist.java => ArtistSubscription.java} | 9 ++++----- .../{SubscribeGenre.java => GenreSubscription.java} | 8 ++++---- 2 files changed, 8 insertions(+), 9 deletions(-) rename app/domain/user-domain/src/main/java/org/example/entity/{SubscribeArtist.java => ArtistSubscription.java} (66%) rename app/domain/user-domain/src/main/java/org/example/entity/{SubscribeGenre.java => GenreSubscription.java} (66%) diff --git a/app/domain/user-domain/src/main/java/org/example/entity/SubscribeArtist.java b/app/domain/user-domain/src/main/java/org/example/entity/ArtistSubscription.java similarity index 66% rename from app/domain/user-domain/src/main/java/org/example/entity/SubscribeArtist.java rename to app/domain/user-domain/src/main/java/org/example/entity/ArtistSubscription.java index 0417c6d4..507908d8 100644 --- a/app/domain/user-domain/src/main/java/org/example/entity/SubscribeArtist.java +++ b/app/domain/user-domain/src/main/java/org/example/entity/ArtistSubscription.java @@ -1,6 +1,5 @@ package org.example.entity; - import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Table; @@ -12,13 +11,13 @@ @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -@Table(name = "subscribe_artist") -public class SubscribeArtist extends BaseEntity { +@Table(name = "artist_subscription") +public class ArtistSubscription extends BaseEntity { - @Column(name = "user_id", nullable = false) + @Column(nullable = false) private UUID userId; - @Column(name = "artist_id", nullable = false) + @Column(nullable = false) private UUID artistId; } diff --git a/app/domain/user-domain/src/main/java/org/example/entity/SubscribeGenre.java b/app/domain/user-domain/src/main/java/org/example/entity/GenreSubscription.java similarity index 66% rename from app/domain/user-domain/src/main/java/org/example/entity/SubscribeGenre.java rename to app/domain/user-domain/src/main/java/org/example/entity/GenreSubscription.java index 466f3fcd..67b5bd55 100644 --- a/app/domain/user-domain/src/main/java/org/example/entity/SubscribeGenre.java +++ b/app/domain/user-domain/src/main/java/org/example/entity/GenreSubscription.java @@ -11,12 +11,12 @@ @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -@Table(name = "subscribe_genre") -public class SubscribeGenre extends BaseEntity { +@Table(name = "genre_subscription") +public class GenreSubscription extends BaseEntity { - @Column(name = "user_id", nullable = false) + @Column(nullable = false) private UUID userId; - @Column(name = "genre_id", nullable = false) + @Column(nullable = false) private UUID genreId; } From 7d0294a370b9e5ff169b438b6fc36ff93437acbb Mon Sep 17 00:00:00 2001 From: devmizz Date: Sun, 21 Jul 2024 23:12:24 +0900 Subject: [PATCH 2/6] feat: Subscribe artist --- .../org/example/config/SecurityConfig.java | 3 +- app/api/show-api/build.gradle | 2 +- .../artist/controller/ArtistController.java | 15 +++- .../request/ArtistSubscriptionApiRequest.java | 4 ++ .../ArtistSubscriptionApiResponse.java | 14 ++++ .../artist/error/ArtistSubscriptionError.java | 28 ++++++++ .../example/artist/service/ArtistService.java | 69 +++++++++++++++++++ .../ArtistSubscriptionServiceRequest.java | 11 +++ .../ArtistSubscriptionServiceResponse.java | 12 ++++ .../com/example/config/ShowApiConfig.java | 3 +- app/build.gradle | 2 + .../org/example/entity/artist/Artist.java | 10 ++- .../artist/ArtistQuerydslRepository.java | 3 + .../artist/ArtistQuerydslRepositoryImpl.java | 38 ++++++---- .../example/usecase/artist/ArtistUseCase.java | 5 +- .../example/ShowDomainTestConfiguration.java | 11 +++ .../example}/domain/ShowTest.java | 4 +- .../org/example/fixture/ArtistFixture.java | 19 +++++ .../example}/fixture/ShowFixture.java | 2 +- .../artist/ArtistRepositoryTest.java | 59 ++++++++++++++++ .../application-show-domain-test.yml | 10 +++ .../org/example/config/UserDomainConfig.java | 7 +- .../example/entity/ArtistSubscription.java | 6 ++ .../java/org/example/entity/SocialLogin.java | 2 +- .../ArtistSubscriptionRepository.java | 11 +++ .../usecase/ArtistSubscriptionUseCase.java | 23 +++++++ 26 files changed, 344 insertions(+), 29 deletions(-) create mode 100644 app/api/show-api/src/main/java/com/example/artist/controller/dto/response/ArtistSubscriptionApiResponse.java create mode 100644 app/api/show-api/src/main/java/com/example/artist/error/ArtistSubscriptionError.java create mode 100644 app/api/show-api/src/main/java/com/example/artist/service/ArtistService.java create mode 100644 app/api/show-api/src/main/java/com/example/artist/service/dto/request/ArtistSubscriptionServiceRequest.java create mode 100644 app/api/show-api/src/main/java/com/example/artist/service/dto/response/ArtistSubscriptionServiceResponse.java create mode 100644 app/domain/show-domain/src/test/java/org/example/ShowDomainTestConfiguration.java rename app/domain/show-domain/src/test/java/{show => org/example}/domain/ShowTest.java (95%) create mode 100644 app/domain/show-domain/src/test/java/org/example/fixture/ArtistFixture.java rename app/domain/show-domain/src/test/java/{show => org/example}/fixture/ShowFixture.java (96%) create mode 100644 app/domain/show-domain/src/test/java/org/example/repository/artist/ArtistRepositoryTest.java create mode 100644 app/domain/show-domain/src/test/resources/application-show-domain-test.yml create mode 100644 app/domain/user-domain/src/main/java/org/example/repository/subscription/ArtistSubscriptionRepository.java create mode 100644 app/domain/user-domain/src/main/java/org/example/usecase/ArtistSubscriptionUseCase.java diff --git a/app/api/common-api/src/main/java/org/example/config/SecurityConfig.java b/app/api/common-api/src/main/java/org/example/config/SecurityConfig.java index ada5bc1b..daf60463 100644 --- a/app/api/common-api/src/main/java/org/example/config/SecurityConfig.java +++ b/app/api/common-api/src/main/java/org/example/config/SecurityConfig.java @@ -84,7 +84,8 @@ private RequestMatcher getMatcherForUserAndAdmin() { antMatcher(HttpMethod.POST, "/api/v1/users/withdrawal"), antMatcher(HttpMethod.POST, "/api/v1/shows/**/interest"), antMatcher(HttpMethod.POST, "/api/v1/shows/**/alert"), - antMatcher(HttpMethod.POST, "/api/v1/genres/**") + antMatcher(HttpMethod.POST, "/api/v1/genres/**"), + antMatcher(HttpMethod.POST, "/api/v1/artists/subscribe") ); } } diff --git a/app/api/show-api/build.gradle b/app/api/show-api/build.gradle index 74b92a9d..92bcfeb6 100644 --- a/app/api/show-api/build.gradle +++ b/app/api/show-api/build.gradle @@ -1,5 +1,5 @@ dependencies { implementation project(":app:domain:show-domain") - + implementation project(":app:domain:user-domain") implementation project(':app:api:common-api') } \ No newline at end of file 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 00aad86c..b0699381 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 @@ -5,13 +5,17 @@ import com.example.artist.controller.dto.request.ArtistUnsubscriptionApiRequest; import com.example.artist.controller.dto.response.ArtistPaginationApiResponse; import com.example.artist.controller.dto.response.ArtistSimpleApiResponse; +import com.example.artist.controller.dto.response.ArtistSubscriptionApiResponse; +import com.example.artist.service.ArtistService; 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.security.dto.AuthenticatedUser; 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.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -25,6 +29,8 @@ @Tag(name = "아티스트") public class ArtistController { + private final ArtistService artistService; + private String image = "https://thumb.mtstarnews.com/06/2023/06/2023062914274537673_1.jpg"; @GetMapping @@ -48,10 +54,15 @@ public ResponseEntity getArtists( @PostMapping("/subscribe") @Operation(summary = "구독하기") - public ResponseEntity bulkSubscribe( + public ResponseEntity subscribe( + @AuthenticationPrincipal AuthenticatedUser user, @Valid @RequestBody ArtistSubscriptionApiRequest request ) { - return ResponseEntity.noContent().build(); + return ResponseEntity.ok( + ArtistSubscriptionApiResponse.from( + artistService.subscribe(request.toServiceRequest(user.userId())) + ) + ); } @PostMapping("/unsubscribe") diff --git a/app/api/show-api/src/main/java/com/example/artist/controller/dto/request/ArtistSubscriptionApiRequest.java b/app/api/show-api/src/main/java/com/example/artist/controller/dto/request/ArtistSubscriptionApiRequest.java index f75de52c..9d93b831 100644 --- a/app/api/show-api/src/main/java/com/example/artist/controller/dto/request/ArtistSubscriptionApiRequest.java +++ b/app/api/show-api/src/main/java/com/example/artist/controller/dto/request/ArtistSubscriptionApiRequest.java @@ -1,5 +1,6 @@ package com.example.artist.controller.dto.request; +import com.example.artist.service.dto.request.ArtistSubscriptionServiceRequest; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import java.util.List; @@ -11,4 +12,7 @@ public record ArtistSubscriptionApiRequest( List artistIds ) { + public ArtistSubscriptionServiceRequest toServiceRequest(UUID userId) { + return new ArtistSubscriptionServiceRequest(artistIds, userId); + } } diff --git a/app/api/show-api/src/main/java/com/example/artist/controller/dto/response/ArtistSubscriptionApiResponse.java b/app/api/show-api/src/main/java/com/example/artist/controller/dto/response/ArtistSubscriptionApiResponse.java new file mode 100644 index 00000000..c6d003de --- /dev/null +++ b/app/api/show-api/src/main/java/com/example/artist/controller/dto/response/ArtistSubscriptionApiResponse.java @@ -0,0 +1,14 @@ +package com.example.artist.controller.dto.response; + +import com.example.artist.service.dto.response.ArtistSubscriptionServiceResponse; +import java.util.List; +import java.util.UUID; + +public record ArtistSubscriptionApiResponse( + List successSubscriptionArtistIds +) { + + public static ArtistSubscriptionApiResponse from(ArtistSubscriptionServiceResponse response) { + return new ArtistSubscriptionApiResponse(response.successSubscriptionArtistIds()); + } +} diff --git a/app/api/show-api/src/main/java/com/example/artist/error/ArtistSubscriptionError.java b/app/api/show-api/src/main/java/com/example/artist/error/ArtistSubscriptionError.java new file mode 100644 index 00000000..133143d9 --- /dev/null +++ b/app/api/show-api/src/main/java/com/example/artist/error/ArtistSubscriptionError.java @@ -0,0 +1,28 @@ +package com.example.artist.error; + +import org.example.exception.BusinessError; + +public enum ArtistSubscriptionError implements BusinessError { + + ARTIST_NOT_EXIST { + @Override + public int getHttpStatus() { + return 404; + } + + @Override + public String getErrorCode() { + return "ASB-001"; + } + + @Override + public String getClientMessage() { + return "구독하려는 아티스트가 존재하지 않습니다."; + } + + @Override + public String getLogMessage() { + return "요청으로 들어온 아티스트 ID에 해당하는 아티스트가 존재하지 않습니다."; + } + } +} 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 new file mode 100644 index 00000000..15c43c85 --- /dev/null +++ b/app/api/show-api/src/main/java/com/example/artist/service/ArtistService.java @@ -0,0 +1,69 @@ +package com.example.artist.service; + +import com.example.artist.service.dto.request.ArtistSubscriptionServiceRequest; +import com.example.artist.service.dto.response.ArtistSubscriptionServiceResponse; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.example.entity.ArtistSubscription; +import org.example.entity.artist.Artist; +import org.example.usecase.ArtistSubscriptionUseCase; +import org.example.usecase.artist.ArtistUseCase; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +@Slf4j +public class ArtistService { + + private final ArtistUseCase artistUseCase; + private final ArtistSubscriptionUseCase artistSubscriptionUseCase; + + public ArtistSubscriptionServiceResponse subscribe(ArtistSubscriptionServiceRequest request) { + List existArtists = artistUseCase.findAllArtistInIds(request.artistIds()); + + List newArtistSubscription = getNewArtistSubscription( + existArtists, + request.userId() + ); + + artistSubscriptionUseCase.subscribe(newArtistSubscription); + + return ArtistSubscriptionServiceResponse.builder() + .successSubscriptionArtistIds( + newArtistSubscription.stream() + .map(ArtistSubscription::getArtistId) + .toList() + ) + .build(); + } + + private List getNewArtistSubscription( + List artists, + UUID userId + ) { + var existSubscriptionByArtistId = getExistSubscriptionByArtistId(userId); + return artists.stream() + .filter(artist -> !existSubscriptionByArtistId.containsKey(artist.getId())) + .map(artist -> + ArtistSubscription.builder() + .artistId(artist.getId()) + .userId(userId) + .build() + ).toList(); + } + + private Map getExistSubscriptionByArtistId(UUID userId) { + return artistSubscriptionUseCase.findSubscriptionList(userId) + .stream() + .collect( + Collectors.toMap( + ArtistSubscription::getArtistId, + artistSubscription -> artistSubscription + ) + ); + } +} diff --git a/app/api/show-api/src/main/java/com/example/artist/service/dto/request/ArtistSubscriptionServiceRequest.java b/app/api/show-api/src/main/java/com/example/artist/service/dto/request/ArtistSubscriptionServiceRequest.java new file mode 100644 index 00000000..273ff7be --- /dev/null +++ b/app/api/show-api/src/main/java/com/example/artist/service/dto/request/ArtistSubscriptionServiceRequest.java @@ -0,0 +1,11 @@ +package com.example.artist.service.dto.request; + +import java.util.List; +import java.util.UUID; + +public record ArtistSubscriptionServiceRequest( + List artistIds, + UUID userId +) { + +} diff --git a/app/api/show-api/src/main/java/com/example/artist/service/dto/response/ArtistSubscriptionServiceResponse.java b/app/api/show-api/src/main/java/com/example/artist/service/dto/response/ArtistSubscriptionServiceResponse.java new file mode 100644 index 00000000..23a3b620 --- /dev/null +++ b/app/api/show-api/src/main/java/com/example/artist/service/dto/response/ArtistSubscriptionServiceResponse.java @@ -0,0 +1,12 @@ +package com.example.artist.service.dto.response; + +import java.util.List; +import java.util.UUID; +import lombok.Builder; + +@Builder +public record ArtistSubscriptionServiceResponse( + List successSubscriptionArtistIds +) { + +} diff --git a/app/api/show-api/src/main/java/com/example/config/ShowApiConfig.java b/app/api/show-api/src/main/java/com/example/config/ShowApiConfig.java index 910f5cda..4b694d0d 100644 --- a/app/api/show-api/src/main/java/com/example/config/ShowApiConfig.java +++ b/app/api/show-api/src/main/java/com/example/config/ShowApiConfig.java @@ -1,12 +1,13 @@ package com.example.config; import org.example.config.ShowDomainConfig; +import org.example.config.UserDomainConfig; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration -@Import(ShowDomainConfig.class) +@Import({ShowDomainConfig.class, UserDomainConfig.class}) @ComponentScan(basePackages = "com.example") public class ShowApiConfig { diff --git a/app/build.gradle b/app/build.gradle index edbd5a0f..75d92760 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,6 +12,8 @@ allprojects { dependencies { implementation project(":common") + implementation 'com.fasterxml.jackson.core:jackson-core:2.17.2' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' } } diff --git a/app/domain/show-domain/src/main/java/org/example/entity/artist/Artist.java b/app/domain/show-domain/src/main/java/org/example/entity/artist/Artist.java index ef63a668..dd22bdf0 100644 --- a/app/domain/show-domain/src/main/java/org/example/entity/artist/Artist.java +++ b/app/domain/show-domain/src/main/java/org/example/entity/artist/Artist.java @@ -40,8 +40,14 @@ public class Artist extends BaseEntity { private ArtistType artistType; @Builder - private Artist(String koreanName, String englishName, String image, String country, ArtistGender artistGender, - ArtistType artistType) { + private Artist( + String koreanName, + String englishName, + String image, + String country, + ArtistGender artistGender, + ArtistType artistType + ) { this.koreanName = koreanName; this.englishName = englishName; this.image = image; diff --git a/app/domain/show-domain/src/main/java/org/example/repository/artist/ArtistQuerydslRepository.java b/app/domain/show-domain/src/main/java/org/example/repository/artist/ArtistQuerydslRepository.java index 251df911..6f2d2a5a 100644 --- a/app/domain/show-domain/src/main/java/org/example/repository/artist/ArtistQuerydslRepository.java +++ b/app/domain/show-domain/src/main/java/org/example/repository/artist/ArtistQuerydslRepository.java @@ -5,6 +5,7 @@ import java.util.UUID; import org.example.dto.artist.response.ArtistDetailResponse; import org.example.dto.artist.response.ArtistKoreanNameResponse; +import org.example.entity.artist.Artist; public interface ArtistQuerydslRepository { @@ -13,4 +14,6 @@ public interface ArtistQuerydslRepository { Optional findArtistWithGenreNamesById(UUID id); List findAllArtistKoreanName(); + + List findAllInIds(List ids); } diff --git a/app/domain/show-domain/src/main/java/org/example/repository/artist/ArtistQuerydslRepositoryImpl.java b/app/domain/show-domain/src/main/java/org/example/repository/artist/ArtistQuerydslRepositoryImpl.java index 478811ea..19a89bc6 100644 --- a/app/domain/show-domain/src/main/java/org/example/repository/artist/ArtistQuerydslRepositoryImpl.java +++ b/app/domain/show-domain/src/main/java/org/example/repository/artist/ArtistQuerydslRepositoryImpl.java @@ -16,6 +16,7 @@ import lombok.RequiredArgsConstructor; import org.example.dto.artist.response.ArtistDetailResponse; import org.example.dto.artist.response.ArtistKoreanNameResponse; +import org.example.entity.artist.Artist; import org.springframework.stereotype.Repository; @Repository @@ -68,6 +69,28 @@ public Optional findArtistWithGenreNamesById(UUID id) { ); } + @Override + public List findAllArtistKoreanName() { + return jpaQueryFactory + .select( + Projections.constructor( + ArtistKoreanNameResponse.class, + artist.id, + artist.koreanName + ) + ) + .from(artist) + .fetch(); + } + + @Override + public List findAllInIds(List ids) { + return jpaQueryFactory + .selectFrom(artist) + .where(artist.id.in(ids)) + .fetch(); + } + private JPAQuery createArtistJoinArtistGenreAndGenreQuery() { return jpaQueryFactory .selectFrom(artist) @@ -83,19 +106,4 @@ private BooleanExpression isArtistGenreEqualArtistIdAndIsDeletedFalse() { private BooleanExpression isGenreEqualArtistIdAndIsDeletedFalse() { return artistGenre.genreId.eq(genre.id).and(genre.isDeleted.isFalse()); } - - - @Override - public List findAllArtistKoreanName() { - return jpaQueryFactory - .select( - Projections.constructor( - ArtistKoreanNameResponse.class, - artist.id, - artist.koreanName - ) - ) - .from(artist) - .fetch(); - } } diff --git a/app/domain/show-domain/src/main/java/org/example/usecase/artist/ArtistUseCase.java b/app/domain/show-domain/src/main/java/org/example/usecase/artist/ArtistUseCase.java index eed20d52..9b6ee237 100644 --- a/app/domain/show-domain/src/main/java/org/example/usecase/artist/ArtistUseCase.java +++ b/app/domain/show-domain/src/main/java/org/example/usecase/artist/ArtistUseCase.java @@ -46,6 +46,10 @@ public ArtistDetailResponse findArtistDetailById(UUID id) { .orElseThrow(() -> new BusinessException(ArtistError.ENTITY_NOT_FOUND_ERROR)); } + public List findAllArtistInIds(List ids) { + return artistRepository.findAllInIds(ids); + } + @Transactional public void updateArtist(UUID id, Artist newArtist, List newGenreIds) { Artist artist = findArtistById(id); @@ -85,6 +89,5 @@ private Artist findArtistById(UUID id) { return artistRepository.findById(id) .orElseThrow(() -> new BusinessException(ArtistError.ENTITY_NOT_FOUND_ERROR)); } - } diff --git a/app/domain/show-domain/src/test/java/org/example/ShowDomainTestConfiguration.java b/app/domain/show-domain/src/test/java/org/example/ShowDomainTestConfiguration.java new file mode 100644 index 00000000..71739379 --- /dev/null +++ b/app/domain/show-domain/src/test/java/org/example/ShowDomainTestConfiguration.java @@ -0,0 +1,11 @@ +package org.example; + +import org.example.config.ShowDomainConfig; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Import; + +@SpringBootApplication +@Import(value = {ShowDomainConfig.class}) +public class ShowDomainTestConfiguration { + +} diff --git a/app/domain/show-domain/src/test/java/show/domain/ShowTest.java b/app/domain/show-domain/src/test/java/org/example/domain/ShowTest.java similarity index 95% rename from app/domain/show-domain/src/test/java/show/domain/ShowTest.java rename to app/domain/show-domain/src/test/java/org/example/domain/ShowTest.java index ff610c88..87af209d 100644 --- a/app/domain/show-domain/src/test/java/show/domain/ShowTest.java +++ b/app/domain/show-domain/src/test/java/org/example/domain/ShowTest.java @@ -1,4 +1,4 @@ -package show.domain; +package org.example.domain; import static org.assertj.core.api.Assertions.assertThat; @@ -7,9 +7,9 @@ import org.example.entity.show.Show; import org.example.entity.show.ShowArtist; import org.example.entity.show.ShowGenre; +import org.example.fixture.ShowFixture; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import show.fixture.ShowFixture; class ShowTest { diff --git a/app/domain/show-domain/src/test/java/org/example/fixture/ArtistFixture.java b/app/domain/show-domain/src/test/java/org/example/fixture/ArtistFixture.java new file mode 100644 index 00000000..3274e712 --- /dev/null +++ b/app/domain/show-domain/src/test/java/org/example/fixture/ArtistFixture.java @@ -0,0 +1,19 @@ +package org.example.fixture; + +import org.example.entity.artist.Artist; +import org.example.entity.artist.ArtistGender; +import org.example.entity.artist.ArtistType; + +public class ArtistFixture { + + public static Artist test() { + return Artist.builder() + .koreanName("아이브") + .englishName("IVE") + .image("abc") + .country("KOREA") + .artistGender(ArtistGender.WOMAN) + .artistType(ArtistType.GROUP) + .build(); + } +} diff --git a/app/domain/show-domain/src/test/java/show/fixture/ShowFixture.java b/app/domain/show-domain/src/test/java/org/example/fixture/ShowFixture.java similarity index 96% rename from app/domain/show-domain/src/test/java/show/fixture/ShowFixture.java rename to app/domain/show-domain/src/test/java/org/example/fixture/ShowFixture.java index 06992606..7cf3d55f 100644 --- a/app/domain/show-domain/src/test/java/show/fixture/ShowFixture.java +++ b/app/domain/show-domain/src/test/java/org/example/fixture/ShowFixture.java @@ -1,4 +1,4 @@ -package show.fixture; +package org.example.fixture; import java.time.LocalDate; import org.example.entity.show.Show; diff --git a/app/domain/show-domain/src/test/java/org/example/repository/artist/ArtistRepositoryTest.java b/app/domain/show-domain/src/test/java/org/example/repository/artist/ArtistRepositoryTest.java new file mode 100644 index 00000000..490f86d0 --- /dev/null +++ b/app/domain/show-domain/src/test/java/org/example/repository/artist/ArtistRepositoryTest.java @@ -0,0 +1,59 @@ +package org.example.repository.artist; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import org.example.entity.artist.Artist; +import org.example.fixture.ArtistFixture; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.ActiveProfiles; + +@DataJpaTest +@ActiveProfiles("show-domain-test") +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +class ArtistRepositoryTest { + + @Autowired + private ArtistRepository artistRepository; + + @Test + @DisplayName("findAllInIds 메서드가 의도대로 동작하는지 확인한다.") + void find_all_in() { + var artists = artistRepository.saveAll( + List.of( + ArtistFixture.test(), + ArtistFixture.test() + ) + ); + + ArrayList ids = new ArrayList<>(artists.stream().map(Artist::getId).toList()); + ids.add(UUID.randomUUID()); + + List findArtists = Assertions.assertDoesNotThrow( + () -> artistRepository.findAllInIds(ids) + ); + + assertThat(findArtists).hasSize(2); + } + + @Test + @DisplayName("findAllInIds 메서드가 매칭되는 ID가 없을 때 빈 리스트를 반환한다.") + void find_all_in_no_match() { + + ArrayList ids = new ArrayList<>(); + ids.add(UUID.randomUUID()); + + List findArtists = Assertions.assertDoesNotThrow( + () -> artistRepository.findAllInIds(ids) + ); + + assertThat(findArtists).hasSize(0); + } +} \ No newline at end of file diff --git a/app/domain/show-domain/src/test/resources/application-show-domain-test.yml b/app/domain/show-domain/src/test/resources/application-show-domain-test.yml new file mode 100644 index 00000000..be5dcf9b --- /dev/null +++ b/app/domain/show-domain/src/test/resources/application-show-domain-test.yml @@ -0,0 +1,10 @@ +spring: + jpa: + hibernate: + ddl-auto: create + show-sql: true + datasource: + url: jdbc:postgresql://localhost:5432/yapp + username: yapp + password: yapp + driver-class-name: org.postgresql.Driver diff --git a/app/domain/user-domain/src/main/java/org/example/config/UserDomainConfig.java b/app/domain/user-domain/src/main/java/org/example/config/UserDomainConfig.java index c7c661a5..2d2fd338 100644 --- a/app/domain/user-domain/src/main/java/org/example/config/UserDomainConfig.java +++ b/app/domain/user-domain/src/main/java/org/example/config/UserDomainConfig.java @@ -8,8 +8,11 @@ @Configuration @ComponentScan(basePackages = "org.example") @EntityScan(basePackages = "org.example.entity") -@EnableJpaRepositories(basePackages = - {"org.example.repository.user", "org.example.repository.admin"}) +@EnableJpaRepositories(basePackages = { + "org.example.repository.user", + "org.example.repository.admin", + "org.example.repository.subscription" +}) public class UserDomainConfig { } diff --git a/app/domain/user-domain/src/main/java/org/example/entity/ArtistSubscription.java b/app/domain/user-domain/src/main/java/org/example/entity/ArtistSubscription.java index 507908d8..5bb4c604 100644 --- a/app/domain/user-domain/src/main/java/org/example/entity/ArtistSubscription.java +++ b/app/domain/user-domain/src/main/java/org/example/entity/ArtistSubscription.java @@ -5,6 +5,7 @@ import jakarta.persistence.Table; import java.util.UUID; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -20,4 +21,9 @@ public class ArtistSubscription extends BaseEntity { @Column(nullable = false) private UUID artistId; + @Builder + public ArtistSubscription(UUID userId, UUID artistId) { + this.userId = userId; + this.artistId = artistId; + } } diff --git a/app/domain/user-domain/src/main/java/org/example/entity/SocialLogin.java b/app/domain/user-domain/src/main/java/org/example/entity/SocialLogin.java index 75ad301a..c8cd060a 100644 --- a/app/domain/user-domain/src/main/java/org/example/entity/SocialLogin.java +++ b/app/domain/user-domain/src/main/java/org/example/entity/SocialLogin.java @@ -28,7 +28,7 @@ ) public class SocialLogin extends BaseEntity { - @Enumerated(EnumType.STRING) + @Enumerated(value = EnumType.STRING) @Column(nullable = false) private SocialLoginType socialLoginType; diff --git a/app/domain/user-domain/src/main/java/org/example/repository/subscription/ArtistSubscriptionRepository.java b/app/domain/user-domain/src/main/java/org/example/repository/subscription/ArtistSubscriptionRepository.java new file mode 100644 index 00000000..0de3e34f --- /dev/null +++ b/app/domain/user-domain/src/main/java/org/example/repository/subscription/ArtistSubscriptionRepository.java @@ -0,0 +1,11 @@ +package org.example.repository.subscription; + +import java.util.List; +import java.util.UUID; +import org.example.entity.ArtistSubscription; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ArtistSubscriptionRepository extends JpaRepository { + + List findByUserId(UUID userId); +} 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/ArtistSubscriptionUseCase.java new file mode 100644 index 00000000..97e067cb --- /dev/null +++ b/app/domain/user-domain/src/main/java/org/example/usecase/ArtistSubscriptionUseCase.java @@ -0,0 +1,23 @@ +package org.example.usecase; + +import java.util.List; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.example.entity.ArtistSubscription; +import org.example.repository.subscription.ArtistSubscriptionRepository; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class ArtistSubscriptionUseCase { + + private final ArtistSubscriptionRepository artistSubscriptionRepository; + + public void subscribe(List subscriptions) { + artistSubscriptionRepository.saveAll(subscriptions); + } + + public List findSubscriptionList(UUID userId) { + return artistSubscriptionRepository.findByUserId(userId); + } +} From 09852b6852370792fedf540049a42eafd9a28d2d Mon Sep 17 00:00:00 2001 From: devmizz Date: Mon, 22 Jul 2024 01:06:45 +0900 Subject: [PATCH 3/6] fix: Update ci script --- .github/workflows/showpot-dev-ci.yml | 2 +- .github/workflows/showpot-prod-ci.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/showpot-dev-ci.yml b/.github/workflows/showpot-dev-ci.yml index bad4ce7b..4846413e 100644 --- a/.github/workflows/showpot-dev-ci.yml +++ b/.github/workflows/showpot-dev-ci.yml @@ -38,7 +38,7 @@ jobs: spring.datasource.password: ${{ secrets.APPLICATION_DATASOURCE_PASSWORD }} - name: Build with Gradle Wrapper - run: ./gradlew clean build + run: ./gradlew clean build -Dspring.profiles.active=dev - name: Backend CI Discord Notification uses: sarisia/actions-status-discord@v1 diff --git a/.github/workflows/showpot-prod-ci.yml b/.github/workflows/showpot-prod-ci.yml index 8383143b..ca687568 100644 --- a/.github/workflows/showpot-prod-ci.yml +++ b/.github/workflows/showpot-prod-ci.yml @@ -38,7 +38,7 @@ jobs: spring.datasource.password: ${{ secrets.APPLICATION_DATASOURCE_PASSWORD }} - name: Build with Gradle Wrapper - run: ./gradlew clean build + run: ./gradlew clean build -Dspring.profiles.active=prod - name: Backend CI Discord Notification uses: sarisia/actions-status-discord@v1 From dda900416eb30d66f1add0ce09c270cb812cb36b Mon Sep 17 00:00:00 2001 From: devmizz Date: Mon, 22 Jul 2024 01:28:44 +0900 Subject: [PATCH 4/6] fix: Update test yml --- .../org/example/repository/artist/ArtistRepositoryTest.java | 2 -- .../{application-show-domain-test.yml => application.yml} | 0 2 files changed, 2 deletions(-) rename app/domain/show-domain/src/test/resources/{application-show-domain-test.yml => application.yml} (100%) diff --git a/app/domain/show-domain/src/test/java/org/example/repository/artist/ArtistRepositoryTest.java b/app/domain/show-domain/src/test/java/org/example/repository/artist/ArtistRepositoryTest.java index 490f86d0..52b28946 100644 --- a/app/domain/show-domain/src/test/java/org/example/repository/artist/ArtistRepositoryTest.java +++ b/app/domain/show-domain/src/test/java/org/example/repository/artist/ArtistRepositoryTest.java @@ -13,10 +13,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.test.context.ActiveProfiles; @DataJpaTest -@ActiveProfiles("show-domain-test") @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) class ArtistRepositoryTest { diff --git a/app/domain/show-domain/src/test/resources/application-show-domain-test.yml b/app/domain/show-domain/src/test/resources/application.yml similarity index 100% rename from app/domain/show-domain/src/test/resources/application-show-domain-test.yml rename to app/domain/show-domain/src/test/resources/application.yml From ed8adb4472fdbf0e36d20c463fe6404df9109a5e Mon Sep 17 00:00:00 2001 From: devmizz Date: Tue, 23 Jul 2024 23:58:32 +0900 Subject: [PATCH 5/6] =?UTF-8?q?feat:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BB=A8=ED=85=8C=EC=9D=B4=EB=84=88=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/build.gradle | 1 - app/build.gradle | 8 ++++++-- app/domain/build.gradle | 3 ++- .../repository/artist/ArtistRepositoryTest.java | 5 ++++- .../src/test/resources/application.yml | 8 ++++---- app/src/main/resources/logback-test.xml | 17 +++++++++++++++++ 6 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 app/src/main/resources/logback-test.xml diff --git a/app/api/build.gradle b/app/api/build.gradle index e3744ca7..090a078c 100644 --- a/app/api/build.gradle +++ b/app/api/build.gradle @@ -17,7 +17,6 @@ allprojects { implementation "org.springframework.boot:spring-boot-starter-web" implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-validation' - testImplementation "org.springframework.boot:spring-boot-starter-test" } } diff --git a/app/build.gradle b/app/build.gradle index 75d92760..6120748c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,12 @@ allprojects { dependencies { implementation project(":common") - implementation 'com.fasterxml.jackson.core:jackson-core:2.17.2' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' + + testImplementation "org.springframework.boot:spring-boot-starter-test" + testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1' + testImplementation 'org.testcontainers:testcontainers:1.20.0' + testImplementation 'org.testcontainers:junit-jupiter:1.20.0' + testImplementation "org.testcontainers:postgresql:1.20.0" } } diff --git a/app/domain/build.gradle b/app/domain/build.gradle index cfb74087..757d7abd 100644 --- a/app/domain/build.gradle +++ b/app/domain/build.gradle @@ -11,7 +11,8 @@ allprojects { annotationProcessor 'jakarta.annotation:jakarta.annotation-api' annotationProcessor 'jakarta.persistence:jakarta.persistence-api' - testImplementation "org.springframework.boot:spring-boot-starter-test" + implementation 'com.fasterxml.jackson.core:jackson-core:2.17.2' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' tasks.named('test') { useJUnitPlatform() diff --git a/app/domain/show-domain/src/test/java/org/example/repository/artist/ArtistRepositoryTest.java b/app/domain/show-domain/src/test/java/org/example/repository/artist/ArtistRepositoryTest.java index 52b28946..87372c70 100644 --- a/app/domain/show-domain/src/test/java/org/example/repository/artist/ArtistRepositoryTest.java +++ b/app/domain/show-domain/src/test/java/org/example/repository/artist/ArtistRepositoryTest.java @@ -12,10 +12,13 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.testcontainers.junit.jupiter.Testcontainers; @DataJpaTest -@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@Testcontainers +@AutoConfigureTestDatabase(replace = Replace.NONE) class ArtistRepositoryTest { @Autowired diff --git a/app/domain/show-domain/src/test/resources/application.yml b/app/domain/show-domain/src/test/resources/application.yml index be5dcf9b..b72bdc17 100644 --- a/app/domain/show-domain/src/test/resources/application.yml +++ b/app/domain/show-domain/src/test/resources/application.yml @@ -4,7 +4,7 @@ spring: ddl-auto: create show-sql: true datasource: - url: jdbc:postgresql://localhost:5432/yapp - username: yapp - password: yapp - driver-class-name: org.postgresql.Driver + driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver + url: jdbc:tc:postgresql:13:///test_container + username: root + password: root diff --git a/app/src/main/resources/logback-test.xml b/app/src/main/resources/logback-test.xml new file mode 100644 index 00000000..8c82c7af --- /dev/null +++ b/app/src/main/resources/logback-test.xml @@ -0,0 +1,17 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + + + + + + + + + + + + + \ No newline at end of file From 5fb7be674aee4c2afea74839ac8de3f970e14981 Mon Sep 17 00:00:00 2001 From: devmizz Date: Tue, 23 Jul 2024 23:59:23 +0900 Subject: [PATCH 6/6] =?UTF-8?q?feat:=20PR=20=EB=A6=AC=EB=B7=B0=20=EB=B0=98?= =?UTF-8?q?=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/example/usecase/ArtistSubscriptionUseCase.java | 2 ++ 1 file changed, 2 insertions(+) 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/ArtistSubscriptionUseCase.java index 97e067cb..95df7e2e 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/ArtistSubscriptionUseCase.java @@ -6,6 +6,7 @@ import org.example.entity.ArtistSubscription; import org.example.repository.subscription.ArtistSubscriptionRepository; import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; @Component @RequiredArgsConstructor @@ -13,6 +14,7 @@ public class ArtistSubscriptionUseCase { private final ArtistSubscriptionRepository artistSubscriptionRepository; + @Transactional public void subscribe(List subscriptions) { artistSubscriptionRepository.saveAll(subscriptions); }