-
Notifications
You must be signed in to change notification settings - Fork 2
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
Feature/#86 컨퍼런스 목록 조회 api 구현 #108
Merged
The head ref may contain hidden characters: "Feature/#86-\uCEE8\uD37C\uB7F0\uC2A4_\uBAA9\uB85D_\uC870\uD68C_API_\uAD6C\uD604"
Merged
Changes from 8 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
5c4a2eb
feat: 월 별로 필터링하여 행사 목록을 조회하는 기능 구현
fbe7973
test: API 테스트 및 RESTDocs API 문서 작성
fa340ca
feat: 행사 진행 상태에 따른 필터링 기능 추가
1df808e
feat: 반환되는 DateTime 포맷 수정
61e900b
feat: Tag로 행사 목록 필터링하는 기능 구현
83d0e1c
test: 연도 및 월 유효성 검사
8165224
refactor: data.sql 쿼리를 Fixture 자바 코드로 대체
8e37641
refactor: 병합 충돌 제거
446b8cb
refactor: EventTagRepository 경로 수정
28a4db5
docs: API 명세 description 수정
570bf1b
refactor: 현장 코드리뷰 반영
3443d9c
fix: backend-main conflict 해결
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,30 @@ | ||
package com.emmsale.event.application; | ||
|
||
import static com.emmsale.event.exception.EventExceptionType.EVENT_NOT_FOUND_EXCEPTION; | ||
import static com.emmsale.event.exception.EventExceptionType.INVALID_MONTH; | ||
import static com.emmsale.event.exception.EventExceptionType.INVALID_STATUS; | ||
import static com.emmsale.event.exception.EventExceptionType.INVALID_YEAR; | ||
import static com.emmsale.tag.exception.TagExceptionType.NOT_FOUND_TAG; | ||
import static java.util.Comparator.comparing; | ||
import static java.util.stream.Collectors.groupingBy; | ||
import static java.util.stream.Collectors.toList; | ||
|
||
import com.emmsale.event.application.dto.EventDetailResponse; | ||
import com.emmsale.event.application.dto.EventResponse; | ||
import com.emmsale.event.domain.Event; | ||
import com.emmsale.event.domain.EventStatus; | ||
import com.emmsale.event.domain.EventTag; | ||
import com.emmsale.event.domain.EventTagRepository; | ||
import com.emmsale.event.domain.repository.EventRepository; | ||
import com.emmsale.event.exception.EventException; | ||
import com.emmsale.tag.domain.Tag; | ||
import com.emmsale.tag.domain.TagRepository; | ||
import com.emmsale.tag.exception.TagException; | ||
import java.time.LocalDate; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.EnumMap; | ||
import java.util.List; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
@@ -15,12 +34,130 @@ | |
@RequiredArgsConstructor | ||
public class EventService { | ||
|
||
private static final int MIN_MONTH = 1; | ||
private static final int MAX_MONTH = 12; | ||
private static final int MIN_YEAR = 2015; | ||
|
||
private final EventRepository eventRepository; | ||
private final EventTagRepository eventTagRepository; | ||
private final TagRepository tagRepository; | ||
|
||
@Transactional(readOnly = true) | ||
public EventDetailResponse findEvent(final Long id) { | ||
final Event event = eventRepository.findById(id) | ||
.orElseThrow(() -> new EventException(EVENT_NOT_FOUND_EXCEPTION)); | ||
return EventDetailResponse.from(event); | ||
} | ||
|
||
@Transactional(readOnly = true) | ||
public List<EventResponse> findEvents(final LocalDate nowDate, final int year, final int month, | ||
final String tagName, final String statusName) { | ||
validateYearAndMonth(year, month); | ||
List<Event> events = filterEventsByTag(tagName); | ||
|
||
final EnumMap<EventStatus, List<Event>> sortAndGroupByStatus | ||
= groupByEventStatus(nowDate, events, year, month); | ||
|
||
return filterEventResponsesByStatus(statusName, sortAndGroupByStatus); | ||
} | ||
|
||
private void validateYearAndMonth(final int year, final int month) { | ||
if (year < MIN_YEAR) { | ||
throw new EventException(INVALID_YEAR); | ||
} | ||
if (month < MIN_MONTH || month > MAX_MONTH) { | ||
throw new EventException(INVALID_MONTH); | ||
} | ||
} | ||
|
||
private List<Event> filterEventsByTag(final String tagName) { | ||
if (isExistTagName(tagName)) { | ||
Tag tag = tagRepository.findByName(tagName) | ||
.orElseThrow(() -> new TagException(NOT_FOUND_TAG)); | ||
|
||
return eventTagRepository.findEventTagsByTag(tag) | ||
.stream() | ||
.map(EventTag::getEvent) | ||
.collect(toList()); | ||
} | ||
return eventRepository.findAll(); | ||
} | ||
|
||
private boolean isExistTagName(final String tagName) { | ||
return tagName != null; | ||
} | ||
|
||
private EnumMap<EventStatus, List<Event>> groupByEventStatus(final LocalDate nowDate, | ||
final List<Event> events, final int year, final int month) { | ||
return events.stream() | ||
.filter(event -> isOverlapToMonth(year, month, | ||
event.getStartDate().toLocalDate(), event.getEndDate().toLocalDate()) | ||
) | ||
.sorted(comparing(Event::getStartDate)) | ||
.collect( | ||
groupingBy(event -> extractEventStatus(nowDate, event.getStartDate().toLocalDate(), | ||
event.getEndDate().toLocalDate()), () -> new EnumMap<>(EventStatus.class), toList()) | ||
); | ||
} | ||
|
||
private boolean isOverlapToMonth(final int year, final int month, | ||
final LocalDate eventStart, final LocalDate eventEnd) { | ||
LocalDate monthStart = LocalDate.of(year, month, 1); | ||
LocalDate monthEnd = LocalDate.of(year, month, monthStart.lengthOfMonth()); | ||
|
||
return (isBeforeOrEquals(eventStart, monthEnd) && isBeforeOrEquals(monthStart, eventEnd)) | ||
|| (isBeforeOrEquals(monthStart, eventStart) && isBeforeOrEquals(eventStart, monthEnd)) | ||
|| (isBeforeOrEquals(monthStart, eventEnd) && isBeforeOrEquals(eventEnd, monthEnd)); | ||
} | ||
|
||
private boolean isBeforeOrEquals(LocalDate criteria, LocalDate comparison) { | ||
return criteria.isBefore(comparison) || criteria.isEqual(comparison); | ||
} | ||
|
||
private EventStatus extractEventStatus(LocalDate now, LocalDate startDate, LocalDate endDate) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 메서드를 Event 안으로 밀어넣어 처리할 수 있지 않을까요? |
||
if (now.isBefore(startDate)) { | ||
return EventStatus.UPCOMING; | ||
} | ||
if (now.isAfter(endDate)) { | ||
return EventStatus.ENDED; | ||
} | ||
return EventStatus.IN_PROGRESS; | ||
} | ||
|
||
private List<EventResponse> filterEventResponsesByStatus(final String statusName, | ||
final EnumMap<EventStatus, List<Event>> sortAndGroupByEventStatus) { | ||
if (isaBoolean(statusName)) { | ||
EventStatus status = findEventStatusByValue(statusName); | ||
return makeEventResponsesByStatus(status, sortAndGroupByEventStatus.get(status)); | ||
} | ||
return mergeEventResponses(sortAndGroupByEventStatus); | ||
} | ||
|
||
private boolean isaBoolean(final String statusName) { | ||
return statusName != null; | ||
} | ||
|
||
private EventStatus findEventStatusByValue(final String value) { | ||
return Arrays.stream(EventStatus.values()) | ||
.filter(status -> status.isSameValue(value)) | ||
.findFirst() | ||
.orElseThrow(() -> new EventException(INVALID_STATUS)); | ||
} | ||
|
||
private List<EventResponse> makeEventResponsesByStatus(EventStatus status, | ||
List<Event> events) { | ||
return events.stream() | ||
.map(event -> EventResponse.from(status, event)) | ||
.collect(toList()); | ||
} | ||
|
||
private List<EventResponse> mergeEventResponses( | ||
final EnumMap<EventStatus, List<Event>> groupByEventStatus) { | ||
return groupByEventStatus.entrySet().stream() | ||
.map(entry -> makeEventResponsesByStatus(entry.getKey(), entry.getValue())) | ||
.reduce(new ArrayList<>(), (combinedEvents, eventsToAdd) -> { | ||
combinedEvents.addAll(eventsToAdd); | ||
return combinedEvents; | ||
}); | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
backend/emm-sale/src/main/java/com/emmsale/event/application/dto/EventResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package com.emmsale.event.application.dto; | ||
|
||
import com.emmsale.event.domain.Event; | ||
import com.emmsale.event.domain.EventStatus; | ||
import com.fasterxml.jackson.annotation.JsonFormat; | ||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public class EventResponse { | ||
|
||
private final Long id; | ||
private final String name; | ||
@JsonFormat(pattern = "yyyy:MM:dd:HH:mm:ss") | ||
private final LocalDateTime startDate; | ||
@JsonFormat(pattern = "yyyy:MM:dd:HH:mm:ss") | ||
private final LocalDateTime endDate; | ||
private final List<String> tags; | ||
private final String status; | ||
|
||
public static EventResponse from(EventStatus status, Event event) { | ||
return | ||
new EventResponse(event.getId(), event.getName(), event.getStartDate(), event.getEndDate(), | ||
event.getTags() | ||
.stream() | ||
.map(tag -> tag.getTag().getName()) | ||
.collect(Collectors.toList()), status.getValue()); | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
backend/emm-sale/src/main/java/com/emmsale/event/domain/EventStatus.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.emmsale.event.domain; | ||
|
||
import lombok.Getter; | ||
|
||
@Getter | ||
public enum EventStatus { | ||
|
||
IN_PROGRESS("진행 중"), | ||
UPCOMING("진행 예정"), | ||
ENDED("종료된 행사"); | ||
|
||
private final String value; | ||
|
||
EventStatus(final String value) { | ||
this.value = value; | ||
} | ||
|
||
public boolean isSameValue(String value) { | ||
return this.value.equals(value); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
backend/emm-sale/src/main/java/com/emmsale/event/domain/EventTagRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.emmsale.event.domain; | ||
|
||
import com.emmsale.tag.domain.Tag; | ||
import java.util.List; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface EventTagRepository extends JpaRepository<EventTag, Long> { | ||
|
||
List<EventTag> findEventTagsByTag(Tag tag); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
backend/emm-sale/src/main/java/com/emmsale/tag/domain/TagRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.emmsale.tag.domain; | ||
|
||
import java.util.Optional; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface TagRepository extends JpaRepository<Tag, Long> { | ||
|
||
Optional<Tag> findByName(String name); | ||
} |
19 changes: 19 additions & 0 deletions
19
backend/emm-sale/src/main/java/com/emmsale/tag/exception/TagException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.emmsale.tag.exception; | ||
|
||
import com.emmsale.base.BaseException; | ||
import com.emmsale.base.BaseExceptionType; | ||
|
||
public class TagException extends BaseException { | ||
|
||
private final TagExceptionType exceptionType; | ||
|
||
public TagException(final TagExceptionType exceptionType) { | ||
super(exceptionType.errorMessage()); | ||
this.exceptionType = exceptionType; | ||
} | ||
|
||
@Override | ||
public BaseExceptionType exceptionType() { | ||
return exceptionType; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
MIN_YEAR를 정한 이유가 있을까요?