Skip to content

Commit

Permalink
Merge branch 'feat/#933' into glen/test1
Browse files Browse the repository at this point in the history
  • Loading branch information
seokjin8678 committed May 7, 2024
2 parents 5cfde01 + 22eac13 commit 119911e
Show file tree
Hide file tree
Showing 14 changed files with 663 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.festago.admin.application;

import com.festago.admin.repository.AdminFestivalIdResolverQueryDslRepository;
import com.festago.admin.repository.AdminStageIdResolverQueryDslRepository;
import com.festago.festival.application.FestivalQueryInfoArtistRenewService;
import com.festago.stage.application.StageQueryInfoService;
import java.time.LocalDate;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
public class AdminQueryInfoRenewalService {

private final FestivalQueryInfoArtistRenewService festivalQueryInfoArtistRenewService;
private final StageQueryInfoService stageQueryInfoService;
private final AdminStageIdResolverQueryDslRepository adminStageIdResolverQueryDslRepository;
private final AdminFestivalIdResolverQueryDslRepository adminFestivalIdResolverQueryDslRepository;

public void renewalByFestivalId(Long festivalId) {
festivalQueryInfoArtistRenewService.renewArtistInfo(festivalId);
adminStageIdResolverQueryDslRepository.findStageIdsByFestivalId(festivalId)
.forEach(stageQueryInfoService::renewalStageQueryInfo);
}

public void renewalByFestivalStartDatePeriod(LocalDate to, LocalDate end) {
List<Long> festivalIds = adminFestivalIdResolverQueryDslRepository.findFestivalIdsByStartDatePeriod(to, end);
log.info("{}๊ฐœ์˜ ์ถ•์ œ์— ๋Œ€ํ•ด QueryInfo๋ฅผ ์ƒˆ๋กœ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค.", festivalIds.size());
festivalIds.forEach(festivalQueryInfoArtistRenewService::renewArtistInfo);
adminStageIdResolverQueryDslRepository.findStageIdsByFestivalIdIn(festivalIds)
.forEach(stageQueryInfoService::renewalStageQueryInfo);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.festago.admin.dto.queryinfo;

import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;

public record QueryInfoRenewalFestivalPeriodV1Request(
@NotNull LocalDate to,
@NotNull LocalDate end
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.festago.admin.presentation.v1;

import com.festago.admin.application.AdminQueryInfoRenewalService;
import com.festago.admin.dto.queryinfo.QueryInfoRenewalFestivalPeriodV1Request;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/admin/api/v1/query-info/renewal")
@RequiredArgsConstructor
@Hidden
public class AdminQueryInfoRenewalV1Controller {

private final AdminQueryInfoRenewalService queryInfoRenewalService;

@PostMapping("/festival-id/{festivalId}")
public ResponseEntity<Void> renewalByFestivalId(
@PathVariable Long festivalId
) {
queryInfoRenewalService.renewalByFestivalId(festivalId);
return ResponseEntity.ok().build();
}

@PostMapping("/festival-period")
public ResponseEntity<Void> renewalByFestivalStartDatePeriod(
@RequestBody @Valid QueryInfoRenewalFestivalPeriodV1Request request
) {
queryInfoRenewalService.renewalByFestivalStartDatePeriod(request.to(), request.end());
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.festago.admin.repository;

import static com.festago.festival.domain.QFestival.festival;

import com.festago.common.querydsl.QueryDslRepositorySupport;
import com.festago.festival.domain.Festival;
import java.time.LocalDate;
import java.util.List;
import org.springframework.stereotype.Repository;

@Repository
public class AdminFestivalIdResolverQueryDslRepository extends QueryDslRepositorySupport {

public AdminFestivalIdResolverQueryDslRepository() {
super(Festival.class);
}

public List<Long> findFestivalIdsByStartDatePeriod(LocalDate to, LocalDate end) {
return select(festival.id)
.from(festival)
.where(festival.festivalDuration.startDate.goe(to)
.and(festival.festivalDuration.startDate.loe(end)))
.fetch();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.festago.admin.repository;

import static com.festago.festival.domain.QFestival.festival;
import static com.festago.stage.domain.QStage.stage;

import com.festago.common.querydsl.QueryDslRepositorySupport;
import com.festago.stage.domain.Stage;
import java.util.List;
import org.springframework.stereotype.Repository;

@Repository
public class AdminStageIdResolverQueryDslRepository extends QueryDslRepositorySupport {

public AdminStageIdResolverQueryDslRepository() {
super(Stage.class);
}

public List<Long> findStageIdsByFestivalId(Long festivalId) {
return select(stage.id)
.from(stage)
.innerJoin(festival).on(festival.id.eq(stage.festival.id))
.where(festival.id.eq(festivalId))
.fetch();
}

public List<Long> findStageIdsByFestivalIdIn(List<Long> festivalIds) {
return select(stage.id)
.from(stage)
.innerJoin(festival).on(festival.id.eq(stage.festival.id))
.where(festival.id.in(festivalIds))
.fetch();
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,9 @@
package com.festago.stage.application;

import com.festago.artist.domain.Artist;
import com.festago.artist.domain.ArtistsSerializer;
import com.festago.artist.repository.ArtistRepository;
import com.festago.common.exception.ErrorCode;
import com.festago.common.exception.InternalServerException;
import com.festago.common.exception.NotFoundException;
import com.festago.stage.domain.Stage;
import com.festago.stage.domain.StageQueryInfo;
import com.festago.stage.dto.event.StageCreatedEvent;
import com.festago.stage.dto.event.StageDeletedEvent;
import com.festago.stage.dto.event.StageUpdatedEvent;
import com.festago.stage.repository.StageArtistRepository;
import com.festago.stage.repository.StageQueryInfoRepository;
import java.util.List;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
Expand All @@ -27,49 +16,26 @@
@Slf4j
public class StageQueryInfoEventListener {

private final StageQueryInfoRepository stageQueryInfoRepository;
private final StageArtistRepository stageArtistRepository;
private final ArtistRepository artistRepository;
private final ArtistsSerializer serializer;
private final StageQueryInfoService stageQueryInfoService;

@EventListener
@Transactional(propagation = Propagation.MANDATORY)
public void stageCreatedEventHandler(StageCreatedEvent event) {
Stage stage = event.stage();
Long stageId = stage.getId();
List<Artist> artists = getStageArtists(stageId);
StageQueryInfo stageQueryInfo = StageQueryInfo.of(stageId, artists, serializer);
stageQueryInfoRepository.save(stageQueryInfo);
}

/**
* ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋กœ์ง์ด ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค๋ฉด ์˜ˆ์™ธ ๋˜์ง€๋Š” ๊ฒƒ์„ ๋‹ค์‹œ ์ƒ๊ฐํ•ด๋ณผ๊ฒƒ! (๋™๊ธฐ๋กœ ์‹คํ–‰๋˜๋ฉด ControllerAdvice์—์„œ ์ฒ˜๋ฆฌ๊ฐ€ ๋จ)
*/
private List<Artist> getStageArtists(Long stageId) {
Set<Long> artistIds = stageArtistRepository.findAllArtistIdByStageId(stageId);
List<Artist> artists = artistRepository.findByIdIn(artistIds);
if (artists.size() != artistIds.size()) {
log.error("StageArtist์— ์กด์žฌํ•˜์ง€ ์•Š์€ Artist๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. artistsIds=" + artistIds);
throw new InternalServerException(ErrorCode.ARTIST_NOT_FOUND);
}
return artists;
stageQueryInfoService.initialStageQueryInfo(stage.getId());
}

@EventListener
@Transactional(propagation = Propagation.MANDATORY)
public void stageUpdatedEventHandler(StageUpdatedEvent event) {
Stage stage = event.stage();
Long stageId = stage.getId();
List<Artist> artists = getStageArtists(stageId);
StageQueryInfo stageQueryInfo = stageQueryInfoRepository.findByStageId(stageId)
.orElseThrow(() -> new NotFoundException(ErrorCode.STAGE_NOT_FOUND));
stageQueryInfo.updateArtist(artists, serializer);
stageQueryInfoService.renewalStageQueryInfo(stage.getId());
}

@EventListener
@Transactional(propagation = Propagation.MANDATORY)
public void stageDeletedEventHandler(StageDeletedEvent event) {
Stage stage = event.stage();
stageQueryInfoRepository.deleteByStageId(stage.getId());
stageQueryInfoService.deleteStageQueryInfo(stage.getId());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.festago.stage.application;

import com.festago.artist.domain.Artist;
import com.festago.artist.domain.ArtistsSerializer;
import com.festago.artist.repository.ArtistRepository;
import com.festago.common.exception.ErrorCode;
import com.festago.common.exception.InternalServerException;
import com.festago.common.exception.NotFoundException;
import com.festago.stage.domain.StageQueryInfo;
import com.festago.stage.repository.StageArtistRepository;
import com.festago.stage.repository.StageQueryInfoRepository;
import java.util.List;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
public class StageQueryInfoService {

private final StageQueryInfoRepository stageQueryInfoRepository;
private final StageArtistRepository stageArtistRepository;
private final ArtistRepository artistRepository;
private final ArtistsSerializer serializer;

public void initialStageQueryInfo(Long stageId) {
List<Artist> artists = getStageArtists(stageId);
StageQueryInfo stageQueryInfo = StageQueryInfo.of(stageId, artists, serializer);
stageQueryInfoRepository.save(stageQueryInfo);
}

private List<Artist> getStageArtists(Long stageId) {
Set<Long> artistIds = stageArtistRepository.findAllArtistIdByStageId(stageId);
List<Artist> artists = artistRepository.findByIdIn(artistIds);
if (artists.size() != artistIds.size()) {
log.error("StageArtist์— ์กด์žฌํ•˜์ง€ ์•Š์€ Artist๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. artistsIds=" + artistIds);
throw new InternalServerException(ErrorCode.ARTIST_NOT_FOUND);
}
return artists;
}

public void renewalStageQueryInfo(Long stageId) {
StageQueryInfo stageQueryInfo = stageQueryInfoRepository.findByStageId(stageId)
.orElseThrow(() -> new NotFoundException(ErrorCode.STAGE_NOT_FOUND));
List<Artist> artists = getStageArtists(stageId);
stageQueryInfo.updateArtist(artists, serializer);
}

public void deleteStageQueryInfo(Long stageId) {
stageQueryInfoRepository.deleteByStageId(stageId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package com.festago.admin.presentation.v1;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.festago.admin.application.AdminQueryInfoRenewalService;
import com.festago.admin.dto.queryinfo.QueryInfoRenewalFestivalPeriodV1Request;
import com.festago.auth.domain.Role;
import com.festago.support.CustomWebMvcTest;
import com.festago.support.WithMockAuth;
import jakarta.servlet.http.Cookie;
import java.time.LocalDate;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

@CustomWebMvcTest
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
@SuppressWarnings("NonAsciiCharacters")
class AdminQueryInfoRenewalV1ControllerTest {

private static final Cookie TOKEN_COOKIE = new Cookie("token", "token");

@Autowired
MockMvc mockMvc;

@Autowired
ObjectMapper objectMapper;

@Autowired
AdminQueryInfoRenewalService adminQueryInfoRenewalService;

@Nested
class QueryInfo_์žฌ๊ฐฑ์‹ _by_festivalId {

final String uri = "/admin/api/v1/query-info/renewal/festival-id/{festivalId}";

@Nested
@DisplayName("POST " + uri)
class ์˜ฌ๋ฐ”๋ฅธ_์ฃผ์†Œ๋กœ {

private long festivalId = 1L;

@Test
@WithMockAuth(role = Role.ADMIN)
void ์š”์ฒญ์„_๋ณด๋‚ด๋ฉด_200_์‘๋‹ต์ด_๋ฐ˜ํ™˜๋œ๋‹ค() throws Exception {
// when & then
mockMvc.perform(post(uri, festivalId)
.cookie(TOKEN_COOKIE)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}

@Test
void ํ† ํฐ_์—†์ด_๋ณด๋‚ด๋ฉด_401_์‘๋‹ต์ด_๋ฐ˜ํ™˜๋œ๋‹ค() throws Exception {
// when & then
mockMvc.perform(post(uri, festivalId))
.andExpect(status().isUnauthorized());
}

@Test
@WithMockAuth(role = Role.MEMBER)
void ํ† ํฐ์˜_๊ถŒํ•œ์ด_Admin์ด_์•„๋‹ˆ๋ฉด_404_์‘๋‹ต์ด_๋ฐ˜ํ™˜๋œ๋‹ค() throws Exception {
// when & then
mockMvc.perform(post(uri, festivalId)
.cookie(TOKEN_COOKIE))
.andExpect(status().isNotFound());
}
}
}

@Nested
class QueryInfo_์žฌ๊ฐฑ์‹ _by_festival_startDate_period {

final String uri = "/admin/api/v1/query-info/renewal/festival-period";

@Nested
@DisplayName("POST " + uri)
class ์˜ฌ๋ฐ”๋ฅธ_์ฃผ์†Œ๋กœ {

@Test
@WithMockAuth(role = Role.ADMIN)
void ์š”์ฒญ์„_๋ณด๋‚ด๋ฉด_200_์‘๋‹ต์ด_๋ฐ˜ํ™˜๋œ๋‹ค() throws Exception {
// given
var request = new QueryInfoRenewalFestivalPeriodV1Request(LocalDate.now(), LocalDate.now());
// when & then
mockMvc.perform(post(uri)
.content(objectMapper.writeValueAsString(request))
.cookie(TOKEN_COOKIE)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}

@Test
void ํ† ํฐ_์—†์ด_๋ณด๋‚ด๋ฉด_401_์‘๋‹ต์ด_๋ฐ˜ํ™˜๋œ๋‹ค() throws Exception {
// when & then
mockMvc.perform(post(uri))
.andExpect(status().isUnauthorized());
}

@Test
@WithMockAuth(role = Role.MEMBER)
void ํ† ํฐ์˜_๊ถŒํ•œ์ด_Admin์ด_์•„๋‹ˆ๋ฉด_404_์‘๋‹ต์ด_๋ฐ˜ํ™˜๋œ๋‹ค() throws Exception {
// when & then
mockMvc.perform(post(uri)
.cookie(TOKEN_COOKIE))
.andExpect(status().isNotFound());
}
}
}
}
Loading

0 comments on commit 119911e

Please sign in to comment.