-
Notifications
You must be signed in to change notification settings - Fork 8
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
[BE] feat: 축제 조회 필터링 구현(#602) #603
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
감동적인 작업재개입니다 .. . 👏
private FestivalSpecification() { | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
인스턴스화 방지 👍 Lombok써도 좋을 것 같아요!
ALL((currentTime) -> all()), | ||
PROGRESS((currentTime) -> afterStartDate(currentTime) | ||
.and(beforeEndDate(currentTime))), | ||
PLANNED((currentTime) -> beforeStartDate(currentTime)), | ||
END((currentTime) -> afterEndDate(currentTime)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ALL((currentTime) -> all()), | |
PROGRESS((currentTime) -> afterStartDate(currentTime) | |
.and(beforeEndDate(currentTime))), | |
PLANNED((currentTime) -> beforeStartDate(currentTime)), | |
END((currentTime) -> afterEndDate(currentTime)); | |
ALL(currentTime -> all()), | |
PROGRESS(currentTime -> afterStartDate(currentTime) | |
.and(beforeEndDate(currentTime))), | |
PLANNED(currentTime -> beforeStartDate(currentTime)), | |
END(currentTime -> afterEndDate(currentTime)); |
FestivalFilter(Function<LocalDate, Specification<Festival>> filter) { | ||
this.filter = filter; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이녀석은 왜 접근제어자가 없나요?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Enum 생성자 접근제어자에 뭘 썼는지 기억이 안나요 이걸 따로 명시해줬나요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Enum은 접근제어자가 필요하지 않습니다..!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아이고 이놈 enum이었네
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
라임 디졌다 ;;
public static Specification<Festival> afterStartDate(LocalDate currentTime) { | ||
return (root, query, criteriaBuilder) -> criteriaBuilder.lessThan(root.get("startDate"), currentTime); | ||
} | ||
|
||
public static Specification<Festival> beforeStartDate(LocalDate currentTime) { | ||
return (root, query, criteriaBuilder) -> criteriaBuilder.greaterThan(root.get("startDate"), currentTime); | ||
} | ||
|
||
public static Specification<Festival> afterEndDate(LocalDate currentTime) { | ||
return (root, query, criteriaBuilder) -> criteriaBuilder.lessThan(root.get("endDate"), currentTime); | ||
} | ||
|
||
public static Specification<Festival> beforeEndDate(LocalDate currentTime) { | ||
return (root, query, criteriaBuilder) -> criteriaBuilder.greaterThan(root.get("endDate"), currentTime); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
startDate와 endDate 상수화해주는건 어떤가요?
@RequestParam(defaultValue = "ALL") String festivalFilter) { | ||
FestivalsResponse response = festivalService.findFestivals(FestivalFilter.from(festivalFilter)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
default ALL 👍
@@ -47,7 +48,7 @@ class FestivalControllerTest { | |||
FestivalResponse festivalResponse2 = new FestivalResponse(2L, 2L, "우테대학교", LocalDate.now().minusDays(3), | |||
LocalDate.now(), "https://image2.png"); | |||
FestivalsResponse expected = new FestivalsResponse(List.of(festivalResponse1, festivalResponse2)); | |||
given(festivalService.findAll()) | |||
given(festivalService.findFestivals(any())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
given(festivalService.findFestivals(any())) | |
given(festivalService.findFestivals(any(FestivalFilter.class))) |
타입 명시해주는건 어떤가요?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
리뷰 다 반영했습니당
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고생하셨습니다 푸우!
간만에 코드 리뷰 하니 재밌네요.
당장 13시간 뒤에 면접이라 그런지도 모르겠습니다.
페이지네이션 적용을 추후 고려해보는 것도 좋을 것 같네요.
ALL(currentTime -> all()), | ||
PROGRESS(currentTime -> afterStartDate(currentTime) | ||
.and(beforeEndDate(currentTime))), | ||
PLANNED(currentTime -> beforeStartDate(currentTime)), | ||
END(currentTime -> afterEndDate(currentTime)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Enum에서 스펙을 조합하여 조건을 맞추기 보단, FestivalSpecification
객체가 명시적으로 스펙을 던져주는 것은 어떤가요?
ALL(currentTime -> all()), | |
PROGRESS(currentTime -> afterStartDate(currentTime) | |
.and(beforeEndDate(currentTime))), | |
PLANNED(currentTime -> beforeStartDate(currentTime)), | |
END(currentTime -> afterEndDate(currentTime)); | |
ALL(FestivalSpecification::all), | |
PROGRESS(FestivalSpecification::progress), | |
PLANNED(FestivalSpecification::beforeStartDate), | |
END(FestivalSpecification::afterEndDate); |
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class FestivalSpecification {
private static final String START_DATE = "startDate";
private static final String END_DATE = "endDate";
public static Specification<Festival> all(LocalDate currentTime) { // 메서드 참조를 위해 파라미터 추가
return (root, query, criteriaBuilder) -> criteriaBuilder.conjunction();
}
public static Specification<Festival> progress(LocalDate currentTime) {
return (root, query, criteriaBuilder) -> criteriaBuilder.and(
criteriaBuilder.lessThan(root.get(START_DATE), currentTime), // lessThanOrEqualTo 고려할 것
criteriaBuilder.greaterThan(root.get(END_DATE), currentTime) // greaterThanOrEqualTo 고려할 것
);
}
public static Specification<Festival> beforeStartDate(LocalDate currentTime) {
return (root, query, criteriaBuilder) -> criteriaBuilder.greaterThan(root.get(START_DATE), currentTime);
}
public static Specification<Festival> afterEndDate(LocalDate currentTime) {
return (root, query, criteriaBuilder) -> criteriaBuilder.lessThan(root.get(END_DATE), currentTime);
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
beforeStartDate
, afterEndDate
는 알잘딱하게 해주세요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 글렌이 말씀하신 부분에 동의합니다. Specification method가 Progress 같은 경우 외부에서 and 조건으로 조합해주는 형식이 아니라 명확하게 완성된 조건을 뱉어주는게 더 이해하기 쉽고, 테스트하기 좋은 코드라고 여겨져요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
반영했습니다!
PROGRESS(currentTime -> afterStartDate(currentTime) | ||
.and(beforeEndDate(currentTime))), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
진행중인 축제의 스펙이 다음과 같이 되어있네요.
public static Specification<Festival> afterStartDate(LocalDate currentTime) {
return (root, query, criteriaBuilder) -> criteriaBuilder.lessThan(root.get(START_DATE), currentTime);
}
public static Specification<Festival> beforeEndDate(LocalDate currentTime) {
return (root, query, criteriaBuilder) -> criteriaBuilder.greaterThan(root.get(END_DATE), currentTime);
}
이때 lessThan
, greaterThan
이라면 당일에만 진행하는 축제에 대해 당일에 조회하면 조회가 되지 않을 것 같네요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Test
void 현재_진행_축제_넘기기_오늘시작_내일끝() {
// given
...
festivalRepository.save(new Festival("name", now.minusDays(0), now.plusDays(1), school));
// when
int actual = festivalRepository.findAll(FestivalFilter.PROGRESS.getSpecification()).size();
// then
assertThat(actual).isEqualTo(1);
}
@Test
void 현재_진행_축제_넘기기_어제시작_오늘끝() {
// given
...
festivalRepository.save(new Festival("name", now.minusDays(1), now.plusDays(0), school));
// when
int actual = festivalRepository.findAll(FestivalFilter.PROGRESS.getSpecification()).size();
// then
assertThat(actual).isEqualTo(1);
}
글렌이 말씀해준것 처럼 이 테스트 코드들이 통과하기 위해선 eqaulsTo 조건이 들어가야겠네요 !!
오늘이 11월 11일이라면, 11월 11일에 시작하는 축제 및 11월 11일에 끝나는 축제가 조회되어야 할테니까요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
헉 수정했습니다
public static FestivalFilter from(String filterName) { | ||
return Arrays.stream(FestivalFilter.values()) | ||
.filter(festivalFilter -> festivalFilter.name().equalsIgnoreCase(filterName)) | ||
.findAny() | ||
.orElseThrow(() -> new BadRequestException(ErrorCode.INVALID_FESTIVAL_FILTER)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
크게 고려해야 할 상황은 아니지만...
스트림을 매번 돌리기 보단 스위치를 사용하는게 좋아 보이네요.
물론 새로운 Filter가 추가되면 해당 코드를 변경해야 합니다.
public static FestivalFilter from(String filterName) { | |
return Arrays.stream(FestivalFilter.values()) | |
.filter(festivalFilter -> festivalFilter.name().equalsIgnoreCase(filterName)) | |
.findAny() | |
.orElseThrow(() -> new BadRequestException(ErrorCode.INVALID_FESTIVAL_FILTER)); | |
} | |
public static FestivalFilter from(String filterName) { | |
return switch (filterName) { // filterName.toUpperCase() 고려 | |
case "ALL" -> ALL; | |
case "PROGRESS" -> PROGRESS; | |
case "PLANNED" -> PLANNED; | |
case "END" -> END; | |
default -> throw new BadRequestException(ErrorCode.INVALID_FESTIVAL_FILTER); | |
}; | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 연산마다 Stream 이 생성되는 것이 비효율적이라 생각했지만
Java 코드 레벨에서의 비효율이 실질적으로 미치는 영향이 크지 않다 생각했습니다.
하지만 But 한번 적용해보는 것도 좋아보여 반영했습니다!
public Specification<Festival> getSpecification() { | ||
return filter.apply(LocalDate.now()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clock
을 매개변수로 받는게 좋아 보이네요.
public static Specification<Festival> all() { | ||
return (root, query, criteriaBuilder) -> criteriaBuilder.conjunction(); | ||
} | ||
|
||
public static Specification<Festival> afterStartDate(LocalDate currentTime) { | ||
return (root, query, criteriaBuilder) -> criteriaBuilder.lessThan(root.get(START_DATE), currentTime); | ||
} | ||
|
||
public static Specification<Festival> beforeStartDate(LocalDate currentTime) { | ||
return (root, query, criteriaBuilder) -> criteriaBuilder.greaterThan(root.get(START_DATE), currentTime); | ||
} | ||
|
||
public static Specification<Festival> afterEndDate(LocalDate currentTime) { | ||
return (root, query, criteriaBuilder) -> criteriaBuilder.lessThan(root.get(END_DATE), currentTime); | ||
} | ||
|
||
public static Specification<Festival> beforeEndDate(LocalDate currentTime) { | ||
return (root, query, criteriaBuilder) -> criteriaBuilder.greaterThan(root.get(END_DATE), currentTime); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
위의 커멘트에도 남기긴 했지만...
다음과 같이 메서드가 하는 일을 명확하게 하는것은 어떤가요
public static Specification<Festival> all() { | |
return (root, query, criteriaBuilder) -> criteriaBuilder.conjunction(); | |
} | |
public static Specification<Festival> afterStartDate(LocalDate currentTime) { | |
return (root, query, criteriaBuilder) -> criteriaBuilder.lessThan(root.get(START_DATE), currentTime); | |
} | |
public static Specification<Festival> beforeStartDate(LocalDate currentTime) { | |
return (root, query, criteriaBuilder) -> criteriaBuilder.greaterThan(root.get(START_DATE), currentTime); | |
} | |
public static Specification<Festival> afterEndDate(LocalDate currentTime) { | |
return (root, query, criteriaBuilder) -> criteriaBuilder.lessThan(root.get(END_DATE), currentTime); | |
} | |
public static Specification<Festival> beforeEndDate(LocalDate currentTime) { | |
return (root, query, criteriaBuilder) -> criteriaBuilder.greaterThan(root.get(END_DATE), currentTime); | |
} | |
public static Specification<Festival> all(LocalDate currentTime) { // 메서드 참조를 위해 파라미터 추가 | |
return (root, query, criteriaBuilder) -> criteriaBuilder.conjunction(); | |
} | |
public static Specification<Festival> progress(LocalDate currentTime) { | |
return (root, query, criteriaBuilder) -> criteriaBuilder.and( | |
criteriaBuilder.lessThan(root.get(START_DATE), currentTime), // lessThanOrEqualTo 고려할 것 | |
criteriaBuilder.greaterThan(root.get(END_DATE), currentTime) // greaterThanOrEqualTo 고려할 것 | |
); | |
} | |
public static Specification<Festival> beforeStartDate(LocalDate currentTime) { | |
return (root, query, criteriaBuilder) -> criteriaBuilder.greaterThan(root.get(START_DATE), currentTime); | |
} | |
public static Specification<Festival> afterEndDate(LocalDate currentTime) { | |
return (root, query, criteriaBuilder) -> criteriaBuilder.lessThan(root.get(END_DATE), currentTime); | |
} |
@Test | ||
void 진행_중_축제_반환() { | ||
// given | ||
FestivalFilter filter = FestivalFilter.PROGRESS; | ||
|
||
// when | ||
List<Festival> actual = festivalRepository.findAll(filter.getSpecification()); | ||
|
||
// then | ||
assertSoftly(softAssertions -> { | ||
assertThat(actual).hasSize(1); | ||
assertThat(actual.get(0)).matches(festival -> festival.getName().equals(CURRENT_FESTIVAL)); | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
당일에 해당하는 축제에 대한 테스트 코드도 필요할 것 같네요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
반영했습니다!
festivalRepository.save(new Festival(PAST_FESTIVAL, now.minusDays(10L), now.minusDays(8L), school)); | ||
festivalRepository.save(new Festival(CURRENT_FESTIVAL, now.minusDays(1L), now.plusDays(1L), school)); | ||
festivalRepository.save(new Festival(FUTURE_FESTIVAL, now.plusDays(1L), now.plusDays(3L), school)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
시간에 대한 테스트는 "2023-11-10" 과 같이 고정된 값을 사용하는 것은 어떤가요?
@@ -29,6 +29,7 @@ public enum ErrorCode { | |||
DELETE_CONSTRAINT_STAGE("티켓이 등록된 공연은 삭제할 수 없습니다."), | |||
DELETE_CONSTRAINT_SCHOOL("학생 또는 축제에 등록된 학교는 삭제할 수 없습니다."), | |||
DUPLICATE_SCHOOL("이미 존재하는 학교 정보입니다."), | |||
INVALID_FESTIVAL_FILTER("유효하지 않은 필터 값입니다."), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
축제 라는 단어가 들어가도 좋겠네요.
ex) 올바르지 않은 축제의 필터 값 입니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
푸우 조금 늦었지만 간단한 코멘트를 첨부했습니다.
Specification도 은근 배우기 귀찮던데 고생하셨어요 !
현재 저희 조건에서 queryDsl 같은 기술을 추가 도입하는건 과하니 이렇게 푸는게 가장 간단한 거 같네요.
public ResponseEntity<FestivalsResponse> findFestivals( | ||
@RequestParam(defaultValue = "ALL") String festivalFilter) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
카톡에서 이야기 했던대로 전체가 없어진다면 default는 PROGRESS로 처리하는게 맞죠?_?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
네네 맞습니다!
PROGRESS(currentTime -> afterStartDate(currentTime) | ||
.and(beforeEndDate(currentTime))), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Test
void 현재_진행_축제_넘기기_오늘시작_내일끝() {
// given
...
festivalRepository.save(new Festival("name", now.minusDays(0), now.plusDays(1), school));
// when
int actual = festivalRepository.findAll(FestivalFilter.PROGRESS.getSpecification()).size();
// then
assertThat(actual).isEqualTo(1);
}
@Test
void 현재_진행_축제_넘기기_어제시작_오늘끝() {
// given
...
festivalRepository.save(new Festival("name", now.minusDays(1), now.plusDays(0), school));
// when
int actual = festivalRepository.findAll(FestivalFilter.PROGRESS.getSpecification()).size();
// then
assertThat(actual).isEqualTo(1);
}
글렌이 말씀해준것 처럼 이 테스트 코드들이 통과하기 위해선 eqaulsTo 조건이 들어가야겠네요 !!
오늘이 11월 11일이라면, 11월 11일에 시작하는 축제 및 11월 11일에 끝나는 축제가 조회되어야 할테니까요.
ALL(currentTime -> all()), | ||
PROGRESS(currentTime -> afterStartDate(currentTime) | ||
.and(beforeEndDate(currentTime))), | ||
PLANNED(currentTime -> beforeStartDate(currentTime)), | ||
END(currentTime -> afterEndDate(currentTime)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 글렌이 말씀하신 부분에 동의합니다. Specification method가 Progress 같은 경우 외부에서 and 조건으로 조합해주는 형식이 아니라 명확하게 완성된 조건을 뱉어주는게 더 이해하기 쉽고, 테스트하기 좋은 코드라고 여겨져요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고생하셨습니다 푸우.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고생하셨습니다!!!
* [AN/USER] feat: 티켓 예매 디자인 수정 (#567) (#570) * feat: 티켓 예매 바텀 시트 화면 디자인 수정 * feat: 포스터 크기 수정 * refactor: 티켓을 선택하면 INVISIBLE로 변환 * refactor: 화면 겹치는 현상 제거 * refactor: 불필요한 공백 제거 --------- Co-authored-by: re4rk <[email protected]> * [AN/USER] feat: 페스타고 유저 앱 버전 변경 (#571) (#572) * [BE] chore: 개발 환경의 서브 모듈을 업데이트 (#573) (#574) * refactor: 사용하지 않게된 클래스를 제거한다. (#513) * [BE] feat: 회원의 학생 인증 정보 조회 API 구현 (#496) (#531) * refactor: 메서드 네이밍 수정 (verifiacte -> verify) * feat: 학생 인증 정보 조회 기능 구현 * refactor: findByMemberIdWithFetch INNER JOIN으로 수정 * refactor: inner line return 으로 수정 * refactor: 캐싱된 Response 반환 * [AN/USER] fix: 예매 완료 화면 버그 픽스 (#575) (#576) * fix: getParcelableExtraCompat * update: 버전 변경 * [ALL] 프로젝트 README 추가 (#552) (#577) * Update README.md * Update README.md * Update README.md * Update README.md * docs: 기능 간단 소개 작성 * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * docs: update * Update README.md 줄바꿈 수정 * docs: Update README.md * Update README.md 백엔드 기술스택 추가 * Update README.md - JUnit5 오타 수정 * Update README.md 백엔드 기술스택 flyway 추가 * 인프라 아키텍처 사진 추가 * Update infra structure image * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md --------- Co-authored-by: xxeol2 <[email protected]> Co-authored-by: Hyun-Seo Oh / 오현서 <[email protected]> Co-authored-by: 해시 <[email protected]> Co-authored-by: Guga <[email protected]> * [AN/USER] refactor: ViewModel Test Code Dispatcher Rule 추가 (#590) * feat: coroutine dispatcher main rule 추가 * refactor: 티켓 예매 화면 ViewModel 테스트 리팩터링 * refactor: 티켓 목록 화면 ViewModel 테스트 리팩터링 * refactor: 티켓 기록 화면 ViewModel 테스트 리팩터링 * refactor: 티켓 입장 화면 ViewModel 테스트 리팩터링 * refactor: 학생 인증 화면 ViewModel 테스트 리팩터링 * refactor: 로그인 화면 ViewModel 테스트 리팩터링 * refactor: 학교 선택 화면 ViewModel 테스트 리팩터링 * refactor: 마이페이지 화면 ViewModel 테스트 리팩터링 * refactor: 홈 화면 ViewModel 테스트 리팩터링 * refactor: 축제 목록 화면 ViewModel 테스트 리팩터링 * refactor: 마이페이지 화면 ViewModel 테스트 재변경 * [AN/USER] feat: 버튼 더블 클릭 막기(#584) (#585) * feat: SingleClick Util 추가 * feat: 바텀 시트 바깥 클릭 막기 * feat: single 클릭 적용 * refactor: SingleClick 메서드명 변경 * refactor: xml 파일 호출 순서 맞추기 * [AN/USER] feat: 홈 화면에서 뒤로가기 누르면 곧바로 종료되지 않는다. (#588) * feat: 홈화면 뒤로가기 상수 추가 * feat: 홈화면 뒤로가기 두 번 클릭 시 종료 * [AN/USER] feat: SingleLivedata 제거 (#586) (#587) * refactor: 사용하지않는 SingleLiveData 제거 * refactor: 사용하지않는 Event 제거 * [AN/USER] feat: 예매 실패 케이스 처리(#369) (#593) * feat: 에러 코드를 구분한다 * feat: API 요청 실패 결과에 따라 에러 코드를 예외로 던진다 * feat: 티켓 예매 요청에 실패하면 예외 이벤트가 발생한다. * feat: 에러 코드에 따라 다른 메세지를 띄운다 * [AN/USER] refactor: 네트워크 에러 로깅을 확장함수 없이 직접 처리한다(#595) (#596) refactor: 네트워크 에러 로깅을 확장함수 없이 직접 처리한다 * [BE] feat: 축제 조회 필터링 구현(#602) (#603) * feat: specification 정의 * feat: FestivalFilter 정의 * feat: 축제 진행 상태에 따른 Controller, Service 생성 * refactor: private 생성자를 lombok 을 통해 생성 * chore: 괄호 제거 * chore: 변수 상수화 * chore: given 절 타입 명시 * feat: 축제 조회 ALL 삭제 및 기본값을 진행 중으로 변경 * feat: 축제 당일이 Progress에 포함되도록 변경 및 Spec 리팩터링 * feat: 축제 진행 상황별 정렬 조건 추가 * chore: 메서드 순서 변경 * chore: index 추가 * chore: 에러 메시지 변경 * chore: test 개행 변경 및 변수 재활용 * [AN/USER] feat: 홈화면 필터링 기능을 제공한다 (#600) (#606) * feat: 축제 목록 필터 이름 상수화 * feat: 축제 목록 칩 색깔 및 텍스트 스타일 작성 * feat: 축제 목록 칩으로 필터링하기 화면 그리기 * feat: 축제 필터 분류 정의 * feat: FestivalRepository 필터링 요청 가능하도록 재정의 * feat: 축제 목록 ViewModel 에 축제 필터링 기능 적용 * feat: 축제 목록 Fragment 에 필터링 기능 적용 * feat: 축제 목록 필터링 API 연동 작업 * feat: 페스타고 홈화면 아이콘 추가 * refactor: 칩 색깔 selector 네이밍 수정 * refactor: 축제 목록 칩 색깔 네이밍 변경 * feat: 필터링 칩 다크모드 적용 * feat: 필터링 상태를 ViewModel 에서 관리하지 않는다 * feat: 현재 선택된 칩의 필터링에 해당하는 리스트를 요청한다 * fix: Loading 이 아니면 구성 변경 시 축제 목록을 재요청하지 않는다 * [BE] refactor: /stages/{stageId}/tickets API의 N+1을 해결한다.(#517) (#578) * refactor: findAllByStageId fetch 조인으로 변경 * refactor: fetch join 메서드 사용하도록 변경 * chore: Inner 조건 명시하도록 변경 * [BE] 도메인 엔티티의 예외를 정의, 적용하고 테스트 패키지 구조를 정리한다. (#482) (#515) * feat: DomainValidException 추가 * fix: DomainValidException -> ValidException 변경, 수정 * feat: Validator 검증 로직 추가 * refactor: 검증 로직 도메인에 적용 * refactor: ValidException 에러코드 수정, Validator 로직 추가 * feat: Admin 검증 추가 * feat: EntryCode 검증 추가 * refactor: 검증 로직 대폭 개선 * test: 테스트 코드 패키지 구조에 맞게 이동 * test: 테스트 코드 추가 * test: Member 테스트 코드 추가 * fix: EntryState IllegalArgumentException 변경 * fix: 테스트 코드 깨짐 수정 * refactor: Validator 호출 시 필드명 변수로 추출 * feat: IllegalArgumentException을 대체하는 UnexpectedException 추가, 적용 * feat: OAuth2Clients 중복 추가 시 에러 로그 추가 * feat: UnexpectedException 예외 핸들러 추가 --------- Co-authored-by: BGuga <[email protected]> * [BE] test properties show sql 관련 설정 삭제 (#605) (#607) test: 테스트 로그에 쿼리 로그 제거하도록 변경 * [BE] refactor: 사용하지 않는 AdminService 제거 (#610) (#611) * test: 테스트 코드에 서비스 클래스 제거 * refactor: AdminService 삭제 * refactor: AdminDTO 삭제 * style: 개행 수정 * [BE] 학교 정보 API에 Swagger Annotation을 추가 (#597) (#598) feat: SchoolController에 Swagger 정보 추가 Co-authored-by: hyunseo <> * [AN/USER] feat: 축제 목록 화면 UX 개선(#614) (#615) * [AN] release: v1.2.0 (#618) (#619) chore: release v1.2.0 --------- Co-authored-by: re4rk <[email protected]> Co-authored-by: 해시 <[email protected]> Co-authored-by: Hyun-Seo Oh / 오현서 <[email protected]> Co-authored-by: xxeol2 <[email protected]> Co-authored-by: seokjin8678 <[email protected]> Co-authored-by: Guga <[email protected]>
* feat: specification 정의 * feat: FestivalFilter 정의 * feat: 축제 진행 상태에 따른 Controller, Service 생성 * refactor: private 생성자를 lombok 을 통해 생성 * chore: 괄호 제거 * chore: 변수 상수화 * chore: given 절 타입 명시 * feat: 축제 조회 ALL 삭제 및 기본값을 진행 중으로 변경 * feat: 축제 당일이 Progress에 포함되도록 변경 및 Spec 리팩터링 * feat: 축제 진행 상황별 정렬 조건 추가 * chore: 메서드 순서 변경 * chore: index 추가 * chore: 에러 메시지 변경 * chore: test 개행 변경 및 변수 재활용
📌 관련 이슈
✨ PR 세부 내용
축제 조건별 조회 기능 구현했습니다.