Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
@RequestMapping("/amateurs")
public class AmateurController {

private final MemberService memberService;
private final AmateurService amateurService;

@PreAuthorize("hasRole('PERFORMER')")
Expand All @@ -57,50 +56,46 @@ public ApiResponse<String> deleteShow(@AuthenticationPrincipal(expression = "mem

@GetMapping("/{amateurShowId}")
@Operation(summary = "소극장 공연 조회 - 단건")
public ApiResponse<AmateurShowResponseDTO.AmateurShowResult> getAmateurShow(@AuthenticationPrincipal(expression = "member") Member member,
@PathVariable Long amateurShowId){
return ApiResponse.onSuccess(amateurService.getAmateurShow(member.getId(), amateurShowId));
public ApiResponse<AmateurShowResponseDTO.AmateurShowResult> getAmateurShow(@PathVariable Long amateurShowId){
return ApiResponse.onSuccess(amateurService.getAmateurShow(amateurShowId));
}

@GetMapping("/ranking")
@Operation(summary = "소극장 공연 랭킹 조회 API")
public ApiResponse<List<AmateurShowResponseDTO.AmateurShowList>> getShowRanking(@AuthenticationPrincipal(expression = "member") Member member) {
return ApiResponse.onSuccess(amateurService.getShowRanking(member.getId()));
public ApiResponse<List<AmateurShowResponseDTO.AmateurShowList>> getShowRanking() {
return ApiResponse.onSuccess(amateurService.getShowRanking());
}

@GetMapping("/today")
@Operation(summary = "오늘 진행하는 소극장 공연 조회 API")
public ApiResponse<SliceResponse<AmateurShowResponseDTO.AmateurShowList>> getShowToday(
@AuthenticationPrincipal(expression = "member") Member member, @ParameterObject Pageable pageable) {
return ApiResponse.onSuccess(SliceResponse.of(amateurService.getShowToday(member.getId(), pageable)));
public ApiResponse<SliceResponse<AmateurShowResponseDTO.AmateurShowList>> getShowToday( @ParameterObject Pageable pageable) {
return ApiResponse.onSuccess(SliceResponse.of(amateurService.getShowToday(pageable)));
}

@GetMapping("/ongoing")
@Operation(summary = "현재 진행중인 소극장 공연 조회 API")
public ApiResponse<SliceResponse<AmateurShowList>> getShowOngoing(
@AuthenticationPrincipal(expression = "member") Member member, @ParameterObject Pageable pageable
public ApiResponse<SliceResponse<AmateurShowList>> getShowOngoing( @ParameterObject Pageable pageable
) {
Slice<AmateurShowList> sliceResult = amateurService.getShowOngoing(member.getId(), pageable);
Slice<AmateurShowList> sliceResult = amateurService.getShowOngoing(pageable);
return ApiResponse.onSuccess(SliceResponse.of(sliceResult));
}

@GetMapping("/closing")
@Operation(summary = "오늘 마감인 공연 조회 API")
public ApiResponse<List<AmateurShowResponseDTO.AmateurShowList>> getShowClosing(@AuthenticationPrincipal(expression = "member") Member member) {
return ApiResponse.onSuccess(amateurService.getShowClosing(member.getId()));
public ApiResponse<List<AmateurShowResponseDTO.AmateurShowList>> getShowClosing() {
return ApiResponse.onSuccess(amateurService.getShowClosing());
}

@GetMapping("/recentlyHot")
@Operation(summary = "요즘 핫한 소극장 연극 조회 API")
public ApiResponse<List<AmateurShowResponseDTO.AmateurShowList>> getRecentlyHotShow(@AuthenticationPrincipal(expression = "member") Member member) {
return ApiResponse.onSuccess(amateurService.getRecentlyHotShow(member.getId()));
public ApiResponse<List<AmateurShowResponseDTO.AmateurShowList>> getRecentlyHotShow() {
return ApiResponse.onSuccess(amateurService.getRecentlyHotShow());
}

@GetMapping("/incoming")
@Operation(summary = "임박한 공연 조회 API")
public ApiResponse<SliceResponse<AmateurShowResponseDTO.AmateurShowList>> getShowIncoming(
@AuthenticationPrincipal(expression = "member") Member member, @ParameterObject Pageable pageable) {
Slice<AmateurShowList> sliceResult = amateurService.getShowToday(member.getId(), pageable);
public ApiResponse<SliceResponse<AmateurShowResponseDTO.AmateurShowList>> getShowIncoming(@ParameterObject Pageable pageable) {
Slice<AmateurShowList> sliceResult = amateurService.getShowToday(pageable);
return ApiResponse.onSuccess(SliceResponse.of(sliceResult));
}
Comment on lines 95 to 100
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

getShowIncoming delegates to getShowToday — likely incorrect.

The operation summary says "임박한 공연 조회 API" (upcoming/imminent shows), but the implementation calls getShowToday(pageable), which filters for shows with rounds happening today. These are semantically different:

  • "Incoming" typically means upcoming/soon-to-happen shows
  • "Today" means shows occurring today

This may be a copy-paste error or intentional reuse, but the API behavior doesn't match its description.

🤖 Prompt for AI Agents
In @src/main/java/cc/backend/amateurShow/controller/AmateurController.java
around lines 95-100, The getShowIncoming controller method currently calls
amateurService.getShowToday, which mismatches the operation summary for "임박한 공연
조회 API"; update AmateurController.getShowIncoming to call the correct service
method (e.g., amateurService.getShowIncoming or amateurService.getUpcomingShows)
that returns upcoming/imminent shows instead of today's shows — if that service
method does not exist, implement a new method in AmateurService (and its impl)
that queries for upcoming rounds and returns a Slice<AmateurShowList>, and
ensure the returned DTO/signature matches SliceResponse.of(...) used in the
controller.

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

@Repository
public interface AmateurShowRepository extends JpaRepository<AmateurShow, Long>, JpaSpecificationExecutor<AmateurShow> {
List<AmateurShow> findAllByMemberId(Long memberId);

@Query("SELECT a FROM AmateurShow a WHERE a.id = :id")
Optional<AmateurShow> findByIdWithDetails(@Param("id") Long id);
Expand All @@ -34,9 +33,6 @@ Slice<AmateurShow> findAllByMemberIdAndStatusOrderByIdDesc(@Param("memberId") Lo
@Param("status") AmateurShowStatus status,
Pageable pageable);

List<AmateurShow> findAllByMemberIdOrderByUpdatedAtDesc(@Param("memberId") Long memberId);


@Query("""
select s
from AmateurShow s
Expand All @@ -60,16 +56,15 @@ Slice<AmateurShow> findByMember_IdAndStatusInOrderByIdDesc(

long countByMember_Id(Long memberId);


Page<AmateurShow> findByNameContainingIgnoreCase(String showName, Pageable pageable);


List<AmateurShow> findByEndGreaterThanEqual(LocalDate today);
List<AmateurShow> findAllByMemberId(Long memberId);

@Query("""
SELECT s
FROM AmateurShow s
WHERE s.end >= :today
AND s.approvalStatus = 'APPROVED'
ORDER BY s.end ASC
""")
List<AmateurShow> findHotShows(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
package cc.backend.amateurShow.repository.specification;

import cc.backend.amateurShow.entity.AmateurRounds;
import cc.backend.amateurShow.entity.AmateurShow;
import cc.backend.amateurShow.entity.enums.ApprovalStatus;
import cc.backend.member.entity.Member;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Join;
import jakarta.persistence.criteria.Path;
import org.springframework.data.jpa.domain.Specification;

import java.time.LocalDate;

public class AmateurShowSpecification {

public static Specification<AmateurShow> isAudienceVisible() {
return (root, query, criteriaBuilder) ->
criteriaBuilder.equal(root.get("approvalStatus"), ApprovalStatus.APPROVED);
}

public static Specification<AmateurShow> isWrittenBy(Member performer) {
return (root, query, criteriaBuilder) ->
criteriaBuilder.equal(root.get("member"), performer);
Expand Down Expand Up @@ -45,4 +44,54 @@ public static Specification<AmateurShow> isNotEnded(LocalDate today) {
return (root, query, criteriaBuilder) ->
criteriaBuilder.greaterThanOrEqualTo(root.get("end"), today);
}

/**
* 오늘 날짜 회차 필터
* performanceDateTime이 전달된 날짜(date)와 일치하는 공연만
*/
public static Specification<AmateurShow> hasRoundOn(LocalDate date) {
return (root, query, cb) -> {
// 중복 제거 필요 시
query.distinct(true);

// Join to amateurRounds
var rounds = root.join("amateurRounds");

// 날짜만 비교 (MySQL 기준)
return cb.equal(cb.function("DATE", LocalDate.class, rounds.get("performanceDateTime")), date);
};
}

/**
* 마지막 회차 날짜가 오늘인 공연 필터
*/
public static Specification<AmateurShow> hasLastRoundOn(LocalDate today) {
return (root, query, cb) -> {
query.distinct(true);

// 서브쿼리: AmateurRounds 기준
var subquery = query.subquery(LocalDate.class);
var roundRoot = subquery.from(AmateurRounds.class);

// MAX(DATE(performanceDateTime))
Expression<LocalDate> lastRoundDate =
cb.greatest(
cb.function(
"DATE",
LocalDate.class,
roundRoot.get("performanceDateTime")
)
);

subquery.select(lastRoundDate);

// 해당 공연의 회차만 대상
subquery.where(
cb.equal(roundRoot.get("amateurShow"), root)
);

// 마지막 회차 날짜 == today
return cb.equal(subquery, today);
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import cc.backend.amateurShow.dto.AmateurShowResponseDTO;
import cc.backend.amateurShow.dto.AmateurUpdateRequestDTO;
import cc.backend.amateurShow.entity.AmateurShowStatus;
import cc.backend.ticket.dto.response.ReserveListResponseDTO;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.stereotype.Service;
Expand All @@ -16,14 +15,14 @@
public interface AmateurService {
AmateurEnrollResponseDTO.AmateurEnrollResult enrollShow(Long memberId,
AmateurEnrollRequestDTO requestDTO);
AmateurShowResponseDTO.AmateurShowResult getAmateurShow(Long memberId, Long amateurId);
AmateurShowResponseDTO.AmateurShowResult getAmateurShow(Long amateurId);
AmateurEnrollResponseDTO.AmateurEnrollResult updateShow(Long memberId, Long showId, AmateurUpdateRequestDTO requestDTO);
void deleteShow(Long memberId, Long amateurShowId);
Slice<AmateurShowResponseDTO.AmateurShowList> getShowToday(Long memberId, Pageable pageable);
Slice<AmateurShowResponseDTO.AmateurShowList> getShowOngoing(Long memberId, Pageable pageable);
List<AmateurShowResponseDTO.AmateurShowList> getShowRanking(Long memberId);
List<AmateurShowResponseDTO.AmateurShowList> getRecentlyHotShow(Long memberId);
List<AmateurShowResponseDTO.AmateurShowList> getShowClosing(Long memberId);
Slice<AmateurShowResponseDTO.AmateurShowList> getShowToday(Pageable pageable);
Slice<AmateurShowResponseDTO.AmateurShowList> getShowOngoing(Pageable pageable);
List<AmateurShowResponseDTO.AmateurShowList> getShowRanking();
List<AmateurShowResponseDTO.AmateurShowList> getRecentlyHotShow();
List<AmateurShowResponseDTO.AmateurShowList> getShowClosing();


Slice<AmateurShowResponseDTO.MyShowAmateurShowList> getMyAmateurShow(Long memberId, AmateurShowStatus showStatus, Pageable pageable);
Expand Down
Loading