Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Subscribe artist #52

Merged
merged 6 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/showpot-dev-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/showpot-prod-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion app/api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")
);
}
}
2 changes: 1 addition & 1 deletion app/api/show-api/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
dependencies {
implementation project(":app:domain:show-domain")

implementation project(":app:domain:user-domain")
implementation project(':app:api:common-api')
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -48,10 +54,15 @@ public ResponseEntity<ArtistPaginationApiResponse> getArtists(

@PostMapping("/subscribe")
@Operation(summary = "κ΅¬λ…ν•˜κΈ°")
public ResponseEntity<Void> bulkSubscribe(
public ResponseEntity<ArtistSubscriptionApiResponse> 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")
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -11,4 +12,7 @@ public record ArtistSubscriptionApiRequest(
List<UUID> artistIds
) {

public ArtistSubscriptionServiceRequest toServiceRequest(UUID userId) {
return new ArtistSubscriptionServiceRequest(artistIds, userId);
}
}
Original file line number Diff line number Diff line change
@@ -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<UUID> successSubscriptionArtistIds
) {

public static ArtistSubscriptionApiResponse from(ArtistSubscriptionServiceResponse response) {
return new ArtistSubscriptionApiResponse(response.successSubscriptionArtistIds());
}
}
Original file line number Diff line number Diff line change
@@ -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에 ν•΄λ‹Ήν•˜λŠ” μ•„ν‹°μŠ€νŠΈκ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.";
}
}
}
Original file line number Diff line number Diff line change
@@ -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<Artist> existArtists = artistUseCase.findAllArtistInIds(request.artistIds());

List<ArtistSubscription> newArtistSubscription = getNewArtistSubscription(
existArtists,
request.userId()
);

artistSubscriptionUseCase.subscribe(newArtistSubscription);

return ArtistSubscriptionServiceResponse.builder()
.successSubscriptionArtistIds(
newArtistSubscription.stream()
.map(ArtistSubscription::getArtistId)
.toList()
)
.build();
}

private List<ArtistSubscription> getNewArtistSubscription(
List<Artist> 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<UUID, ArtistSubscription> getExistSubscriptionByArtistId(UUID userId) {
return artistSubscriptionUseCase.findSubscriptionList(userId)
.stream()
.collect(
Collectors.toMap(
ArtistSubscription::getArtistId,
artistSubscription -> artistSubscription
)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.example.artist.service.dto.request;

import java.util.List;
import java.util.UUID;

public record ArtistSubscriptionServiceRequest(
List<UUID> artistIds,
UUID userId
) {

}
Original file line number Diff line number Diff line change
@@ -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<UUID> successSubscriptionArtistIds
) {

}
Original file line number Diff line number Diff line change
@@ -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 {

Expand Down
6 changes: 6 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ allprojects {

dependencies {
implementation project(":common")

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"
}
}

Expand Down
3 changes: 2 additions & 1 deletion app/domain/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand All @@ -13,4 +14,6 @@ public interface ArtistQuerydslRepository {
Optional<ArtistDetailResponse> findArtistWithGenreNamesById(UUID id);

List<ArtistKoreanNameResponse> findAllArtistKoreanName();

List<Artist> findAllInIds(List<UUID> ids);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -68,6 +69,28 @@ public Optional<ArtistDetailResponse> findArtistWithGenreNamesById(UUID id) {
);
}

@Override
public List<ArtistKoreanNameResponse> findAllArtistKoreanName() {
return jpaQueryFactory
.select(
Projections.constructor(
ArtistKoreanNameResponse.class,
artist.id,
artist.koreanName
)
)
.from(artist)
.fetch();
}

@Override
public List<Artist> findAllInIds(List<UUID> ids) {
return jpaQueryFactory
.selectFrom(artist)
.where(artist.id.in(ids))
.fetch();
}

private JPAQuery<?> createArtistJoinArtistGenreAndGenreQuery() {
return jpaQueryFactory
.selectFrom(artist)
Expand All @@ -83,19 +106,4 @@ private BooleanExpression isArtistGenreEqualArtistIdAndIsDeletedFalse() {
private BooleanExpression isGenreEqualArtistIdAndIsDeletedFalse() {
return artistGenre.genreId.eq(genre.id).and(genre.isDeleted.isFalse());
}


@Override
public List<ArtistKoreanNameResponse> findAllArtistKoreanName() {
return jpaQueryFactory
.select(
Projections.constructor(
ArtistKoreanNameResponse.class,
artist.id,
artist.koreanName
)
)
.from(artist)
.fetch();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ public ArtistDetailResponse findArtistDetailById(UUID id) {
.orElseThrow(() -> new BusinessException(ArtistError.ENTITY_NOT_FOUND_ERROR));
}

public List<Artist> findAllArtistInIds(List<UUID> ids) {
return artistRepository.findAllInIds(ids);
}

@Transactional
public void updateArtist(UUID id, Artist newArtist, List<UUID> newGenreIds) {
Artist artist = findArtistById(id);
Expand Down Expand Up @@ -85,6 +89,5 @@ private Artist findArtistById(UUID id) {
return artistRepository.findById(id)
.orElseThrow(() -> new BusinessException(ArtistError.ENTITY_NOT_FOUND_ERROR));
}

}

Original file line number Diff line number Diff line change
@@ -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 {

}
Loading
Loading