From 5c4a2eb2ea6eef1cc6fd10f3e2baf081e4173bc8 Mon Sep 17 00:00:00 2001 From: amaran-th Date: Tue, 25 Jul 2023 22:45:03 +0900 Subject: [PATCH 01/10] =?UTF-8?q?feat:=20=EC=9B=94=20=EB=B3=84=EB=A1=9C=20?= =?UTF-8?q?=ED=95=84=ED=84=B0=EB=A7=81=ED=95=98=EC=97=AC=20=ED=96=89?= =?UTF-8?q?=EC=82=AC=20=EB=AA=A9=EB=A1=9D=EC=9D=84=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 월 별로 필터링할 수 있다. - 결과는 status가 진행중, 진행 예정, 종료된 행사 순으로 정렬한다. - 같은 status인 결과들은 시작일을 기준으로 오름차순 정렬한다. #86 --- .../java/com/emmsale/event/api/EventApi.java | 29 ++++++ .../event/application/EventService.java | 88 +++++++++++++++++++ .../event/application/dto/EventResponse.java | 30 +++++++ .../java/com/emmsale/event/domain/Event.java | 7 ++ .../emmsale/event/domain/EventRepository.java | 7 ++ .../com/emmsale/event/domain/EventStatus.java | 18 ++++ .../com/emmsale/event/domain/EventTag.java | 5 ++ .../main/java/com/emmsale/tag/domain/Tag.java | 5 ++ backend/emm-sale/src/main/resources/data.sql | 53 +++++++++++ .../src/main/resources/http/event.http | 2 + .../event/application/EventServiceTest.java | 80 +++++++++++++++++ 11 files changed, 324 insertions(+) create mode 100644 backend/emm-sale/src/main/java/com/emmsale/event/api/EventApi.java create mode 100644 backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java create mode 100644 backend/emm-sale/src/main/java/com/emmsale/event/application/dto/EventResponse.java create mode 100644 backend/emm-sale/src/main/java/com/emmsale/event/domain/EventRepository.java create mode 100644 backend/emm-sale/src/main/java/com/emmsale/event/domain/EventStatus.java create mode 100644 backend/emm-sale/src/main/resources/http/event.http create mode 100644 backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/api/EventApi.java b/backend/emm-sale/src/main/java/com/emmsale/event/api/EventApi.java new file mode 100644 index 000000000..a28597336 --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/event/api/EventApi.java @@ -0,0 +1,29 @@ +package com.emmsale.event.api; + +import com.emmsale.event.application.EventService; +import com.emmsale.event.application.dto.EventResponse; +import java.time.LocalDate; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/events") +@RequiredArgsConstructor +public class EventApi { + + private final EventService eventService; + + @GetMapping + public ResponseEntity> findEvents(@RequestParam final int year, + @RequestParam final int month, @RequestParam(required = false) final List tags, + @RequestParam(required = false) final String status) { + + return ResponseEntity.ok(eventService.findEvents(LocalDate.now(), year, month, tags, status)); + } + +} diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java new file mode 100644 index 000000000..69292dc1c --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java @@ -0,0 +1,88 @@ +package com.emmsale.event.application; + +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.EventResponse; +import com.emmsale.event.domain.Event; +import com.emmsale.event.domain.EventRepository; +import com.emmsale.event.domain.EventStatus; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map.Entry; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +@RequiredArgsConstructor +public class EventService { + + private final EventRepository eventRepository; + + public List findEvents(final LocalDate nowDate, final int year, final int month, + final List tags, final String status) { + + List events = eventRepository.findAll(); + + final EnumMap> sortAndGroupByEventStatus + = groupByEventStatus(nowDate, events, year, month); + + return makeEventResponses(sortAndGroupByEventStatus); + } + + private EnumMap> groupByEventStatus(final LocalDate nowDate, + final List 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) { + if (now.isBefore(startDate)) { + return EventStatus.UPCOMING; + } + if (now.isAfter(endDate)) { + return EventStatus.ENDED; + } + return EventStatus.IN_PROGRESS; + } + + private List makeEventResponses( + final EnumMap> groupByEventStatus) { + List responses = new ArrayList<>(); + + for (final Entry> entry : groupByEventStatus.entrySet()) { + final List statusResponses = entry.getValue() + .stream() + .map(event -> EventResponse.from(entry.getKey(), event)) + .collect(toList()); + responses.addAll(statusResponses); + } + return responses; + } +} diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/application/dto/EventResponse.java b/backend/emm-sale/src/main/java/com/emmsale/event/application/dto/EventResponse.java new file mode 100644 index 000000000..769954db0 --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/event/application/dto/EventResponse.java @@ -0,0 +1,30 @@ +package com.emmsale.event.application.dto; + +import com.emmsale.event.domain.Event; +import com.emmsale.event.domain.EventStatus; +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; + private final LocalDateTime startDate; + private final LocalDateTime endDate; + private final List 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()); + } +} diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/domain/Event.java b/backend/emm-sale/src/main/java/com/emmsale/event/domain/Event.java index dd7dd9877..376093ce6 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/domain/Event.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/domain/Event.java @@ -10,8 +10,13 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; @Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class Event extends BaseEntity { @Id @@ -34,4 +39,6 @@ public class Event extends BaseEntity { //@OneToMany //private List participants; + + } diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventRepository.java b/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventRepository.java new file mode 100644 index 000000000..a650ef68c --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventRepository.java @@ -0,0 +1,7 @@ +package com.emmsale.event.domain; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface EventRepository extends JpaRepository { + +} diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventStatus.java b/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventStatus.java new file mode 100644 index 000000000..aadffcb1b --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventStatus.java @@ -0,0 +1,18 @@ +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; + } + +} diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventTag.java b/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventTag.java index 959ebf66f..28349cfb6 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventTag.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventTag.java @@ -8,8 +8,13 @@ import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +@Getter @Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class EventTag { @Id diff --git a/backend/emm-sale/src/main/java/com/emmsale/tag/domain/Tag.java b/backend/emm-sale/src/main/java/com/emmsale/tag/domain/Tag.java index 8333b2fbe..3a9364918 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/tag/domain/Tag.java +++ b/backend/emm-sale/src/main/java/com/emmsale/tag/domain/Tag.java @@ -5,8 +5,13 @@ import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +@Getter @Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class Tag { @Id diff --git a/backend/emm-sale/src/main/resources/data.sql b/backend/emm-sale/src/main/resources/data.sql index 9029b97bd..6209760ea 100644 --- a/backend/emm-sale/src/main/resources/data.sql +++ b/backend/emm-sale/src/main/resources/data.sql @@ -44,3 +44,56 @@ values (3, 3, 1, CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); insert into member_activity(id, activity_id, member_id, created_at, updated_at) values (4, 1, 2, CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); + +insert into tag(id, name) +values (1, '백엔드'); +insert into tag(id, name) +values (2, '프론트엔드'); +insert into tag(id, name) +values (3, '안드로이드'); +insert into tag(id, name) +values (4, 'IOS'); +insert into tag(id, name) +values (5, 'AI'); + +insert into event(id, name, start_date, end_date, location, information_url, created_at, updated_at) +values (1, '인프콘 2023', '2023-06-01T12:00:00', '2023-09-01T12:00:00', '코엑스', 'https://~~~', + CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); +insert into event(id, name, start_date, end_date, location, information_url, created_at, updated_at) +values (2, 'AI 컨퍼런스', '2023-07-22T12:00:00', '2023-07-30T12:00:00', '코엑스', 'https://~~~', + CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); +insert into event(id, name, start_date, end_date, location, information_url, created_at, updated_at) +values (3, '모바일 컨퍼런스', '2023-08-03T12:00:00', '2023-09-03T12:00:00', '코엑스', 'https://~~~', + CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); +insert into event(id, name, start_date, end_date, location, information_url, created_at, updated_at) +values (4, '안드로이드 컨퍼런스', '2023-06-29T12:00:00', '2023-07-16T12:00:00', '코엑스', 'https://~~~', + CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); +insert into event(id, name, start_date, end_date, location, information_url, created_at, updated_at) +values (5, '웹 컨퍼런스', '2023-07-03T12:00:00', '2023-08-03T12:00:00', '코엑스', 'https://~~~', + CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); +insert into event(id, name, start_date, end_date, location, information_url, created_at, updated_at) +values (6, '옛날 웹 컨퍼런스', '2022-07-03T12:00:00', '2022-08-03T12:00:00', '코엑스', 'https://~~~', + CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); + +insert into event_tag(id, event_id, tag_id) +values (1, 1, 1); +insert into event_tag(id, event_id, tag_id) +values (2, 1, 2); +insert into event_tag(id, event_id, tag_id) +values (3, 1, 3); +insert into event_tag(id, event_id, tag_id) +values (4, 1, 4); +insert into event_tag(id, event_id, tag_id) +values (5, 1, 5); +insert into event_tag(id, event_id, tag_id) +values (6, 2, 5); +insert into event_tag(id, event_id, tag_id) +values (7, 3, 3); +insert into event_tag(id, event_id, tag_id) +values (8, 3, 4); +insert into event_tag(id, event_id, tag_id) +values (9, 4, 3); +insert into event_tag(id, event_id, tag_id) +values (10, 5, 1); +insert into event_tag(id, event_id, tag_id) +values (11, 5, 2); \ No newline at end of file diff --git a/backend/emm-sale/src/main/resources/http/event.http b/backend/emm-sale/src/main/resources/http/event.http new file mode 100644 index 000000000..d77d1dec0 --- /dev/null +++ b/backend/emm-sale/src/main/resources/http/event.http @@ -0,0 +1,2 @@ +GET http://localhost:8080/events?year=2023&month=7&tags=aa,bbb,ccc +Content-Type: application/json diff --git a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java new file mode 100644 index 000000000..373f6d804 --- /dev/null +++ b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java @@ -0,0 +1,80 @@ +package com.emmsale.event.application; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.emmsale.event.application.dto.EventResponse; +import com.emmsale.helper.ServiceIntegrationTestHelper; +import java.time.LocalDate; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class EventServiceTest extends ServiceIntegrationTestHelper { + + @Autowired + private EventService eventService; + + @Nested + @DisplayName("연도&월 별 필터링 및 정렬 기능 테스트") + class dateFilterAndSort { + + @Test + @DisplayName("2023년 7월 21일에 2023년 7월 행사를 조회하면, 해당 연도&월에 걸쳐있는 모든 행사 목록을 조회할 수 있다.") + void findEvents_2023_7() { + // given + final List expectedEvents = List.of( + new EventResponse(null, "인프콘 2023", null, null, List.of(), "진행 중"), + new EventResponse(null, "웹 컨퍼런스", null, null, List.of(), "진행 중"), + new EventResponse(null, "AI 컨퍼런스", null, null, List.of(), "진행 예정"), + new EventResponse(null, "안드로이드 컨퍼런스", null, null, List.of(), "종료된 행사") + ); + + // when + final List actualEvents = eventService.findEvents(LocalDate.of(2023, 7, 21), + 2023, 7, null, null); + + // then + assertThat(actualEvents).usingRecursiveComparison().comparingOnlyFields("name", "status") + .isEqualTo(expectedEvents); + } + + @Test + @DisplayName("2023년 7월 21일에 2023년 8월 행사를 조회하면, 해당 연도&월에 걸쳐있는 모든 행사 목록을 조회할 수 있다.") + void findEvents_2023_8() { + // given + final List expectedEvents = List.of( + new EventResponse(null, "인프콘 2023", null, null, List.of(), "진행 중"), + new EventResponse(null, "웹 컨퍼런스", null, null, List.of(), "진행 중"), + new EventResponse(null, "모바일 컨퍼런스", null, null, List.of(), "진행 예정") + ); + + // when + final List actualEvents = eventService.findEvents(LocalDate.of(2023, 7, 21), + 2023, 8, null, null); + + // then + assertThat(actualEvents).usingRecursiveComparison().comparingOnlyFields("name", "status") + .isEqualTo(expectedEvents); + } + + @Test + @DisplayName("2023년 7월 21일에 2023년 6월 행사를 조회하면, 해당 연도&월에 걸쳐있는 모든 행사 목록을 조회할 수 있다.") + void findEvents_2023_6() { + // given + final List expectedEvents = List.of( + new EventResponse(null, "인프콘 2023", null, null, List.of(), "진행 중"), + new EventResponse(null, "안드로이드 컨퍼런스", null, null, List.of(), "종료된 행사") + ); + + // when + final List actualEvents = eventService.findEvents(LocalDate.of(2023, 7, 21), + 2023, 6, null, null); + + // then + assertThat(actualEvents).usingRecursiveComparison().comparingOnlyFields("name", "status") + .isEqualTo(expectedEvents); + } + } +} From fbe7973935fb9316781bd21ddfc0c2d97e232165 Mon Sep 17 00:00:00 2001 From: amaran-th Date: Tue, 25 Jul 2023 23:00:27 +0900 Subject: [PATCH 02/10] =?UTF-8?q?test:=20API=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EB=B0=8F=20RESTDocs=20API=20=EB=AC=B8=EC=84=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #86 --- backend/emm-sale/src/docs/asciidoc/index.adoc | 18 +++- .../com/emmsale/event/api/EventApiTest.java | 85 +++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 backend/emm-sale/src/test/java/com/emmsale/event/api/EventApiTest.java diff --git a/backend/emm-sale/src/docs/asciidoc/index.adoc b/backend/emm-sale/src/docs/asciidoc/index.adoc index edb25a8da..3dcc118f3 100644 --- a/backend/emm-sale/src/docs/asciidoc/index.adoc +++ b/backend/emm-sale/src/docs/asciidoc/index.adoc @@ -91,6 +91,7 @@ include::{snippets}/wish-with-no-authentication-products/request-headers.adoc[] include::{snippets}/wish-with-no-authentication-products/http-response.adoc[] == Career + === `POST`: 커리어 등록 API .HTTP request 설명 @@ -105,7 +106,6 @@ include::{snippets}/add-activity/http-response.adoc[] .HTTP response 설명 include::{snippets}/add-activity/response-fields.adoc[] - === `DELETE`: 커리어 삭제 API .HTTP request 설명 @@ -154,3 +154,19 @@ include::{snippets}/initial-register-member/http-request.adoc[] .HTTP response include::{snippets}/initial-register-member/http-response.adoc[] + +== Event + +=== `GET`: 행사 목록 조회 + +.HTTP request +include::{snippets}/find-events/http-request.adoc[] + +.HTTP request 설명 +include::{snippets}/find-events/request-parameters.adoc[] + +.HTTP response +include::{snippets}/find-events/http-response.adoc[] + +.HTTP response 설명 +include::{snippets}/find-events/response-fields.adoc[] diff --git a/backend/emm-sale/src/test/java/com/emmsale/event/api/EventApiTest.java b/backend/emm-sale/src/test/java/com/emmsale/event/api/EventApiTest.java new file mode 100644 index 000000000..9f73750f8 --- /dev/null +++ b/backend/emm-sale/src/test/java/com/emmsale/event/api/EventApiTest.java @@ -0,0 +1,85 @@ +package com.emmsale.event.api; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.requestParameters; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.emmsale.event.application.EventService; +import com.emmsale.event.application.dto.EventResponse; +import com.emmsale.helper.MockMvcTestHelper; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.restdocs.payload.ResponseFieldsSnippet; +import org.springframework.restdocs.request.RequestParametersSnippet; + +@WebMvcTest(EventApi.class) +class EventApiTest extends MockMvcTestHelper { + + @MockBean + private EventService eventService; + + // TODO: 2023-07-24 월+태그별 컨퍼런스 필터링 + // TODO: 2023-07-24 월+상태별 필터링 + @Test + @DisplayName("특정 연도&월의 행사 목록을 조회할 수 있으면 200 OK를 반환한다.") + void findEvents() throws Exception { + // given + final RequestParametersSnippet requestParameters = requestParameters( + parameterWithName("year").description("조회하고자 하는 연도"), + parameterWithName("month").description("조회하고자 하는 월"), + parameterWithName("tags").description("필터링하려는 태그 목록").optional(), + parameterWithName("status").description("필터링하려는 상태").optional() + ); + + final ResponseFieldsSnippet responseFields = responseFields( + fieldWithPath("[].id").type(JsonFieldType.NUMBER).description("행사 id"), + fieldWithPath("[].name").type(JsonFieldType.STRING).description("행사명"), + fieldWithPath("[].startDate").type(JsonFieldType.STRING).description("행사 시작일"), + fieldWithPath("[].endDate").type(JsonFieldType.STRING).description("행사 종료일"), + fieldWithPath("[].tags[]").type(JsonFieldType.ARRAY) + .description("행사 태그 목록"), + fieldWithPath("[].status").type(JsonFieldType.STRING).description("행사 진행 상황") + ); + + final List eventResponses = List.of( + new EventResponse(1L, "인프콘 2023", LocalDateTime.parse("2023-06-03T12:00:00"), + LocalDateTime.parse("2023-09-03T12:00:00"), + List.of("백엔드", "프론트엔드", "안드로이드", "IOS", "AI"), "진행 중"), + new EventResponse(5L, "웹 컨퍼런스", LocalDateTime.parse("2023-07-03T12:00:00"), + LocalDateTime.parse("2023-08-03T12:00:00"), List.of("백엔드", "프론트엔드"), "진행 중"), + new EventResponse(2L, "AI 컨퍼런스", LocalDateTime.parse("2023-07-22T12:00:00"), + LocalDateTime.parse("2023-07-30T12:00:00"), List.of("AI"), "진행 예정"), + new EventResponse(4L, "안드로이드 컨퍼런스", LocalDateTime.parse("2023-06-29T12:00:00"), + LocalDateTime.parse("2023-07-16T12:00:00"), List.of("백엔드", "프론트엔드"), "종료된 행사") + + ); + + int year = 2023; + int month = 7; + + when(eventService.findEvents(any(LocalDate.class), eq(year), eq(month), eq(null), + eq(null))).thenReturn(eventResponses); + + // when & then + mockMvc.perform(get("/events") + .param("year", "2023") + .param("month", "7") + ) + .andExpect(status().isOk()) + .andDo(document("find-events", requestParameters, responseFields)); + } + +} \ No newline at end of file From fa340cace1e61706f28363e8ff9fe37a805603b6 Mon Sep 17 00:00:00 2001 From: amaran-th Date: Wed, 26 Jul 2023 15:25:24 +0900 Subject: [PATCH 03/10] =?UTF-8?q?feat:=20=ED=96=89=EC=82=AC=20=EC=A7=84?= =?UTF-8?q?=ED=96=89=20=EC=83=81=ED=83=9C=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=ED=95=84=ED=84=B0=EB=A7=81=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #86 --- .../java/com/emmsale/event/api/EventApi.java | 6 +-- .../event/application/EventService.java | 45 +++++++++++++------ .../com/emmsale/event/domain/EventStatus.java | 5 ++- .../event/exception/EventException.java | 19 ++++++++ .../event/exception/EventExceptionType.java | 30 +++++++++++++ .../src/main/resources/http/event.http | 19 +++++++- .../com/emmsale/event/api/EventApiTest.java | 4 +- .../event/application/EventServiceTest.java | 42 ++++++++++++++++- 8 files changed, 147 insertions(+), 23 deletions(-) create mode 100644 backend/emm-sale/src/main/java/com/emmsale/event/exception/EventException.java create mode 100644 backend/emm-sale/src/main/java/com/emmsale/event/exception/EventExceptionType.java diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/api/EventApi.java b/backend/emm-sale/src/main/java/com/emmsale/event/api/EventApi.java index a28597336..d8d4cd2ca 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/api/EventApi.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/api/EventApi.java @@ -20,10 +20,10 @@ public class EventApi { @GetMapping public ResponseEntity> findEvents(@RequestParam final int year, - @RequestParam final int month, @RequestParam(required = false) final List tags, + @RequestParam final int month, @RequestParam(required = false) final String tag, @RequestParam(required = false) final String status) { - - return ResponseEntity.ok(eventService.findEvents(LocalDate.now(), year, month, tags, status)); + + return ResponseEntity.ok(eventService.findEvents(LocalDate.now(), year, month, tag, status)); } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java index 69292dc1c..abd2b42c5 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java @@ -1,5 +1,6 @@ package com.emmsale.event.application; +import static com.emmsale.event.exception.EventExceptionType.INVALID_STATUS; import static java.util.Comparator.comparing; import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.toList; @@ -8,11 +9,12 @@ import com.emmsale.event.domain.Event; import com.emmsale.event.domain.EventRepository; import com.emmsale.event.domain.EventStatus; +import com.emmsale.event.exception.EventException; import java.time.LocalDate; import java.util.ArrayList; +import java.util.Arrays; import java.util.EnumMap; import java.util.List; -import java.util.Map.Entry; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -24,15 +26,34 @@ public class EventService { private final EventRepository eventRepository; + + private static List makeEventResponsesByStatus(EventStatus status, + List events) { + return events.stream() + .map(event -> EventResponse.from(status, event)) + .collect(toList()); + } + public List findEvents(final LocalDate nowDate, final int year, final int month, - final List tags, final String status) { + final String tag, final String status) { List events = eventRepository.findAll(); final EnumMap> sortAndGroupByEventStatus = groupByEventStatus(nowDate, events, year, month); - return makeEventResponses(sortAndGroupByEventStatus); + if (status != null) { + EventStatus eventStatus = findEventStatusByValue(status); + return makeEventResponsesByStatus(eventStatus, sortAndGroupByEventStatus.get(eventStatus)); + } + return mergeEventResponses(sortAndGroupByEventStatus); + } + + private EventStatus findEventStatusByValue(final String value) { + return Arrays.stream(EventStatus.values()) + .filter(status -> status.isSameValue(value)) + .findFirst() + .orElseThrow(() -> new EventException(INVALID_STATUS)); } private EnumMap> groupByEventStatus(final LocalDate nowDate, @@ -72,17 +93,13 @@ private EventStatus extractEventStatus(LocalDate now, LocalDate startDate, Local return EventStatus.IN_PROGRESS; } - private List makeEventResponses( + private List mergeEventResponses( final EnumMap> groupByEventStatus) { - List responses = new ArrayList<>(); - - for (final Entry> entry : groupByEventStatus.entrySet()) { - final List statusResponses = entry.getValue() - .stream() - .map(event -> EventResponse.from(entry.getKey(), event)) - .collect(toList()); - responses.addAll(statusResponses); - } - return responses; + return groupByEventStatus.entrySet().stream() + .map(entry -> makeEventResponsesByStatus(entry.getKey(), entry.getValue())) + .reduce(new ArrayList<>(), (combinedEvents, eventsToAdd) -> { + combinedEvents.addAll(eventsToAdd); + return combinedEvents; + }); } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventStatus.java b/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventStatus.java index aadffcb1b..23d2c044c 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventStatus.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventStatus.java @@ -4,7 +4,7 @@ @Getter public enum EventStatus { - + IN_PROGRESS("진행 중"), UPCOMING("진행 예정"), ENDED("종료된 행사"); @@ -15,4 +15,7 @@ public enum EventStatus { this.value = value; } + public boolean isSameValue(String value) { + return this.value.equals(value); + } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/exception/EventException.java b/backend/emm-sale/src/main/java/com/emmsale/event/exception/EventException.java new file mode 100644 index 000000000..18908405d --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/event/exception/EventException.java @@ -0,0 +1,19 @@ +package com.emmsale.event.exception; + +import com.emmsale.base.BaseException; +import com.emmsale.base.BaseExceptionType; + +public class EventException extends BaseException { + + private final EventExceptionType exceptionType; + + public EventException(final EventExceptionType exceptionType) { + super(exceptionType.errorMessage()); + this.exceptionType = exceptionType; + } + + @Override + public BaseExceptionType exceptionType() { + return exceptionType; + } +} diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/exception/EventExceptionType.java b/backend/emm-sale/src/main/java/com/emmsale/event/exception/EventExceptionType.java new file mode 100644 index 000000000..fd19839da --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/event/exception/EventExceptionType.java @@ -0,0 +1,30 @@ +package com.emmsale.event.exception; + +import com.emmsale.base.BaseExceptionType; +import org.springframework.http.HttpStatus; + +public enum EventExceptionType implements BaseExceptionType { + + INVALID_STATUS( + HttpStatus.BAD_REQUEST, + "요청하신 상태는 유효하지 않는 값입니다." + ); + + private final HttpStatus httpStatus; + private final String errorMessage; + + EventExceptionType(final HttpStatus httpStatus, final String errorMessage) { + this.httpStatus = httpStatus; + this.errorMessage = errorMessage; + } + + @Override + public HttpStatus httpStatus() { + return httpStatus; + } + + @Override + public String errorMessage() { + return errorMessage; + } +} diff --git a/backend/emm-sale/src/main/resources/http/event.http b/backend/emm-sale/src/main/resources/http/event.http index d77d1dec0..3399fb67e 100644 --- a/backend/emm-sale/src/main/resources/http/event.http +++ b/backend/emm-sale/src/main/resources/http/event.http @@ -1,2 +1,19 @@ -GET http://localhost:8080/events?year=2023&month=7&tags=aa,bbb,ccc +### 필터링 없이 특정 연도 & 월의 행사 목록 조회 + +GET http://localhost:8080/events?year=2023&month=7 +Content-Type: application/json + +### 상태 필터링이 적용된 경우 + +GET http://localhost:8080/events?year=2023&month=7&status=진행 중 +Content-Type: application/json + +### 태그 필터링이 적용된 경우 + +GET http://localhost:8080/events?year=2023&month=7&tag=안드로이드 +Content-Type: application/json + +### 태그 필터링과 상태 필터링이 모두 적용된 경우 + +GET http://localhost:8080/events?year=2023&month=7&tag=백엔드&status=진행 중 Content-Type: application/json diff --git a/backend/emm-sale/src/test/java/com/emmsale/event/api/EventApiTest.java b/backend/emm-sale/src/test/java/com/emmsale/event/api/EventApiTest.java index 9f73750f8..597c1e52b 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/event/api/EventApiTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/event/api/EventApiTest.java @@ -40,8 +40,8 @@ void findEvents() throws Exception { final RequestParametersSnippet requestParameters = requestParameters( parameterWithName("year").description("조회하고자 하는 연도"), parameterWithName("month").description("조회하고자 하는 월"), - parameterWithName("tags").description("필터링하려는 태그 목록").optional(), - parameterWithName("status").description("필터링하려는 상태").optional() + parameterWithName("tag").optional().description("필터링하려는 태그"), + parameterWithName("status").optional().description("필터링하려는 상태") ); final ResponseFieldsSnippet responseFields = responseFields( diff --git a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java index 373f6d804..5d182cfb6 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java @@ -1,11 +1,15 @@ package com.emmsale.event.application; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.emmsale.event.application.dto.EventResponse; +import com.emmsale.event.exception.EventException; +import com.emmsale.event.exception.EventExceptionType; import com.emmsale.helper.ServiceIntegrationTestHelper; import java.time.LocalDate; import java.util.List; +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -17,8 +21,8 @@ class EventServiceTest extends ServiceIntegrationTestHelper { private EventService eventService; @Nested - @DisplayName("연도&월 별 필터링 및 정렬 기능 테스트") - class dateFilterAndSort { + @DisplayName("findEvents() : 행사 목록 조회") + class findEvents { @Test @DisplayName("2023년 7월 21일에 2023년 7월 행사를 조회하면, 해당 연도&월에 걸쳐있는 모든 행사 목록을 조회할 수 있다.") @@ -76,5 +80,39 @@ void findEvents_2023_6() { assertThat(actualEvents).usingRecursiveComparison().comparingOnlyFields("name", "status") .isEqualTo(expectedEvents); } + + @Test + @DisplayName("'진행 중' 상태의 행사 목록을 조회할 수 있다.") + void findEvents_status_filter() { + // given + final List expectedEvents = List.of( + new EventResponse(null, "인프콘 2023", null, null, List.of(), "진행 중"), + new EventResponse(null, "웹 컨퍼런스", null, null, List.of(), "진행 중") + ); + + // when + final List actualEvents = eventService.findEvents(LocalDate.of(2023, 7, 21), + 2023, 7, null, "진행 중"); + + // then + assertThat(actualEvents) + .usingRecursiveComparison() + .comparingOnlyFields("name", "status") + .isEqualTo(expectedEvents); + } + + @Test + @DisplayName("잘못된 양식의 status가 입력으로 들어오면 예외를 반환한다.") + void findEvents_status_filter_fail() { + // given, when + final ThrowingCallable actual = () -> eventService.findEvents(LocalDate.of(2023, 7, 21), + 2023, 7, null, "존재하지 않는 상태"); + + // then + assertThatThrownBy(actual) + .isInstanceOf(EventException.class) + .hasMessage(EventExceptionType.INVALID_STATUS.errorMessage()); + ; + } } } From 1df808e2ac99ff0ae407bd6f192b6b0325626e32 Mon Sep 17 00:00:00 2001 From: amaran-th Date: Wed, 26 Jul 2023 15:25:57 +0900 Subject: [PATCH 04/10] =?UTF-8?q?feat:=20=EB=B0=98=ED=99=98=EB=90=98?= =?UTF-8?q?=EB=8A=94=20DateTime=20=ED=8F=AC=EB=A7=B7=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #86 --- .../java/com/emmsale/event/application/dto/EventResponse.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/application/dto/EventResponse.java b/backend/emm-sale/src/main/java/com/emmsale/event/application/dto/EventResponse.java index 769954db0..bc10795c4 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/application/dto/EventResponse.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/application/dto/EventResponse.java @@ -2,6 +2,7 @@ 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; @@ -14,7 +15,9 @@ 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 tags; private final String status; From 61e900b0711002c9edc915cc4365fbaf9afa7e1e Mon Sep 17 00:00:00 2001 From: amaran-th Date: Wed, 26 Jul 2023 18:50:32 +0900 Subject: [PATCH 05/10] =?UTF-8?q?feat:=20Tag=EB=A1=9C=20=ED=96=89=EC=82=AC?= =?UTF-8?q?=20=EB=AA=A9=EB=A1=9D=20=ED=95=84=ED=84=B0=EB=A7=81=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #86 --- .../event/application/EventService.java | 67 +++++++++++++------ .../event/domain/EventTagRepository.java | 11 +++ .../com/emmsale/tag/domain/TagRepository.java | 9 +++ .../emmsale/tag/exception/TagException.java | 19 ++++++ .../tag/exception/TagExceptionType.java | 30 +++++++++ .../src/main/resources/http/event.http | 2 + .../event/application/EventServiceTest.java | 35 ++++++++++ 7 files changed, 152 insertions(+), 21 deletions(-) create mode 100644 backend/emm-sale/src/main/java/com/emmsale/event/domain/EventTagRepository.java create mode 100644 backend/emm-sale/src/main/java/com/emmsale/tag/domain/TagRepository.java create mode 100644 backend/emm-sale/src/main/java/com/emmsale/tag/exception/TagException.java create mode 100644 backend/emm-sale/src/main/java/com/emmsale/tag/exception/TagExceptionType.java diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java index abd2b42c5..54e8adf6b 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java @@ -1,6 +1,7 @@ package com.emmsale.event.application; import static com.emmsale.event.exception.EventExceptionType.INVALID_STATUS; +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; @@ -9,7 +10,12 @@ import com.emmsale.event.domain.Event; import com.emmsale.event.domain.EventRepository; import com.emmsale.event.domain.EventStatus; +import com.emmsale.event.domain.EventTag; +import com.emmsale.event.domain.EventTagRepository; 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; @@ -25,35 +31,31 @@ public class EventService { private final EventRepository eventRepository; - - - private static List makeEventResponsesByStatus(EventStatus status, - List events) { - return events.stream() - .map(event -> EventResponse.from(status, event)) - .collect(toList()); - } + private final EventTagRepository eventTagRepository; + private final TagRepository tagRepository; public List findEvents(final LocalDate nowDate, final int year, final int month, - final String tag, final String status) { + final String tagName, final String statusName) { - List events = eventRepository.findAll(); + List events = filterEventsByTag(tagName); - final EnumMap> sortAndGroupByEventStatus + final EnumMap> sortAndGroupByStatus = groupByEventStatus(nowDate, events, year, month); - if (status != null) { - EventStatus eventStatus = findEventStatusByValue(status); - return makeEventResponsesByStatus(eventStatus, sortAndGroupByEventStatus.get(eventStatus)); - } - return mergeEventResponses(sortAndGroupByEventStatus); + return filterEventResponsesByStatus(statusName, sortAndGroupByStatus); } - private EventStatus findEventStatusByValue(final String value) { - return Arrays.stream(EventStatus.values()) - .filter(status -> status.isSameValue(value)) - .findFirst() - .orElseThrow(() -> new EventException(INVALID_STATUS)); + private List filterEventsByTag(final String tagName) { + if (tagName != null) { + 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 EnumMap> groupByEventStatus(final LocalDate nowDate, @@ -93,6 +95,29 @@ private EventStatus extractEventStatus(LocalDate now, LocalDate startDate, Local return EventStatus.IN_PROGRESS; } + private List filterEventResponsesByStatus(final String statusName, + final EnumMap> sortAndGroupByEventStatus) { + if (statusName != null) { + EventStatus status = findEventStatusByValue(statusName); + return makeEventResponsesByStatus(status, sortAndGroupByEventStatus.get(status)); + } + return mergeEventResponses(sortAndGroupByEventStatus); + } + + private EventStatus findEventStatusByValue(final String value) { + return Arrays.stream(EventStatus.values()) + .filter(status -> status.isSameValue(value)) + .findFirst() + .orElseThrow(() -> new EventException(INVALID_STATUS)); + } + + private List makeEventResponsesByStatus(EventStatus status, + List events) { + return events.stream() + .map(event -> EventResponse.from(status, event)) + .collect(toList()); + } + private List mergeEventResponses( final EnumMap> groupByEventStatus) { return groupByEventStatus.entrySet().stream() diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventTagRepository.java b/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventTagRepository.java new file mode 100644 index 000000000..c6a46c42e --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventTagRepository.java @@ -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 { + + List findEventTagsByTag(Tag tag); + +} diff --git a/backend/emm-sale/src/main/java/com/emmsale/tag/domain/TagRepository.java b/backend/emm-sale/src/main/java/com/emmsale/tag/domain/TagRepository.java new file mode 100644 index 000000000..b3d8b9416 --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/tag/domain/TagRepository.java @@ -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 { + + Optional findByName(String name); +} diff --git a/backend/emm-sale/src/main/java/com/emmsale/tag/exception/TagException.java b/backend/emm-sale/src/main/java/com/emmsale/tag/exception/TagException.java new file mode 100644 index 000000000..2d4e93e9a --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/tag/exception/TagException.java @@ -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; + } +} \ No newline at end of file diff --git a/backend/emm-sale/src/main/java/com/emmsale/tag/exception/TagExceptionType.java b/backend/emm-sale/src/main/java/com/emmsale/tag/exception/TagExceptionType.java new file mode 100644 index 000000000..30813e142 --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/tag/exception/TagExceptionType.java @@ -0,0 +1,30 @@ +package com.emmsale.tag.exception; + +import com.emmsale.base.BaseExceptionType; +import org.springframework.http.HttpStatus; + +public enum TagExceptionType implements BaseExceptionType { + + NOT_FOUND_TAG( + HttpStatus.NOT_FOUND, + "해당 태그가 존재하지 않습니다." + ); + + private final HttpStatus httpStatus; + private final String errorMessage; + + TagExceptionType(final HttpStatus httpStatus, final String errorMessage) { + this.httpStatus = httpStatus; + this.errorMessage = errorMessage; + } + + @Override + public HttpStatus httpStatus() { + return httpStatus; + } + + @Override + public String errorMessage() { + return errorMessage; + } +} diff --git a/backend/emm-sale/src/main/resources/http/event.http b/backend/emm-sale/src/main/resources/http/event.http index 3399fb67e..3e287e809 100644 --- a/backend/emm-sale/src/main/resources/http/event.http +++ b/backend/emm-sale/src/main/resources/http/event.http @@ -1,3 +1,5 @@ +## 행사 목록 조회 + ### 필터링 없이 특정 연도 & 월의 행사 목록 조회 GET http://localhost:8080/events?year=2023&month=7 diff --git a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java index 5d182cfb6..c304ba679 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java @@ -7,6 +7,8 @@ import com.emmsale.event.exception.EventException; import com.emmsale.event.exception.EventExceptionType; import com.emmsale.helper.ServiceIntegrationTestHelper; +import com.emmsale.tag.exception.TagException; +import com.emmsale.tag.exception.TagExceptionType; import java.time.LocalDate; import java.util.List; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; @@ -81,6 +83,39 @@ void findEvents_2023_6() { .isEqualTo(expectedEvents); } + @Test + @DisplayName("'안드로이드' 태그를 포함하는 행사 목록을 조회할 수 있다.") + void findEvents_tag_filter() { + // given + final List expectedEvents = List.of( + new EventResponse(null, "인프콘 2023", null, null, List.of(), "진행 중"), + new EventResponse(null, "안드로이드 컨퍼런스", null, null, List.of(), "종료된 행사") + ); + + // when + final List actualEvents = eventService.findEvents(LocalDate.of(2023, 7, 21), + 2023, 7, "안드로이드", null); + + // then + assertThat(actualEvents) + .usingRecursiveComparison() + .comparingOnlyFields("name", "status") + .isEqualTo(expectedEvents); + } + + @Test + @DisplayName("존재하지 않는 태그가 입력으로 들어오면 예외를 반환한다.") + void findEvents_tag_filter_fail() { + // given, when + final ThrowingCallable actual = () -> eventService.findEvents(LocalDate.of(2023, 7, 21), + 2023, 7, "개발", null); + + // then + assertThatThrownBy(actual) + .isInstanceOf(TagException.class) + .hasMessage(TagExceptionType.NOT_FOUND_TAG.errorMessage()); + } + @Test @DisplayName("'진행 중' 상태의 행사 목록을 조회할 수 있다.") void findEvents_status_filter() { From 83d0e1c47bd163c050fc8cf9f5787274fe283b89 Mon Sep 17 00:00:00 2001 From: amaran-th Date: Wed, 26 Jul 2023 19:47:41 +0900 Subject: [PATCH 06/10] =?UTF-8?q?test:=20=EC=97=B0=EB=8F=84=20=EB=B0=8F=20?= =?UTF-8?q?=EC=9B=94=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #86 --- .../event/application/EventService.java | 29 +++++- .../event/exception/EventExceptionType.java | 8 ++ .../com/emmsale/event/api/EventApiTest.java | 13 +-- .../event/application/EventServiceTest.java | 95 +++++++++++-------- 4 files changed, 95 insertions(+), 50 deletions(-) diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java index 54e8adf6b..86d0d94ab 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java @@ -1,6 +1,8 @@ package com.emmsale.event.application; +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; @@ -30,13 +32,17 @@ @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; public List findEvents(final LocalDate nowDate, final int year, final int month, final String tagName, final String statusName) { - + validateYearAndMonth(year, month); List events = filterEventsByTag(tagName); final EnumMap> sortAndGroupByStatus @@ -45,8 +51,17 @@ public List findEvents(final LocalDate nowDate, final int year, f 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 filterEventsByTag(final String tagName) { - if (tagName != null) { + if (isExistTagName(tagName)) { Tag tag = tagRepository.findByName(tagName) .orElseThrow(() -> new TagException(NOT_FOUND_TAG)); @@ -58,6 +73,10 @@ private List filterEventsByTag(final String tagName) { return eventRepository.findAll(); } + private boolean isExistTagName(final String tagName) { + return tagName != null; + } + private EnumMap> groupByEventStatus(final LocalDate nowDate, final List events, final int year, final int month) { return events.stream() @@ -97,13 +116,17 @@ private EventStatus extractEventStatus(LocalDate now, LocalDate startDate, Local private List filterEventResponsesByStatus(final String statusName, final EnumMap> sortAndGroupByEventStatus) { - if (statusName != null) { + 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)) diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/exception/EventExceptionType.java b/backend/emm-sale/src/main/java/com/emmsale/event/exception/EventExceptionType.java index fd19839da..a16f5a15f 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/exception/EventExceptionType.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/exception/EventExceptionType.java @@ -8,6 +8,14 @@ public enum EventExceptionType implements BaseExceptionType { INVALID_STATUS( HttpStatus.BAD_REQUEST, "요청하신 상태는 유효하지 않는 값입니다." + ), + INVALID_YEAR( + HttpStatus.BAD_REQUEST, + "연도 값은 2015 이상이어야 합니다." + ), + INVALID_MONTH( + HttpStatus.BAD_REQUEST, + "월은 1에서 12 사이여야 합니다." ); private final HttpStatus httpStatus; diff --git a/backend/emm-sale/src/test/java/com/emmsale/event/api/EventApiTest.java b/backend/emm-sale/src/test/java/com/emmsale/event/api/EventApiTest.java index 597c1e52b..430605ca5 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/event/api/EventApiTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/event/api/EventApiTest.java @@ -28,11 +28,11 @@ @WebMvcTest(EventApi.class) class EventApiTest extends MockMvcTestHelper { + private static final int QUERY_YEAR = 2023; + private static final int QUERY_MONTH = 7; @MockBean private EventService eventService; - // TODO: 2023-07-24 월+태그별 컨퍼런스 필터링 - // TODO: 2023-07-24 월+상태별 필터링 @Test @DisplayName("특정 연도&월의 행사 목록을 조회할 수 있으면 200 OK를 반환한다.") void findEvents() throws Exception { @@ -40,8 +40,8 @@ void findEvents() throws Exception { final RequestParametersSnippet requestParameters = requestParameters( parameterWithName("year").description("조회하고자 하는 연도"), parameterWithName("month").description("조회하고자 하는 월"), - parameterWithName("tag").optional().description("필터링하려는 태그"), - parameterWithName("status").optional().description("필터링하려는 상태") + parameterWithName("tag").description("필터링하려는 태그").optional(), + parameterWithName("status").description("필터링하려는 상태").optional() ); final ResponseFieldsSnippet responseFields = responseFields( @@ -67,10 +67,7 @@ void findEvents() throws Exception { ); - int year = 2023; - int month = 7; - - when(eventService.findEvents(any(LocalDate.class), eq(year), eq(month), eq(null), + when(eventService.findEvents(any(LocalDate.class), eq(QUERY_YEAR), eq(QUERY_MONTH), eq(null), eq(null))).thenReturn(eventResponses); // when & then diff --git a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java index c304ba679..074334b69 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java @@ -15,10 +15,24 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.springframework.beans.factory.annotation.Autowired; class EventServiceTest extends ServiceIntegrationTestHelper { + public static final EventResponse 인프콘_2023 = new EventResponse(null, "인프콘 2023", null, null, + List.of(), "진행 중"); + public static final EventResponse 웹_컨퍼런스 = new EventResponse(null, "웹 컨퍼런스", null, null, + List.of(), + "진행 중"); + public static final EventResponse 안드로이드_컨퍼런스 = new EventResponse(null, "안드로이드 컨퍼런스", null, null, + List.of(), "종료된 행사"); + public static final EventResponse AI_컨퍼런스 = new EventResponse(null, "AI 컨퍼런스", null, null, + List.of(), "진행 예정"); + public static final EventResponse 모바일_컨퍼런스 = new EventResponse(null, "모바일 컨퍼런스", null, null, + List.of(), "진행 예정"); + private static final LocalDate TODAY = LocalDate.of(2023, 7, 21); @Autowired private EventService eventService; @@ -30,16 +44,10 @@ class findEvents { @DisplayName("2023년 7월 21일에 2023년 7월 행사를 조회하면, 해당 연도&월에 걸쳐있는 모든 행사 목록을 조회할 수 있다.") void findEvents_2023_7() { // given - final List expectedEvents = List.of( - new EventResponse(null, "인프콘 2023", null, null, List.of(), "진행 중"), - new EventResponse(null, "웹 컨퍼런스", null, null, List.of(), "진행 중"), - new EventResponse(null, "AI 컨퍼런스", null, null, List.of(), "진행 예정"), - new EventResponse(null, "안드로이드 컨퍼런스", null, null, List.of(), "종료된 행사") - ); + final List expectedEvents = List.of(인프콘_2023, 웹_컨퍼런스, AI_컨퍼런스, 안드로이드_컨퍼런스); // when - final List actualEvents = eventService.findEvents(LocalDate.of(2023, 7, 21), - 2023, 7, null, null); + final List actualEvents = eventService.findEvents(TODAY, 2023, 7, null, null); // then assertThat(actualEvents).usingRecursiveComparison().comparingOnlyFields("name", "status") @@ -50,15 +58,10 @@ void findEvents_2023_7() { @DisplayName("2023년 7월 21일에 2023년 8월 행사를 조회하면, 해당 연도&월에 걸쳐있는 모든 행사 목록을 조회할 수 있다.") void findEvents_2023_8() { // given - final List expectedEvents = List.of( - new EventResponse(null, "인프콘 2023", null, null, List.of(), "진행 중"), - new EventResponse(null, "웹 컨퍼런스", null, null, List.of(), "진행 중"), - new EventResponse(null, "모바일 컨퍼런스", null, null, List.of(), "진행 예정") - ); + final List expectedEvents = List.of(인프콘_2023, 웹_컨퍼런스, 모바일_컨퍼런스); // when - final List actualEvents = eventService.findEvents(LocalDate.of(2023, 7, 21), - 2023, 8, null, null); + final List actualEvents = eventService.findEvents(TODAY, 2023, 8, null, null); // then assertThat(actualEvents).usingRecursiveComparison().comparingOnlyFields("name", "status") @@ -69,32 +72,51 @@ void findEvents_2023_8() { @DisplayName("2023년 7월 21일에 2023년 6월 행사를 조회하면, 해당 연도&월에 걸쳐있는 모든 행사 목록을 조회할 수 있다.") void findEvents_2023_6() { // given - final List expectedEvents = List.of( - new EventResponse(null, "인프콘 2023", null, null, List.of(), "진행 중"), - new EventResponse(null, "안드로이드 컨퍼런스", null, null, List.of(), "종료된 행사") - ); + final List expectedEvents = List.of(인프콘_2023, 안드로이드_컨퍼런스); // when - final List actualEvents = eventService.findEvents(LocalDate.of(2023, 7, 21), - 2023, 6, null, null); + final List actualEvents = eventService.findEvents(TODAY, 2023, 6, null, null); // then assertThat(actualEvents).usingRecursiveComparison().comparingOnlyFields("name", "status") .isEqualTo(expectedEvents); } + @ParameterizedTest + @ValueSource(ints = {2014, 0, -1}) + @DisplayName("유효하지 않은 값이 연도 값으로 들어오면 예외를 반환한다.") + void findEvents_year_fail(int year) { + // given, when + final ThrowingCallable actual = () -> eventService.findEvents(TODAY, year, 7, null, null); + + // then + assertThatThrownBy(actual) + .isInstanceOf(EventException.class) + .hasMessage(EventExceptionType.INVALID_YEAR.errorMessage()); + } + + @ParameterizedTest + @ValueSource(ints = {0, -1, 13, 14}) + @DisplayName("유효하지 않은 값이 월 값으로 들어오면 예외를 반환한다.") + void findEvents_month_fail(int month) { + // given, when + final ThrowingCallable actual = () -> eventService.findEvents(TODAY, 2023, month, null, null); + + // then + assertThatThrownBy(actual) + .isInstanceOf(EventException.class) + .hasMessage(EventExceptionType.INVALID_MONTH.errorMessage()); + } + @Test @DisplayName("'안드로이드' 태그를 포함하는 행사 목록을 조회할 수 있다.") void findEvents_tag_filter() { // given - final List expectedEvents = List.of( - new EventResponse(null, "인프콘 2023", null, null, List.of(), "진행 중"), - new EventResponse(null, "안드로이드 컨퍼런스", null, null, List.of(), "종료된 행사") - ); + final List expectedEvents = List.of(인프콘_2023, 안드로이드_컨퍼런스); // when - final List actualEvents = eventService.findEvents(LocalDate.of(2023, 7, 21), - 2023, 7, "안드로이드", null); + final List actualEvents = eventService.findEvents(TODAY, 2023, 7, "안드로이드", + null); // then assertThat(actualEvents) @@ -107,8 +129,7 @@ void findEvents_tag_filter() { @DisplayName("존재하지 않는 태그가 입력으로 들어오면 예외를 반환한다.") void findEvents_tag_filter_fail() { // given, when - final ThrowingCallable actual = () -> eventService.findEvents(LocalDate.of(2023, 7, 21), - 2023, 7, "개발", null); + final ThrowingCallable actual = () -> eventService.findEvents(TODAY, 2023, 7, "개발", null); // then assertThatThrownBy(actual) @@ -120,14 +141,11 @@ void findEvents_tag_filter_fail() { @DisplayName("'진행 중' 상태의 행사 목록을 조회할 수 있다.") void findEvents_status_filter() { // given - final List expectedEvents = List.of( - new EventResponse(null, "인프콘 2023", null, null, List.of(), "진행 중"), - new EventResponse(null, "웹 컨퍼런스", null, null, List.of(), "진행 중") - ); + final List expectedEvents = List.of(인프콘_2023, 웹_컨퍼런스); // when - final List actualEvents = eventService.findEvents(LocalDate.of(2023, 7, 21), - 2023, 7, null, "진행 중"); + final List actualEvents = eventService.findEvents(TODAY, 2023, 7, null, + "진행 중"); // then assertThat(actualEvents) @@ -137,17 +155,16 @@ void findEvents_status_filter() { } @Test - @DisplayName("잘못된 양식의 status가 입력으로 들어오면 예외를 반환한다.") + @DisplayName("잘못된 양식의 status 가 입력으로 들어오면 예외를 반환한다.") void findEvents_status_filter_fail() { // given, when - final ThrowingCallable actual = () -> eventService.findEvents(LocalDate.of(2023, 7, 21), - 2023, 7, null, "존재하지 않는 상태"); + final ThrowingCallable actual = () -> eventService.findEvents(TODAY, 2023, 7, null, + "존재하지 않는 상태"); // then assertThatThrownBy(actual) .isInstanceOf(EventException.class) .hasMessage(EventExceptionType.INVALID_STATUS.errorMessage()); - ; } } } From 81652241f3221aec79ccd7ebca0afd0711c1be7f Mon Sep 17 00:00:00 2001 From: amaran-th Date: Wed, 26 Jul 2023 21:10:57 +0900 Subject: [PATCH 07/10] =?UTF-8?q?refactor:=20data.sql=20=EC=BF=BC=EB=A6=AC?= =?UTF-8?q?=EB=A5=BC=20Fixture=20=EC=9E=90=EB=B0=94=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=EB=A1=9C=20=EB=8C=80=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #86 --- .../java/com/emmsale/event/domain/Event.java | 13 ++++- .../com/emmsale/event/domain/EventTag.java | 5 ++ .../main/java/com/emmsale/tag/domain/Tag.java | 4 ++ backend/emm-sale/src/main/resources/data.sql | 53 ------------------ .../java/com/emmsale/event/EventFixture.java | 33 +++++++++++ .../event/application/EventServiceTest.java | 55 +++++++++++++++++-- .../test/java/com/emmsale/tag/TagFixture.java | 27 +++++++++ 7 files changed, 131 insertions(+), 59 deletions(-) create mode 100644 backend/emm-sale/src/test/java/com/emmsale/event/EventFixture.java create mode 100644 backend/emm-sale/src/test/java/com/emmsale/tag/TagFixture.java diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/domain/Event.java b/backend/emm-sale/src/main/java/com/emmsale/event/domain/Event.java index 376093ce6..c2f4ffcce 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/domain/Event.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/domain/Event.java @@ -40,5 +40,16 @@ public class Event extends BaseEntity { //@OneToMany //private List participants; - + public Event( + final String name, final String location, + final LocalDateTime startDate, final LocalDateTime endDate, + final String informationUrl, final List tags + ) { + this.name = name; + this.location = location; + this.startDate = startDate; + this.endDate = endDate; + this.informationUrl = informationUrl; + this.tags = tags; + } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventTag.java b/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventTag.java index 28349cfb6..572b1ec46 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventTag.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventTag.java @@ -26,4 +26,9 @@ public class EventTag { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "tag_id", nullable = false) private Tag tag; + + public EventTag(Event event, Tag tag) { + this.event = event; + this.tag = tag; + } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/tag/domain/Tag.java b/backend/emm-sale/src/main/java/com/emmsale/tag/domain/Tag.java index 3a9364918..506083d26 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/tag/domain/Tag.java +++ b/backend/emm-sale/src/main/java/com/emmsale/tag/domain/Tag.java @@ -19,4 +19,8 @@ public class Tag { private Long id; @Column(nullable = false) private String name; + + public Tag(String name) { + this.name = name; + } } diff --git a/backend/emm-sale/src/main/resources/data.sql b/backend/emm-sale/src/main/resources/data.sql index 6209760ea..9029b97bd 100644 --- a/backend/emm-sale/src/main/resources/data.sql +++ b/backend/emm-sale/src/main/resources/data.sql @@ -44,56 +44,3 @@ values (3, 3, 1, CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); insert into member_activity(id, activity_id, member_id, created_at, updated_at) values (4, 1, 2, CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); - -insert into tag(id, name) -values (1, '백엔드'); -insert into tag(id, name) -values (2, '프론트엔드'); -insert into tag(id, name) -values (3, '안드로이드'); -insert into tag(id, name) -values (4, 'IOS'); -insert into tag(id, name) -values (5, 'AI'); - -insert into event(id, name, start_date, end_date, location, information_url, created_at, updated_at) -values (1, '인프콘 2023', '2023-06-01T12:00:00', '2023-09-01T12:00:00', '코엑스', 'https://~~~', - CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); -insert into event(id, name, start_date, end_date, location, information_url, created_at, updated_at) -values (2, 'AI 컨퍼런스', '2023-07-22T12:00:00', '2023-07-30T12:00:00', '코엑스', 'https://~~~', - CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); -insert into event(id, name, start_date, end_date, location, information_url, created_at, updated_at) -values (3, '모바일 컨퍼런스', '2023-08-03T12:00:00', '2023-09-03T12:00:00', '코엑스', 'https://~~~', - CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); -insert into event(id, name, start_date, end_date, location, information_url, created_at, updated_at) -values (4, '안드로이드 컨퍼런스', '2023-06-29T12:00:00', '2023-07-16T12:00:00', '코엑스', 'https://~~~', - CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); -insert into event(id, name, start_date, end_date, location, information_url, created_at, updated_at) -values (5, '웹 컨퍼런스', '2023-07-03T12:00:00', '2023-08-03T12:00:00', '코엑스', 'https://~~~', - CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); -insert into event(id, name, start_date, end_date, location, information_url, created_at, updated_at) -values (6, '옛날 웹 컨퍼런스', '2022-07-03T12:00:00', '2022-08-03T12:00:00', '코엑스', 'https://~~~', - CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); - -insert into event_tag(id, event_id, tag_id) -values (1, 1, 1); -insert into event_tag(id, event_id, tag_id) -values (2, 1, 2); -insert into event_tag(id, event_id, tag_id) -values (3, 1, 3); -insert into event_tag(id, event_id, tag_id) -values (4, 1, 4); -insert into event_tag(id, event_id, tag_id) -values (5, 1, 5); -insert into event_tag(id, event_id, tag_id) -values (6, 2, 5); -insert into event_tag(id, event_id, tag_id) -values (7, 3, 3); -insert into event_tag(id, event_id, tag_id) -values (8, 3, 4); -insert into event_tag(id, event_id, tag_id) -values (9, 4, 3); -insert into event_tag(id, event_id, tag_id) -values (10, 5, 1); -insert into event_tag(id, event_id, tag_id) -values (11, 5, 2); \ No newline at end of file diff --git a/backend/emm-sale/src/test/java/com/emmsale/event/EventFixture.java b/backend/emm-sale/src/test/java/com/emmsale/event/EventFixture.java new file mode 100644 index 000000000..e84b90cae --- /dev/null +++ b/backend/emm-sale/src/test/java/com/emmsale/event/EventFixture.java @@ -0,0 +1,33 @@ +package com.emmsale.event; + +import com.emmsale.event.domain.Event; +import java.time.LocalDateTime; + +public class EventFixture { + + public static Event 인프콘_2023() { + return new Event("인프콘 2023", "코엑스", LocalDateTime.parse("2023-06-01T12:00:00"), + LocalDateTime.parse("2023-09-01T12:00:00"), "https://~~~", null); + } + + public static Event AI_컨퍼런스() { + return new Event("AI 컨퍼런스", "코엑스", LocalDateTime.parse("2023-07-22T12:00:00"), + LocalDateTime.parse("2023-07-30T12:00:00"), "https://~~~", null); + } + + public static Event 모바일_컨퍼런스() { + return new Event("모바일 컨퍼런스", "코엑스", LocalDateTime.parse("2023-08-03T12:00:00"), + LocalDateTime.parse("2023-09-03T12:00:00"), "https://~~~", null); + } + + public static Event 안드로이드_컨퍼런스() { + return new Event("안드로이드 컨퍼런스", "코엑스", LocalDateTime.parse("2023-06-29T12:00:00"), + LocalDateTime.parse("2023-07-16T12:00:00"), "https://~~~", null); + } + + public static Event 웹_컨퍼런스() { + return new Event("웹 컨퍼런스", "코엑스", LocalDateTime.parse("2023-07-03T12:00:00"), + LocalDateTime.parse("2023-08-03T12:00:00"), "https://~~~", null); + } + +} diff --git a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java index 074334b69..0ac51162e 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java @@ -1,17 +1,34 @@ package com.emmsale.event.application; +import static com.emmsale.event.EventFixture.AI_컨퍼런스; +import static com.emmsale.event.EventFixture.모바일_컨퍼런스; +import static com.emmsale.event.EventFixture.안드로이드_컨퍼런스; +import static com.emmsale.event.EventFixture.웹_컨퍼런스; +import static com.emmsale.event.EventFixture.인프콘_2023; +import static com.emmsale.tag.TagFixture.AI; +import static com.emmsale.tag.TagFixture.IOS; +import static com.emmsale.tag.TagFixture.백엔드; +import static com.emmsale.tag.TagFixture.안드로이드; +import static com.emmsale.tag.TagFixture.프론트엔드; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.emmsale.event.application.dto.EventResponse; +import com.emmsale.event.domain.Event; +import com.emmsale.event.domain.EventRepository; +import com.emmsale.event.domain.EventTag; +import com.emmsale.event.domain.EventTagRepository; import com.emmsale.event.exception.EventException; import com.emmsale.event.exception.EventExceptionType; import com.emmsale.helper.ServiceIntegrationTestHelper; +import com.emmsale.tag.domain.Tag; +import com.emmsale.tag.domain.TagRepository; import com.emmsale.tag.exception.TagException; import com.emmsale.tag.exception.TagExceptionType; import java.time.LocalDate; import java.util.List; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -21,21 +38,49 @@ class EventServiceTest extends ServiceIntegrationTestHelper { - public static final EventResponse 인프콘_2023 = new EventResponse(null, "인프콘 2023", null, null, + private static final EventResponse 인프콘_2023 = new EventResponse(null, "인프콘 2023", null, null, List.of(), "진행 중"); - public static final EventResponse 웹_컨퍼런스 = new EventResponse(null, "웹 컨퍼런스", null, null, + private static final EventResponse 웹_컨퍼런스 = new EventResponse(null, "웹 컨퍼런스", null, null, List.of(), "진행 중"); - public static final EventResponse 안드로이드_컨퍼런스 = new EventResponse(null, "안드로이드 컨퍼런스", null, null, + private static final EventResponse 안드로이드_컨퍼런스 = new EventResponse(null, "안드로이드 컨퍼런스", null, null, List.of(), "종료된 행사"); - public static final EventResponse AI_컨퍼런스 = new EventResponse(null, "AI 컨퍼런스", null, null, + private static final EventResponse AI_컨퍼런스 = new EventResponse(null, "AI 컨퍼런스", null, null, List.of(), "진행 예정"); - public static final EventResponse 모바일_컨퍼런스 = new EventResponse(null, "모바일 컨퍼런스", null, null, + private static final EventResponse 모바일_컨퍼런스 = new EventResponse(null, "모바일 컨퍼런스", null, null, List.of(), "진행 예정"); private static final LocalDate TODAY = LocalDate.of(2023, 7, 21); @Autowired + private EventRepository eventRepository; + @Autowired + private EventTagRepository eventTagRepository; + @Autowired + private TagRepository tagRepository; + @Autowired private EventService eventService; + @BeforeEach + void init() { + Tag 백엔드 = tagRepository.save(백엔드()); + Tag 프론트엔드 = tagRepository.save(프론트엔드()); + Tag 안드로이드 = tagRepository.save(안드로이드()); + Tag IOS = tagRepository.save(IOS()); + Tag AI = tagRepository.save(AI()); + + Event 인프콘_2023 = eventRepository.save(인프콘_2023()); + Event AI_컨퍼런스 = eventRepository.save(AI_컨퍼런스()); + Event 모바일_컨퍼런스 = eventRepository.save(모바일_컨퍼런스()); + Event 안드로이드_컨퍼런스 = eventRepository.save(안드로이드_컨퍼런스()); + Event 웹_컨퍼런스 = eventRepository.save(웹_컨퍼런스()); + + eventTagRepository.saveAll(List.of( + new EventTag(인프콘_2023, 백엔드), new EventTag(인프콘_2023, 프론트엔드), new EventTag(인프콘_2023, 안드로이드), + new EventTag(인프콘_2023, IOS), new EventTag(인프콘_2023, AI), new EventTag(AI_컨퍼런스, AI), + new EventTag(모바일_컨퍼런스, 안드로이드), new EventTag(모바일_컨퍼런스, IOS), new EventTag(안드로이드_컨퍼런스, 안드로이드), + new EventTag(웹_컨퍼런스, 백엔드), new EventTag(웹_컨퍼런스, 프론트엔드)) + ); + } + @Nested @DisplayName("findEvents() : 행사 목록 조회") class findEvents { diff --git a/backend/emm-sale/src/test/java/com/emmsale/tag/TagFixture.java b/backend/emm-sale/src/test/java/com/emmsale/tag/TagFixture.java new file mode 100644 index 000000000..8ea3739c0 --- /dev/null +++ b/backend/emm-sale/src/test/java/com/emmsale/tag/TagFixture.java @@ -0,0 +1,27 @@ +package com.emmsale.tag; + +import com.emmsale.tag.domain.Tag; + +public class TagFixture { + + public static Tag 백엔드() { + return new Tag("백엔드"); + } + + public static Tag 프론트엔드() { + return new Tag("프론트엔드"); + } + + public static Tag 안드로이드() { + return new Tag("안드로이드"); + } + + public static Tag IOS() { + return new Tag("IOS"); + } + + public static Tag AI() { + return new Tag("AI"); + } + +} From 446b8cb2f4ef7b8d2d481927dffb9ef4b5e1964b Mon Sep 17 00:00:00 2001 From: amaran-th Date: Thu, 27 Jul 2023 10:15:12 +0900 Subject: [PATCH 08/10] =?UTF-8?q?refactor:=20EventTagRepository=20?= =?UTF-8?q?=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - repository 패키지로 이동 #86 --- .../main/java/com/emmsale/event/application/EventService.java | 2 +- .../event/domain/{ => repository}/EventTagRepository.java | 3 ++- .../java/com/emmsale/event/application/EventServiceTest.java | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) rename backend/emm-sale/src/main/java/com/emmsale/event/domain/{ => repository}/EventTagRepository.java (74%) diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java index 8f9f7031e..e66cf1788 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java @@ -14,8 +14,8 @@ 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.domain.repository.EventTagRepository; import com.emmsale.event.exception.EventException; import com.emmsale.tag.domain.Tag; import com.emmsale.tag.domain.TagRepository; diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventTagRepository.java b/backend/emm-sale/src/main/java/com/emmsale/event/domain/repository/EventTagRepository.java similarity index 74% rename from backend/emm-sale/src/main/java/com/emmsale/event/domain/EventTagRepository.java rename to backend/emm-sale/src/main/java/com/emmsale/event/domain/repository/EventTagRepository.java index c6a46c42e..5149843e2 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventTagRepository.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/domain/repository/EventTagRepository.java @@ -1,5 +1,6 @@ -package com.emmsale.event.domain; +package com.emmsale.event.domain.repository; +import com.emmsale.event.domain.EventTag; import com.emmsale.tag.domain.Tag; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java index 18c0ffbfd..b8c176069 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java @@ -18,8 +18,8 @@ import com.emmsale.event.application.dto.EventResponse; import com.emmsale.event.domain.Event; import com.emmsale.event.domain.EventTag; -import com.emmsale.event.domain.EventTagRepository; import com.emmsale.event.domain.repository.EventRepository; +import com.emmsale.event.domain.repository.EventTagRepository; import com.emmsale.event.exception.EventException; import com.emmsale.event.exception.EventExceptionType; import com.emmsale.helper.ServiceIntegrationTestHelper; From 28a4db58c7564dfb82df89e1f9f232e9d5df8d13 Mon Sep 17 00:00:00 2001 From: amaran-th Date: Thu, 27 Jul 2023 11:06:34 +0900 Subject: [PATCH 09/10] =?UTF-8?q?docs:=20API=20=EB=AA=85=EC=84=B8=20descri?= =?UTF-8?q?ption=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #86 --- backend/emm-sale/src/docs/asciidoc/index.adoc | 2 -- .../java/com/emmsale/event/api/EventApiTest.java | 14 ++++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/backend/emm-sale/src/docs/asciidoc/index.adoc b/backend/emm-sale/src/docs/asciidoc/index.adoc index c8e78ef51..a8f3916f0 100644 --- a/backend/emm-sale/src/docs/asciidoc/index.adoc +++ b/backend/emm-sale/src/docs/asciidoc/index.adoc @@ -168,8 +168,6 @@ include::{snippets}/find-event/http-response.adoc[] .HTTP response 설명 include::{snippets}/find-event/response-fields.adoc[] -== Event - === `GET`: 행사 목록 조회 .HTTP request diff --git a/backend/emm-sale/src/test/java/com/emmsale/event/api/EventApiTest.java b/backend/emm-sale/src/test/java/com/emmsale/event/api/EventApiTest.java index 22a9db009..8a451494a 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/event/api/EventApiTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/event/api/EventApiTest.java @@ -73,17 +73,19 @@ void findEvent() throws Exception { void findEvents() throws Exception { // given final RequestParametersSnippet requestParameters = requestParameters( - parameterWithName("year").description("조회하고자 하는 연도"), - parameterWithName("month").description("조회하고자 하는 월"), - parameterWithName("tag").description("필터링하려는 태그").optional(), - parameterWithName("status").description("필터링하려는 상태").optional() + parameterWithName("year").description("조회하고자 하는 연도(2015 이상의 값)"), + parameterWithName("month").description("조회하고자 하는 월(1~12)"), + parameterWithName("tag").description("필터링하려는 태그(option)").optional(), + parameterWithName("status").description("필터링하려는 상태(option)").optional() ); final ResponseFieldsSnippet responseFields = responseFields( fieldWithPath("[].id").type(JsonFieldType.NUMBER).description("행사 id"), fieldWithPath("[].name").type(JsonFieldType.STRING).description("행사명"), - fieldWithPath("[].startDate").type(JsonFieldType.STRING).description("행사 시작일"), - fieldWithPath("[].endDate").type(JsonFieldType.STRING).description("행사 종료일"), + fieldWithPath("[].startDate").type(JsonFieldType.STRING) + .description("행사 시작일(yyyy:MM:dd:HH:mm:ss)"), + fieldWithPath("[].endDate").type(JsonFieldType.STRING) + .description("행사 종료일(yyyy:MM:dd:HH:mm:ss)"), fieldWithPath("[].tags[]").type(JsonFieldType.ARRAY) .description("행사 태그 목록"), fieldWithPath("[].status").type(JsonFieldType.STRING).description("행사 진행 상황") From 570bf1b1992a81c09aa7c2ca15cefe3890f60271 Mon Sep 17 00:00:00 2001 From: amaran-th Date: Thu, 27 Jul 2023 13:23:41 +0900 Subject: [PATCH 10/10] =?UTF-8?q?refactor:=20=ED=98=84=EC=9E=A5=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #86 --- .../java/com/emmsale/event/api/EventApi.java | 4 +- .../event/application/EventService.java | 52 +++---------------- .../event/application/dto/EventResponse.java | 24 ++++++++- .../java/com/emmsale/event/domain/Event.java | 11 ++++ .../com/emmsale/event/domain/EventStatus.java | 11 ++++ .../emmsale/tag/exception/TagException.java | 2 +- .../com/emmsale/member/api/MemberApiTest.java | 12 ++--- 7 files changed, 61 insertions(+), 55 deletions(-) diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/api/EventApi.java b/backend/emm-sale/src/main/java/com/emmsale/event/api/EventApi.java index aea2fd75a..f088e6fba 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/api/EventApi.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/api/EventApi.java @@ -8,8 +8,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -24,11 +24,11 @@ public class EventApi { public ResponseEntity findEventById(@PathVariable final String id) { return ResponseEntity.ok(eventService.findEvent(Long.parseLong(id))); } + @GetMapping public ResponseEntity> findEvents(@RequestParam final int year, @RequestParam final int month, @RequestParam(required = false) final String tag, @RequestParam(required = false) final String status) { - return ResponseEntity.ok(eventService.findEvents(LocalDate.now(), year, month, tag, status)); } diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java index e66cf1788..3c96a7667 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java @@ -2,7 +2,6 @@ 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; @@ -21,8 +20,6 @@ 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; @@ -95,8 +92,8 @@ private EnumMap> groupByEventStatus(final LocalDate now ) .sorted(comparing(Event::getStartDate)) .collect( - groupingBy(event -> extractEventStatus(nowDate, event.getStartDate().toLocalDate(), - event.getEndDate().toLocalDate()), () -> new EnumMap<>(EventStatus.class), toList()) + groupingBy(event -> event.calculateEventStatus(nowDate), + () -> new EnumMap<>(EventStatus.class), toList()) ); } @@ -114,50 +111,17 @@ private boolean isBeforeOrEquals(LocalDate criteria, LocalDate comparison) { return criteria.isBefore(comparison) || criteria.isEqual(comparison); } - private EventStatus extractEventStatus(LocalDate now, LocalDate startDate, LocalDate endDate) { - if (now.isBefore(startDate)) { - return EventStatus.UPCOMING; - } - if (now.isAfter(endDate)) { - return EventStatus.ENDED; - } - return EventStatus.IN_PROGRESS; - } - private List filterEventResponsesByStatus(final String statusName, final EnumMap> sortAndGroupByEventStatus) { - if (isaBoolean(statusName)) { - EventStatus status = findEventStatusByValue(statusName); - return makeEventResponsesByStatus(status, sortAndGroupByEventStatus.get(status)); + if (isExistStatusName(statusName)) { + EventStatus status = EventStatus.from(statusName); + return EventResponse.makeEventResponsesByStatus(status, + sortAndGroupByEventStatus.get(status)); } - return mergeEventResponses(sortAndGroupByEventStatus); + return EventResponse.mergeEventResponses(sortAndGroupByEventStatus); } - private boolean isaBoolean(final String statusName) { + private boolean isExistStatusName(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 makeEventResponsesByStatus(EventStatus status, - List events) { - return events.stream() - .map(event -> EventResponse.from(status, event)) - .collect(toList()); - } - - private List mergeEventResponses( - final EnumMap> groupByEventStatus) { - return groupByEventStatus.entrySet().stream() - .map(entry -> makeEventResponsesByStatus(entry.getKey(), entry.getValue())) - .reduce(new ArrayList<>(), (combinedEvents, eventsToAdd) -> { - combinedEvents.addAll(eventsToAdd); - return combinedEvents; - }); - } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/application/dto/EventResponse.java b/backend/emm-sale/src/main/java/com/emmsale/event/application/dto/EventResponse.java index bc10795c4..f7b50c947 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/application/dto/EventResponse.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/application/dto/EventResponse.java @@ -1,9 +1,13 @@ package com.emmsale.event.application.dto; +import static java.util.stream.Collectors.toList; + 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.ArrayList; +import java.util.EnumMap; import java.util.List; import java.util.stream.Collectors; import lombok.Getter; @@ -22,7 +26,24 @@ public class EventResponse { private final List tags; private final String status; - public static EventResponse from(EventStatus status, Event event) { + public static List makeEventResponsesByStatus(EventStatus status, + List events) { + return events.stream() + .map(event -> EventResponse.from(status, event)) + .collect(toList()); + } + + public static List mergeEventResponses( + final EnumMap> groupByEventStatus) { + return groupByEventStatus.entrySet().stream() + .map(entry -> makeEventResponsesByStatus(entry.getKey(), entry.getValue())) + .reduce(new ArrayList<>(), (combinedEvents, eventsToAdd) -> { + combinedEvents.addAll(eventsToAdd); + return combinedEvents; + }); + } + + private static EventResponse from(EventStatus status, Event event) { return new EventResponse(event.getId(), event.getName(), event.getStartDate(), event.getEndDate(), event.getTags() @@ -30,4 +51,5 @@ public static EventResponse from(EventStatus status, Event event) { .map(tag -> tag.getTag().getName()) .collect(Collectors.toList()), status.getValue()); } + } diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/domain/Event.java b/backend/emm-sale/src/main/java/com/emmsale/event/domain/Event.java index 9da74b3de..62dbb2270 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/domain/Event.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/domain/Event.java @@ -4,6 +4,7 @@ import com.emmsale.base.BaseEntity; import com.emmsale.comment.domain.Comment; +import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; import javax.persistence.Column; @@ -51,4 +52,14 @@ public Event( this.endDate = endDate; this.informationUrl = informationUrl; } + + public EventStatus calculateEventStatus(LocalDate now) { + if (now.isBefore(startDate.toLocalDate())) { + return EventStatus.UPCOMING; + } + if (now.isAfter(endDate.toLocalDate())) { + return EventStatus.ENDED; + } + return EventStatus.IN_PROGRESS; + } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventStatus.java b/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventStatus.java index 23d2c044c..40e2dbb73 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventStatus.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/domain/EventStatus.java @@ -1,5 +1,9 @@ package com.emmsale.event.domain; +import static com.emmsale.event.exception.EventExceptionType.INVALID_STATUS; + +import com.emmsale.event.exception.EventException; +import java.util.Arrays; import lombok.Getter; @Getter @@ -15,6 +19,13 @@ public enum EventStatus { this.value = value; } + public static EventStatus from(final String value) { + return Arrays.stream(values()) + .filter(status -> status.isSameValue(value)) + .findFirst() + .orElseThrow(() -> new EventException(INVALID_STATUS)); + } + public boolean isSameValue(String value) { return this.value.equals(value); } diff --git a/backend/emm-sale/src/main/java/com/emmsale/tag/exception/TagException.java b/backend/emm-sale/src/main/java/com/emmsale/tag/exception/TagException.java index 2d4e93e9a..1e3abf9f6 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/tag/exception/TagException.java +++ b/backend/emm-sale/src/main/java/com/emmsale/tag/exception/TagException.java @@ -16,4 +16,4 @@ public TagException(final TagExceptionType exceptionType) { public BaseExceptionType exceptionType() { return exceptionType; } -} \ No newline at end of file +} diff --git a/backend/emm-sale/src/test/java/com/emmsale/member/api/MemberApiTest.java b/backend/emm-sale/src/test/java/com/emmsale/member/api/MemberApiTest.java index 89fc0cf23..16fc18a59 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/member/api/MemberApiTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/member/api/MemberApiTest.java @@ -14,10 +14,10 @@ import com.emmsale.helper.MockMvcTestHelper; import com.emmsale.member.application.MemberActivityService; -import com.emmsale.member.application.dto.MemberActivityResponse; import com.emmsale.member.application.dto.MemberActivityAddRequest; import com.emmsale.member.application.dto.MemberActivityDeleteRequest; import com.emmsale.member.application.dto.MemberActivityInitialRequest; +import com.emmsale.member.application.dto.MemberActivityResponse; import com.emmsale.member.application.dto.MemberActivityResponses; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -32,9 +32,6 @@ @WebMvcTest(MemberApi.class) class MemberApiTest extends MockMvcTestHelper { - @MockBean - private MemberActivityService memberActivityService; - private static final ResponseFieldsSnippet RESPONSE_FIELDS = responseFields( fieldWithPath("[].activityType").type(JsonFieldType.STRING).description("activity 분류"), @@ -43,9 +40,10 @@ class MemberApiTest extends MockMvcTestHelper { fieldWithPath("[].memberActivityResponses[].name").type(JsonFieldType.STRING) .description("activity 이름") ); - private static final RequestFieldsSnippet REQUEST_FIELDS = requestFields( fieldWithPath("activityIds").description("활동 id들")); + @MockBean + private MemberActivityService memberActivityService; @Test @DisplayName("사용자 정보를 잘 저장하면, 204 no Content를 반환해줄 수 있다.") @@ -54,8 +52,8 @@ void register() throws Exception { final List activityIds = List.of(1L, 2L); final String name = "우르"; - final MemberActivityInitialRequest request = new MemberActivityInitialRequest(name, activityIds); - + final MemberActivityInitialRequest request = new MemberActivityInitialRequest(name, + activityIds); final RequestFieldsSnippet REQUEST_FIELDS = requestFields( fieldWithPath("activityIds").description("활동 id들"), fieldWithPath("name").description("사용자 이름"));