diff --git a/backend/emm-sale/src/documentTest/asciidoc/index.adoc b/backend/emm-sale/src/documentTest/asciidoc/index.adoc index 701dc6e70..419b2577e 100644 --- a/backend/emm-sale/src/documentTest/asciidoc/index.adoc +++ b/backend/emm-sale/src/documentTest/asciidoc/index.adoc @@ -632,6 +632,20 @@ include::{snippets}/delete-notifications/http-response.adoc[] == 관리자 API +=== `POST` : 관리자 로그인 + +.HTTP request +include::{snippets}/admin-login-snippet/http-request.adoc[] + +.HTTP request 설명 +include::{snippets}/admin-login-snippet/request-fields.adoc[] + +.HTTP response +include::{snippets}/admin-login-snippet/http-response.adoc[] + +.HTTP response 설명 +include::{snippets}/admin-login-snippet/response-fields.adoc[] + === `POST` : 행사 생성 .HTTP request diff --git a/backend/emm-sale/src/documentTest/java/com/emmsale/ActivityApiTest.java b/backend/emm-sale/src/documentTest/java/com/emmsale/ActivityApiTest.java index 6d1d83fe4..c588da6d9 100644 --- a/backend/emm-sale/src/documentTest/java/com/emmsale/ActivityApiTest.java +++ b/backend/emm-sale/src/documentTest/java/com/emmsale/ActivityApiTest.java @@ -13,6 +13,8 @@ import com.emmsale.activity.application.dto.ActivityAddRequest; import com.emmsale.activity.application.dto.ActivityResponse; import com.emmsale.activity.domain.ActivityType; +import com.emmsale.admin.activity.api.AdminActivityApi; +import com.emmsale.member.domain.Member; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -27,7 +29,7 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -@WebMvcTest(ActivityApi.class) +@WebMvcTest({ActivityApi.class, AdminActivityApi.class}) // TODO: 2023/11/18 Admin API Test 분리하기 class ActivityApiTest extends MockMvcTestHelper { @Test @@ -35,26 +37,26 @@ class ActivityApiTest extends MockMvcTestHelper { void findAll() throws Exception { // given final ResponseFieldsSnippet responseFields = PayloadDocumentation.responseFields( - fieldWithPath("[].id").type(JsonFieldType.NUMBER).description("activity id"), - fieldWithPath("[].activityType").type(JsonFieldType.STRING).description("activity 분류"), - fieldWithPath("[].name").type(JsonFieldType.STRING).description("activity 이름") + fieldWithPath("[].id").type(JsonFieldType.NUMBER).description("activity id"), + fieldWithPath("[].activityType").type(JsonFieldType.STRING).description("activity 분류"), + fieldWithPath("[].name").type(JsonFieldType.STRING).description("activity 이름") ); final List expected = List.of( - new ActivityResponse(1L, "동아리", "YAPP"), - new ActivityResponse(2L, "동아리", "DND"), - new ActivityResponse(3L, "동아리", "nexters"), - new ActivityResponse(4L, "컨퍼런스", "인프콘"), - new ActivityResponse(5L, "교육", "우아한테크코스"), - new ActivityResponse(6L, "직무", "Backend") + new ActivityResponse(1L, "동아리", "YAPP"), + new ActivityResponse(2L, "동아리", "DND"), + new ActivityResponse(3L, "동아리", "nexters"), + new ActivityResponse(4L, "컨퍼런스", "인프콘"), + new ActivityResponse(5L, "교육", "우아한테크코스"), + new ActivityResponse(6L, "직무", "Backend") ); Mockito.when(activityQueryService.findAll()).thenReturn(expected); // when & then mockMvc.perform(MockMvcRequestBuilders.get("/activities")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andDo(MockMvcRestDocumentation.document("find-all-activities", responseFields)); + .andExpect(MockMvcResultMatchers.status().isOk()) + .andDo(MockMvcRestDocumentation.document("find-all-activities", responseFields)); } @Test @@ -62,29 +64,32 @@ void findAll() throws Exception { void addTag() throws Exception { //given final RequestFieldsSnippet requestFields = requestFields( - fieldWithPath("activityType").type(JsonFieldType.STRING).description("활동 유형"), - fieldWithPath("name").type(JsonFieldType.STRING).description("활동 이름") + fieldWithPath("activityType").type(JsonFieldType.STRING).description("활동 유형"), + fieldWithPath("name").type(JsonFieldType.STRING).description("활동 이름") ); final ActivityAddRequest request = new ActivityAddRequest(ActivityType.CLUB, "DND"); final ActivityResponse response = new ActivityResponse(3L, - ActivityType.CLUB.getValue(), - "DND" + ActivityType.CLUB.getValue(), + "DND" ); + final String accessToken = "Bearer accessToken"; - when(activityCommandService.addActivity(any(ActivityAddRequest.class))).thenReturn(response); + when(activityCommandService.addActivity(any(ActivityAddRequest.class), + any(Member.class))).thenReturn(response); final ResponseFieldsSnippet responseFields = responseFields( - fieldWithPath("id").type(JsonFieldType.NUMBER).description("활동 식별자"), - fieldWithPath("activityType").type(JsonFieldType.STRING).description("활동 종류"), - fieldWithPath("name").type(JsonFieldType.STRING).description("활동 이름") + fieldWithPath("id").type(JsonFieldType.NUMBER).description("활동 식별자"), + fieldWithPath("activityType").type(JsonFieldType.STRING).description("활동 종류"), + fieldWithPath("name").type(JsonFieldType.STRING).description("활동 이름") ); //when & then - mockMvc.perform(post("/activities") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(request))) - .andExpect(status().isCreated()) - .andDo(document("add-activity", requestFields, responseFields)); + mockMvc.perform(post("/admin/activities") + .header("Authorization", accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isCreated()) + .andDo(document("add-activity", requestFields, responseFields)); } } diff --git a/backend/emm-sale/src/documentTest/java/com/emmsale/EventApiTest.java b/backend/emm-sale/src/documentTest/java/com/emmsale/EventApiTest.java index ef69d49b0..c7dc6e9f2 100644 --- a/backend/emm-sale/src/documentTest/java/com/emmsale/EventApiTest.java +++ b/backend/emm-sale/src/documentTest/java/com/emmsale/EventApiTest.java @@ -1,5 +1,6 @@ package com.emmsale; +import static com.emmsale.member.MemberFixture.adminMember; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; @@ -11,6 +12,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.emmsale.admin.event.api.AdminEventApi; import com.emmsale.event.EventFixture; import com.emmsale.event.api.EventApi; import com.emmsale.event.application.dto.EventDetailRequest; @@ -19,8 +21,10 @@ import com.emmsale.event.domain.EventMode; import com.emmsale.event.domain.EventType; import com.emmsale.event.domain.PaymentType; +import com.emmsale.member.domain.Member; import com.emmsale.tag.TagFixture; import com.emmsale.tag.application.dto.TagRequest; +import com.emmsale.tag.application.dto.TagResponse; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.util.HashMap; @@ -49,12 +53,15 @@ import org.springframework.restdocs.request.RequestParametersSnippet; import org.springframework.restdocs.request.RequestPartsSnippet; import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; -@WebMvcTest(EventApi.class) +@WebMvcTest({EventApi.class, AdminEventApi.class}) class EventApiTest extends MockMvcTestHelper { + private static final String accessToken = "Bearer accessToken"; + private static final ResponseFieldsSnippet EVENT_DETAIL_RESPONSE_FILED = PayloadDocumentation.responseFields( fieldWithPath("id").type(JsonFieldType.NUMBER).description("event 식별자"), fieldWithPath("name").type(JsonFieldType.STRING) @@ -70,6 +77,8 @@ class EventApiTest extends MockMvcTestHelper { .description("신청 종료일자(nullable)"), fieldWithPath("location").type(JsonFieldType.STRING).description("장소"), fieldWithPath("tags[]").type(JsonFieldType.ARRAY).description("태그들"), + fieldWithPath("tags[].id").type(JsonFieldType.NUMBER).description("행사 태그 ID"), + fieldWithPath("tags[].name").type(JsonFieldType.STRING).description("행사 태그 이름"), fieldWithPath("thumbnailUrl").type(JsonFieldType.STRING) .description("섬네일 이미지 Url(포스터)"), fieldWithPath("type").type(JsonFieldType.STRING) @@ -94,7 +103,9 @@ class EventApiTest extends MockMvcTestHelper { fieldWithPath("[].applyEndDate").type(JsonFieldType.STRING) .description("행사 신청 종료 일자(nullable)"), fieldWithPath("[].location").type(JsonFieldType.STRING).description("행사 장소"), - fieldWithPath("[].tags[]").type(JsonFieldType.ARRAY).description("행사 태그들"), + fieldWithPath("[].tags[]").type(JsonFieldType.ARRAY).description("태그들"), + fieldWithPath("[].tags[].id").type(JsonFieldType.NUMBER).description("행사 태그 ID"), + fieldWithPath("[].tags[].name").type(JsonFieldType.STRING).description("행사 태그 이름"), fieldWithPath("[].thumbnailUrl").type(JsonFieldType.STRING) .description("행사 섬네일 이미지 Url(포스터)"), fieldWithPath("[].type").type(JsonFieldType.STRING) @@ -110,11 +121,14 @@ class EventApiTest extends MockMvcTestHelper { void findEvent() throws Exception { //given final Long eventId = 1L; + final List tagResponses = List.of( + new TagResponse(1L, "코틀린"), new TagResponse(2L, "백엔드"), new TagResponse(3L, "안드로이드") + ); final EventResponse eventResponse = new EventResponse(eventId, "인프콘 2023", "http://infcon.com", LocalDateTime.of(2023, 8, 15, 12, 0), LocalDateTime.of(2023, 8, 15, 12, 0), LocalDateTime.of(2023, 8, 1, 12, 0), LocalDateTime.of(2023, 8, 15, 12, 0), "코엑스", - List.of("코틀린", "백엔드", "안드로이드"), + tagResponses, "https://www.image.com", EventType.COMPETITION.toString(), List.of("imageUrl1", "imageUrl2"), "인프런", "유료", "온라인"); @@ -157,7 +171,7 @@ void findEvents() throws Exception { LocalDateTime.parse("2023-08-03T12:00:00"), LocalDateTime.parse("2023-06-23T10:00:00"), LocalDateTime.parse("2023-07-03T12:00:00"), - "코엑스", List.of("백엔드", "프론트엔드"), + "코엑스", List.of(new TagResponse(1L, "백엔드"), new TagResponse(2L, "프론트엔드")), "imageUrl0", EventType.CONFERENCE.name(), List.of("imageUrl1", "imageUrl2"), "인프런", PaymentType.PAID.getValue(), @@ -169,7 +183,7 @@ void findEvents() throws Exception { LocalDateTime.parse("2023-07-30T12:00:00"), LocalDateTime.parse("2023-07-01T00:00:00"), LocalDateTime.parse("2023-07-21T23:59:59"), - "코엑스", List.of("AI"), + "코엑스", List.of(new TagResponse(5L, "AI")), "imageUrl0", EventType.CONFERENCE.name(), List.of("imageUrl1", "imageUrl2"), "인프런", PaymentType.PAID.getValue(), @@ -228,11 +242,12 @@ void updateEventTest() throws Exception { request.getInformationUrl(), request.getStartDateTime(), request.getEndDateTime(), request.getApplyStartDateTime(), request.getApplyEndDateTime(), request.getLocation(), - tags.stream().map(TagRequest::getName).collect(Collectors.toList()), + List.of(new TagResponse(1L, "백엔드"), new TagResponse(2L, "안드로이드")), "image1.jpg", request.getType().toString(), List.of("imageUrl1", "imageUrl2"), "행사기관", "유료", "온라인"); - Mockito.when(eventCommandService.updateEvent(eq(eventId), any(EventDetailRequest.class), any())) + Mockito.when( + eventCommandService.updateEvent(eq(eventId), any(EventDetailRequest.class), any(), any())) .thenReturn(response); final String contents = objectMapper.writeValueAsString(request); @@ -258,12 +273,13 @@ void updateEventTest() throws Exception { ); //when - final MockMultipartHttpServletRequestBuilder builder = multipart(HttpMethod.PUT, - "/events/" + eventId) + final MockHttpServletRequestBuilder builder = multipart(HttpMethod.PUT, + "/admin/events/" + eventId) .file("images", image1.getBytes()) .file("images", image2.getBytes()) .file(new MockMultipartFile("request", "", "application/json", contents.getBytes( - StandardCharsets.UTF_8))); + StandardCharsets.UTF_8))) + .header("Authorization", accessToken); final ResultActions result = mockMvc.perform(builder); @@ -282,10 +298,11 @@ void deleteEventTest() throws Exception { //given final long eventId = 1L; - Mockito.doNothing().when(eventCommandService).deleteEvent(eventId); + Mockito.doNothing().when(eventCommandService).deleteEvent(eventId, adminMember()); //when final ResultActions result = mockMvc.perform( - delete("/events/" + eventId)); + delete("/admin/events/" + eventId) + .header("Authorization", accessToken)); //then result.andExpect(status().isNoContent()) @@ -330,11 +347,12 @@ void addEventTest() throws Exception { request.getInformationUrl(), request.getStartDateTime(), request.getEndDateTime(), request.getApplyStartDateTime(), request.getApplyEndDateTime(), request.getLocation(), - tags.stream().map(TagRequest::getName).collect(Collectors.toList()), + List.of(new TagResponse(1L, "백엔드"), new TagResponse(2L, "안드로이드")), "image1.jpg", request.getType().toString(), List.of("imageUrl1", "imageUrl2"), "행사기관", "무료", "오프라인"); - Mockito.when(eventCommandService.addEvent(any(EventDetailRequest.class), any())) + Mockito.when( + eventCommandService.addEvent(any(EventDetailRequest.class), any(), any(Member.class))) .thenReturn(response); final String contents = objectMapper.writeValueAsString(request); @@ -360,13 +378,13 @@ void addEventTest() throws Exception { ); //when - final MockMultipartHttpServletRequestBuilder builder = multipart("/events") + final MockMultipartHttpServletRequestBuilder builder = multipart("/admin/events") .file("images", image1.getBytes()) .file("images", image2.getBytes()) .file(new MockMultipartFile("request", "", "application/json", contents.getBytes( StandardCharsets.UTF_8))); - final ResultActions result = mockMvc.perform(builder); + final ResultActions result = mockMvc.perform(builder.header("Authorization", accessToken)); //then result.andExpect(status().isCreated()) @@ -407,11 +425,12 @@ void addEventWithEmptyNameTest(final String eventName) throws Exception { event.getPaymentType(), event.getOrganization()); final String contents = objectMapper.writeValueAsString(request); //when & then - mockMvc.perform(multipart("/events") + mockMvc.perform(multipart("/admin/events") .file("images", image1.getBytes()) .file("images", image2.getBytes()) .file(new MockMultipartFile("request", "", "application/json", contents.getBytes( StandardCharsets.UTF_8))) + .header("Authorization", accessToken) ) .andExpect(status().isBadRequest()); } @@ -448,11 +467,12 @@ void addEventWithEmptyLocationTest(final String eventLocation) throws Exception event.getPaymentType(), event.getOrganization()); final String contents = objectMapper.writeValueAsString(request); //when & then - mockMvc.perform(multipart("/events") + mockMvc.perform(multipart("/admin/events") .file("images", image1.getBytes()) .file("images", image2.getBytes()) .file(new MockMultipartFile("request", "", "application/json", contents.getBytes( StandardCharsets.UTF_8))) + .header("Authorization", accessToken) ) .andExpect(status().isBadRequest()); } @@ -490,11 +510,12 @@ void addEventWithInvalidInformationUrlTest(final String informationUrl) throws E event.getPaymentType(), event.getOrganization()); final String contents = objectMapper.writeValueAsString(request); //when & then - mockMvc.perform(multipart("/events") + mockMvc.perform(multipart("/admin/events") .file("images", image1.getBytes()) .file("images", image2.getBytes()) .file(new MockMultipartFile("request", "", "application/json", contents.getBytes( StandardCharsets.UTF_8))) + .header("Authorization", accessToken) ) .andExpect(status().isBadRequest()); } @@ -538,11 +559,12 @@ void addEventWithUnformattedStartDateTimeTest(final String startDateTime) final String contents = objectMapper.writeValueAsString(request); //when & then - mockMvc.perform(multipart("/events") + mockMvc.perform(multipart("/admin/events") .file("images", image1.getBytes()) .file("images", image2.getBytes()) .file(new MockMultipartFile("request", "", "application/json", contents.getBytes( StandardCharsets.UTF_8))) + .header("Authorization", accessToken) ) .andExpect(status().isBadRequest()); } @@ -585,11 +607,12 @@ void addEventWithUnformattedEndDateTimeTest(final String endDateTime) throws Exc final String contents = objectMapper.writeValueAsString(request); //when & then - mockMvc.perform(multipart("/events") + mockMvc.perform(multipart("/admin/events") .file("images", image1.getBytes()) .file("images", image2.getBytes()) .file(new MockMultipartFile("request", "", "application/json", contents.getBytes( StandardCharsets.UTF_8))) + .header("Authorization", accessToken) ) .andExpect(status().isBadRequest()); } diff --git a/backend/emm-sale/src/documentTest/java/com/emmsale/LoginApiTest.java b/backend/emm-sale/src/documentTest/java/com/emmsale/LoginApiTest.java index 01b3aae9c..7a146a28d 100644 --- a/backend/emm-sale/src/documentTest/java/com/emmsale/LoginApiTest.java +++ b/backend/emm-sale/src/documentTest/java/com/emmsale/LoginApiTest.java @@ -1,7 +1,9 @@ package com.emmsale; +import static org.mockito.ArgumentMatchers.any; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; import static org.springframework.restdocs.request.RequestDocumentation.requestParameters; @@ -9,18 +11,23 @@ import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.emmsale.admin.login.api.AdminLoginApi; +import com.emmsale.admin.login.application.dto.AdminLoginRequest; +import com.emmsale.admin.login.application.dto.AdminTokenResponse; import com.emmsale.login.api.LoginApi; import com.emmsale.login.application.dto.TokenResponse; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.mockito.BDDMockito; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.http.MediaType; import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.restdocs.payload.RequestFieldsSnippet; import org.springframework.restdocs.payload.ResponseFieldsSnippet; import org.springframework.restdocs.request.RequestParametersSnippet; import org.springframework.test.web.servlet.ResultActions; -@WebMvcTest(LoginApi.class) +@WebMvcTest({LoginApi.class, AdminLoginApi.class}) class LoginApiTest extends MockMvcTestHelper { @Test @@ -62,4 +69,35 @@ void illegalLoginTest() throws Exception { result.andExpect(status().isBadRequest()) .andDo(print()); } + + @Test + @DisplayName("id와 password가 유효할 경우 200과 함께 AdminTokenResponse를 반환해 준다.") + void availableAdminLoginTest() throws Exception { + // given + final AdminLoginRequest request = new AdminLoginRequest("관리자 id", "관리자 password"); + final AdminTokenResponse adminTokenResponse = new AdminTokenResponse("access_token"); + + BDDMockito.given(adminLoginService.createAdminToken(any())).willReturn(adminTokenResponse); + + final RequestFieldsSnippet requestFields = requestFields( + fieldWithPath("id").type(JsonFieldType.STRING).description("관리자 로그인 id"), + fieldWithPath("password").type(JsonFieldType.STRING).description("관리자 로그인 password") + ); + + final ResponseFieldsSnippet responseFields = responseFields( + fieldWithPath("accessToken").type(JsonFieldType.STRING).description("관리자 Access Token 값") + ); + + // when + final ResultActions result = mockMvc.perform( + post("/admin/login") + .contentType(MediaType.APPLICATION_JSON_VALUE) + .content(objectMapper.writeValueAsString(request)) + ); + + // then + result.andExpect(status().isOk()) + .andDo(print()) + .andDo(document("admin-login-snippet", requestFields, responseFields)); + } } diff --git a/backend/emm-sale/src/documentTest/java/com/emmsale/MockMvcTestHelper.java b/backend/emm-sale/src/documentTest/java/com/emmsale/MockMvcTestHelper.java index 350bfbf05..d3debbb60 100644 --- a/backend/emm-sale/src/documentTest/java/com/emmsale/MockMvcTestHelper.java +++ b/backend/emm-sale/src/documentTest/java/com/emmsale/MockMvcTestHelper.java @@ -3,13 +3,16 @@ import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; -import com.emmsale.activity.application.ActivityCommandService; import com.emmsale.activity.application.ActivityQueryService; +import com.emmsale.admin.activity.application.ActivityCommandService; +import com.emmsale.admin.event.application.EventCommandService; +import com.emmsale.admin.login.application.AdminLoginService; +import com.emmsale.admin.report.application.ReportQueryService; +import com.emmsale.admin.tag.application.TagCommandService; import com.emmsale.block.application.BlockCommandService; import com.emmsale.block.application.BlockQueryService; import com.emmsale.comment.application.CommentCommandService; import com.emmsale.comment.application.CommentQueryService; -import com.emmsale.event.application.EventCommandService; import com.emmsale.event.application.EventQueryService; import com.emmsale.event.application.RecruitmentPostCommandService; import com.emmsale.event.application.RecruitmentPostQueryService; @@ -27,11 +30,9 @@ import com.emmsale.notification.application.NotificationCommandService; import com.emmsale.notification.application.NotificationQueryService; import com.emmsale.report.application.ReportCommandService; -import com.emmsale.report.application.ReportQueryService; import com.emmsale.resolver.MemberArgumentResolver; import com.emmsale.scrap.application.ScrapCommandService; import com.emmsale.scrap.application.ScrapQueryService; -import com.emmsale.tag.application.TagCommandService; import com.emmsale.tag.application.TagQueryService; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.BeforeEach; @@ -81,6 +82,8 @@ abstract class MockMvcTestHelper { @MockBean protected LoginService loginService; @MockBean + protected AdminLoginService adminLoginService; + @MockBean protected EventQueryService eventQueryService; @MockBean protected EventCommandService eventCommandService; diff --git a/backend/emm-sale/src/documentTest/java/com/emmsale/RecruitmentPostApiTest.java b/backend/emm-sale/src/documentTest/java/com/emmsale/RecruitmentPostApiTest.java index 17c61de19..cc8ad1ad6 100644 --- a/backend/emm-sale/src/documentTest/java/com/emmsale/RecruitmentPostApiTest.java +++ b/backend/emm-sale/src/documentTest/java/com/emmsale/RecruitmentPostApiTest.java @@ -47,7 +47,8 @@ class RecruitmentPostApiTest extends MockMvcTestHelper { .description("member의 이미지 url"), fieldWithPath("[].member.githubUrl").type(JsonFieldType.STRING) .description("member의 github Url"), - fieldWithPath("[].eventId").type(JsonFieldType.NUMBER).description("행사의 식별자") + fieldWithPath("[].eventId").type(JsonFieldType.NUMBER).description("행사의 식별자"), + fieldWithPath("[].eventName").type(JsonFieldType.STRING).description("행사의 이름") ); private static final ResponseFieldsSnippet RECRUITMENT_POST_RESPONSE_FIELDS = responseFields( @@ -62,7 +63,8 @@ class RecruitmentPostApiTest extends MockMvcTestHelper { .description("member의 이미지 url"), fieldWithPath("member.githubUrl").type(JsonFieldType.STRING) .description("member의 github Url"), - fieldWithPath("eventId").type(JsonFieldType.NUMBER).description("행사의 식별자") + fieldWithPath("eventId").type(JsonFieldType.NUMBER).description("행사의 식별자"), + fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사의 이름") ); @Test @@ -125,9 +127,9 @@ void findRecruitmentPosts() throws Exception { final LocalDate postedAt = LocalDate.of(2023, 7, 15); final List response = List.of( new RecruitmentPostQueryResponse(1L, "함께해요~", postedAt, - MemberReferenceResponse.from(member1), 21L), + MemberReferenceResponse.from(member1), 21L, "21번 행사"), new RecruitmentPostQueryResponse(2L, "같이 가요~", postedAt, - MemberReferenceResponse.from(member2), 43L) + MemberReferenceResponse.from(member2), 43L, "43번 행사") ); when(postQueryService.findRecruitmentPosts(eventId)).thenReturn(response); @@ -150,7 +152,7 @@ void findRecruitmentPost() throws Exception { final RecruitmentPostQueryResponse response = new RecruitmentPostQueryResponse(1L, "함께해요~", postedAt, - MemberReferenceResponse.from(member), 21L); + MemberReferenceResponse.from(member), 21L, "21번 행사"); when(postQueryService.findRecruitmentPost(eventId, postId)).thenReturn(response); //when && then @@ -212,9 +214,9 @@ void findRecruitmentPostsByMemberIdTest() throws Exception { final LocalDate postedAt = LocalDate.of(2023, 7, 15); final List response = List.of( new RecruitmentPostQueryResponse(1L, "함께해요~", postedAt, - MemberReferenceResponse.from(member), 21L), + MemberReferenceResponse.from(member), 21L,"21번 행사"), new RecruitmentPostQueryResponse(2L, "같이 가요~", postedAt, - MemberReferenceResponse.from(member), 43L) + MemberReferenceResponse.from(member), 43L, "43번 행사") ); //when @@ -222,8 +224,7 @@ void findRecruitmentPostsByMemberIdTest() throws Exception { //then mockMvc.perform( - get("/events/recruitment-posts?member-id={memberId}", - memberId) + get("/events/recruitment-posts?member-id={memberId}", memberId) .header(HttpHeaders.AUTHORIZATION, "Bearer AccessToken")) .andExpect(status().isOk()) .andDo(document("find-all-by-member-id-recruitment-post", diff --git a/backend/emm-sale/src/documentTest/java/com/emmsale/ReportApiTest.java b/backend/emm-sale/src/documentTest/java/com/emmsale/ReportApiTest.java index 580fcbf05..8658fd3a1 100644 --- a/backend/emm-sale/src/documentTest/java/com/emmsale/ReportApiTest.java +++ b/backend/emm-sale/src/documentTest/java/com/emmsale/ReportApiTest.java @@ -10,6 +10,8 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.emmsale.admin.report.api.AdminReportApi; +import com.emmsale.member.domain.Member; import com.emmsale.report.api.ReportApi; import com.emmsale.report.application.dto.ReportCreateRequest; import com.emmsale.report.application.dto.ReportCreateResponse; @@ -25,7 +27,7 @@ import org.springframework.restdocs.payload.RequestFieldsSnippet; import org.springframework.restdocs.payload.ResponseFieldsSnippet; -@WebMvcTest(ReportApi.class) +@WebMvcTest({ReportApi.class, AdminReportApi.class}) class ReportApiTest extends MockMvcTestHelper { @Test @@ -74,6 +76,7 @@ void addReport() throws Exception { @DisplayName("신고 목록을 조회할 수 있다.") void findReports() throws Exception { // given + final String accessToken = "Bearer accessToken"; final ResponseFieldsSnippet responseFields = responseFields( fieldWithPath("[].id").type(JsonFieldType.NUMBER).description("신고 id"), fieldWithPath("[].reporterId").type(JsonFieldType.NUMBER).description("신고자의 Id"), @@ -97,10 +100,11 @@ void findReports() throws Exception { ); - when(reportQueryService.findReports()).thenReturn(reportFindResponse); + when(reportQueryService.findReports(any(Member.class))).thenReturn(reportFindResponse); // when & then - mockMvc.perform(get("/reports")) + mockMvc.perform(get("/admin/reports") + .header("Authorization", accessToken)) .andExpect(status().isOk()) .andDo(document("find-reports", responseFields)); } diff --git a/backend/emm-sale/src/documentTest/java/com/emmsale/ScrapApiTest.java b/backend/emm-sale/src/documentTest/java/com/emmsale/ScrapApiTest.java index 9b7d2d5bb..3aa7a4059 100644 --- a/backend/emm-sale/src/documentTest/java/com/emmsale/ScrapApiTest.java +++ b/backend/emm-sale/src/documentTest/java/com/emmsale/ScrapApiTest.java @@ -16,6 +16,7 @@ import com.emmsale.event.domain.PaymentType; import com.emmsale.scrap.api.ScrapApi; import com.emmsale.scrap.application.dto.ScrapRequest; +import com.emmsale.tag.application.dto.TagResponse; import java.time.LocalDateTime; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -31,7 +32,13 @@ @WebMvcTest(ScrapApi.class) class ScrapApiTest extends MockMvcTestHelper { - final ResponseFieldsSnippet SCRAPPED_EVENT_RESPONSE_FIELDS = PayloadDocumentation.responseFields( + private static final List TAG_RESPONSES = List.of( + new TagResponse(1L, "백엔드"), new TagResponse(2L, "프론트엔드"), + new TagResponse(3L, "안드로이드"), new TagResponse(4L, "IOS"), + new TagResponse(5L, "AI") + ); + + static final ResponseFieldsSnippet SCRAPPED_EVENT_RESPONSE_FIELDS = PayloadDocumentation.responseFields( fieldWithPath("id").type(JsonFieldType.NUMBER).description("행사 식별자"), fieldWithPath("name").type(JsonFieldType.STRING) .description("행사 이름"), @@ -45,7 +52,9 @@ class ScrapApiTest extends MockMvcTestHelper { fieldWithPath("applyEndDate").type(JsonFieldType.STRING) .description("행사 신청 종료 일자(nullable)"), fieldWithPath("location").type(JsonFieldType.STRING).description("행사 장소"), - fieldWithPath("tags[]").type(JsonFieldType.ARRAY).description("행사 태그들"), + fieldWithPath("tags[]").type(JsonFieldType.ARRAY).description("태그들"), + fieldWithPath("tags[].id").type(JsonFieldType.NUMBER).description("행사 태그 ID"), + fieldWithPath("tags[].name").type(JsonFieldType.STRING).description("행사 태그 이름"), fieldWithPath("thumbnailUrl").type(JsonFieldType.STRING) .description("행사 섬네일 이미지 Url(포스터)"), fieldWithPath("type").type(JsonFieldType.STRING) @@ -70,7 +79,7 @@ void findAllScraps() throws Exception { LocalDateTime.parse("2023-09-01T00:00:00"), LocalDateTime.parse("2023-09-02T23:59:59"), "코엑스", - List.of("백엔드", "프론트엔드", "안드로이드", "IOS", "AI"), + TAG_RESPONSES, "image0.jpg", EventType.CONFERENCE.name(), List.of("image1.jpg", "image2.jpg", "image3.jpg"), @@ -87,7 +96,7 @@ void findAllScraps() throws Exception { LocalDateTime.parse("2023-09-01T00:00:00"), LocalDateTime.parse("2023-09-02T23:59:59"), "코엑스", - List.of("백엔드", "프론트엔드", "안드로이드", "IOS", "AI"), + TAG_RESPONSES, "image0.jpg", EventType.CONFERENCE.name(), List.of("image1.jpg", "image2.jpg", "image3.jpg"), @@ -102,7 +111,7 @@ void findAllScraps() throws Exception { LocalDateTime.parse("2023-09-01T00:00:00"), LocalDateTime.parse("2023-09-02T23:59:59"), "코엑스", - List.of("백엔드", "프론트엔드", "안드로이드", "IOS", "AI"), + TAG_RESPONSES, "image0.jpg", EventType.CONFERENCE.name(), List.of("image1.jpg", "image2.jpg", "image3.jpg"), @@ -125,7 +134,9 @@ void findAllScraps() throws Exception { fieldWithPath("[].applyEndDate").type(JsonFieldType.STRING) .description("행사 신청 종료 일자(nullable)"), fieldWithPath("[].location").type(JsonFieldType.STRING).description("행사 장소"), - fieldWithPath("[].tags[]").type(JsonFieldType.ARRAY).description("행사 태그들"), + fieldWithPath("[].tags[]").type(JsonFieldType.ARRAY).description("태그들"), + fieldWithPath("[].tags[].id").type(JsonFieldType.NUMBER).description("행사 태그 ID"), + fieldWithPath("[].tags[].name").type(JsonFieldType.STRING).description("행사 태그 이름"), fieldWithPath("[].thumbnailUrl").type(JsonFieldType.STRING) .description("행사 섬네일 이미지 Url(포스터)"), fieldWithPath("[].type").type(JsonFieldType.STRING) @@ -161,7 +172,7 @@ void append() throws Exception { LocalDateTime.parse("2023-09-01T00:00:00"), LocalDateTime.parse("2023-09-02T23:59:59"), "코엑스", - List.of("백엔드", "프론트엔드", "안드로이드", "IOS", "AI"), + TAG_RESPONSES, "image0.jpg", EventType.CONFERENCE.name(), List.of("image1.jpg", "image2.jpg", "image3.jpg"), @@ -199,7 +210,7 @@ void deleteScrap() throws Exception { LocalDateTime.parse("2023-09-01T00:00:00"), LocalDateTime.parse("2023-09-02T23:59:59"), "코엑스", - List.of("백엔드", "프론트엔드", "안드로이드", "IOS", "AI"), + TAG_RESPONSES, "image0.jpg", EventType.CONFERENCE.name(), List.of("image1.jpg", "image2.jpg", "image3.jpg"), diff --git a/backend/emm-sale/src/documentTest/java/com/emmsale/TagApiTest.java b/backend/emm-sale/src/documentTest/java/com/emmsale/TagApiTest.java index fd15419a4..67ec043b0 100644 --- a/backend/emm-sale/src/documentTest/java/com/emmsale/TagApiTest.java +++ b/backend/emm-sale/src/documentTest/java/com/emmsale/TagApiTest.java @@ -10,6 +10,8 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.emmsale.admin.tag.api.AdminTagApi; +import com.emmsale.member.domain.Member; import com.emmsale.tag.api.TagApi; import com.emmsale.tag.application.dto.TagRequest; import com.emmsale.tag.application.dto.TagResponse; @@ -22,7 +24,7 @@ import org.springframework.restdocs.payload.RequestFieldsSnippet; import org.springframework.restdocs.payload.ResponseFieldsSnippet; -@WebMvcTest(TagApi.class) +@WebMvcTest({TagApi.class, AdminTagApi.class}) class TagApiTest extends MockMvcTestHelper { @Test @@ -57,8 +59,9 @@ void addTag() throws Exception { ); final TagRequest request = new TagRequest("프론트"); final TagResponse response = new TagResponse(3L, "프론트"); + final String accessToken = "Bearer accessToken"; - when(tagCommandService.addTag(any(TagRequest.class))).thenReturn(response); + when(tagCommandService.addTag(any(TagRequest.class), any(Member.class))).thenReturn(response); final ResponseFieldsSnippet responseFields = responseFields( fieldWithPath("id").type(JsonFieldType.NUMBER).description("태그 식별자"), @@ -66,7 +69,8 @@ void addTag() throws Exception { ); //when & then - mockMvc.perform(post("/tags") + mockMvc.perform(post("/admin/tags") + .header("Authorization", accessToken) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(status().isCreated()) diff --git a/backend/emm-sale/src/main/java/com/emmsale/activity/api/ActivityApi.java b/backend/emm-sale/src/main/java/com/emmsale/activity/api/ActivityApi.java index ed2e74e79..d8a600abc 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/activity/api/ActivityApi.java +++ b/backend/emm-sale/src/main/java/com/emmsale/activity/api/ActivityApi.java @@ -1,16 +1,11 @@ package com.emmsale.activity.api; -import com.emmsale.activity.application.ActivityCommandService; import com.emmsale.activity.application.ActivityQueryService; -import com.emmsale.activity.application.dto.ActivityAddRequest; import com.emmsale.activity.application.dto.ActivityResponse; import java.util.List; import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -20,18 +15,9 @@ public class ActivityApi { private final ActivityQueryService activityQueryService; - private final ActivityCommandService activityCommandService; @GetMapping public ResponseEntity> findAll() { return ResponseEntity.ok(activityQueryService.findAll()); } - - @PostMapping - public ResponseEntity create( - @RequestBody final ActivityAddRequest request - ) { - return ResponseEntity.status(HttpStatus.CREATED) - .body(activityCommandService.addActivity(request)); - } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/admin/activity/api/AdminActivityApi.java b/backend/emm-sale/src/main/java/com/emmsale/admin/activity/api/AdminActivityApi.java new file mode 100644 index 000000000..26c990eca --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/admin/activity/api/AdminActivityApi.java @@ -0,0 +1,30 @@ +package com.emmsale.admin.activity.api; + +import com.emmsale.activity.application.dto.ActivityAddRequest; +import com.emmsale.activity.application.dto.ActivityResponse; +import com.emmsale.admin.activity.application.ActivityCommandService; +import com.emmsale.member.domain.Member; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/admin/activities") +@RequiredArgsConstructor +public class AdminActivityApi { + + private final ActivityCommandService activityCommandService; + + @PostMapping + public ResponseEntity create( + @RequestBody final ActivityAddRequest request, + final Member admin + ) { + return ResponseEntity.status(HttpStatus.CREATED) + .body(activityCommandService.addActivity(request, admin)); + } +} diff --git a/backend/emm-sale/src/main/java/com/emmsale/activity/application/ActivityCommandService.java b/backend/emm-sale/src/main/java/com/emmsale/admin/activity/application/ActivityCommandService.java similarity index 82% rename from backend/emm-sale/src/main/java/com/emmsale/activity/application/ActivityCommandService.java rename to backend/emm-sale/src/main/java/com/emmsale/admin/activity/application/ActivityCommandService.java index e5b6585fa..686d0cb34 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/activity/application/ActivityCommandService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/admin/activity/application/ActivityCommandService.java @@ -1,4 +1,6 @@ -package com.emmsale.activity.application; +package com.emmsale.admin.activity.application; + +import static com.emmsale.admin.login.utils.AdminValidator.validateAuthorization; import com.emmsale.activity.application.dto.ActivityAddRequest; import com.emmsale.activity.application.dto.ActivityResponse; @@ -6,6 +8,7 @@ import com.emmsale.activity.domain.ActivityRepository; import com.emmsale.activity.exception.ActivityException; import com.emmsale.activity.exception.ActivityExceptionType; +import com.emmsale.member.domain.Member; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -17,7 +20,8 @@ public class ActivityCommandService { private final ActivityRepository activityRepository; - public ActivityResponse addActivity(final ActivityAddRequest request) { + public ActivityResponse addActivity(final ActivityAddRequest request, final Member admin) { + validateAuthorization(admin); final String name = request.getName(); validateAlreadyExist(name); final Activity activity = new Activity(request.getActivityType(), name); @@ -30,4 +34,3 @@ private void validateAlreadyExist(final String name) { } } } - diff --git a/backend/emm-sale/src/main/java/com/emmsale/admin/event/api/AdminEventApi.java b/backend/emm-sale/src/main/java/com/emmsale/admin/event/api/AdminEventApi.java new file mode 100644 index 000000000..7d5647833 --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/admin/event/api/AdminEventApi.java @@ -0,0 +1,53 @@ +package com.emmsale.admin.event.api; + +import com.emmsale.admin.event.application.EventCommandService; +import com.emmsale.event.application.dto.EventDetailRequest; +import com.emmsale.event.application.dto.EventResponse; +import com.emmsale.member.domain.Member; +import java.util.List; +import javax.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +@RestController +@RequestMapping("/admin/events") +@RequiredArgsConstructor +public class AdminEventApi { + + private final EventCommandService eventCommandService; + + @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + @ResponseStatus(HttpStatus.CREATED) + public EventResponse addEvent(@RequestPart @Valid final EventDetailRequest request, + @RequestPart final List images, + final Member admin + ) { + return eventCommandService.addEvent(request, images, admin); + } + + @PutMapping(path = "/{eventId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + @ResponseStatus(HttpStatus.OK) + public EventResponse updateEvent(@PathVariable final Long eventId, + @RequestPart @Valid final EventDetailRequest request, + @RequestPart final List images, + final Member admin + ) { + return eventCommandService.updateEvent(eventId, request, images, admin); + } + + @DeleteMapping("/{eventId}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteEvent(@PathVariable final Long eventId, final Member admin) { + eventCommandService.deleteEvent(eventId, admin); + } +} diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventCommandService.java b/backend/emm-sale/src/main/java/com/emmsale/admin/event/application/EventCommandService.java similarity index 89% rename from backend/emm-sale/src/main/java/com/emmsale/event/application/EventCommandService.java rename to backend/emm-sale/src/main/java/com/emmsale/admin/event/application/EventCommandService.java index c958f360a..244217c33 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventCommandService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/admin/event/application/EventCommandService.java @@ -1,5 +1,6 @@ -package com.emmsale.event.application; +package com.emmsale.admin.event.application; +import static com.emmsale.admin.login.utils.AdminValidator.validateAuthorization; import static com.emmsale.event.exception.EventExceptionType.NOT_FOUND_EVENT; import static java.util.stream.Collectors.toList; @@ -14,6 +15,7 @@ import com.emmsale.image.application.ImageCommandService; import com.emmsale.image.domain.AllImagesOfContent; import com.emmsale.image.domain.ImageType; +import com.emmsale.member.domain.Member; import com.emmsale.tag.application.dto.TagRequest; import com.emmsale.tag.domain.Tag; import com.emmsale.tag.domain.TagRepository; @@ -36,7 +38,8 @@ public class EventCommandService { private final ImageCommandService imageCommandService; public EventResponse addEvent(final EventDetailRequest request, - final List images) { + final List images, final Member admin) { + validateAuthorization(admin); final Event event = eventRepository.save(request.toEvent()); final List tags = findAllPersistTagsOrElseThrow(request.getTags()); event.addAllEventTags(tags); @@ -49,7 +52,8 @@ public EventResponse addEvent(final EventDetailRequest request, } public EventResponse updateEvent(final Long eventId, final EventDetailRequest request, - final List images) { + final List images, final Member admin) { + validateAuthorization(admin); final Event event = eventRepository.findById(eventId) .orElseThrow(() -> new EventException(NOT_FOUND_EVENT)); @@ -77,7 +81,8 @@ public EventResponse updateEvent(final Long eventId, final EventDetailRequest re return EventResponse.from(updatedEvent, savedImages); } - public void deleteEvent(final Long eventId) { + public void deleteEvent(final Long eventId, final Member admin) { + validateAuthorization(admin); if (!eventRepository.existsById(eventId)) { throw new EventException(NOT_FOUND_EVENT); } diff --git a/backend/emm-sale/src/main/java/com/emmsale/admin/login/api/AdminLoginApi.java b/backend/emm-sale/src/main/java/com/emmsale/admin/login/api/AdminLoginApi.java new file mode 100644 index 000000000..3256fb6da --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/admin/login/api/AdminLoginApi.java @@ -0,0 +1,26 @@ +package com.emmsale.admin.login.api; + +import com.emmsale.admin.login.application.AdminLoginService; +import com.emmsale.admin.login.application.dto.AdminLoginRequest; +import com.emmsale.admin.login.application.dto.AdminTokenResponse; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/admin/login") +public class AdminLoginApi { + + private final AdminLoginService adminLoginService; + + public AdminLoginApi(final AdminLoginService adminLoginService) { + this.adminLoginService = adminLoginService; + } + + @PostMapping + public ResponseEntity login(@RequestBody final AdminLoginRequest request) { + return ResponseEntity.ok().body(adminLoginService.createAdminToken(request)); + } +} diff --git a/backend/emm-sale/src/main/java/com/emmsale/admin/login/application/AdminLoginService.java b/backend/emm-sale/src/main/java/com/emmsale/admin/login/application/AdminLoginService.java new file mode 100644 index 000000000..4eee73f9c --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/admin/login/application/AdminLoginService.java @@ -0,0 +1,45 @@ +package com.emmsale.admin.login.application; + +import com.emmsale.admin.login.application.dto.AdminLoginRequest; +import com.emmsale.admin.login.application.dto.AdminTokenResponse; +import com.emmsale.login.exception.LoginException; +import com.emmsale.login.exception.LoginExceptionType; +import com.emmsale.login.utils.JwtTokenProvider; +import javax.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +@Transactional +@RequiredArgsConstructor +public class AdminLoginService { + + private final JwtTokenProvider tokenProvider; + @Value("${data.admin_login.id}") + private String adminId; + @Value("${data.admin_login.password}") + private String adminPassword; + @Value("${data.admin_login.member_id}") + private Long adminMemberId; + + public AdminTokenResponse createAdminToken(final AdminLoginRequest request) { + validateNotNullRequest(request); + validateAdminLoginInformation(request); + final String accessToken = tokenProvider.createToken(String.valueOf(adminMemberId)); + + return new AdminTokenResponse(accessToken); + } + + private void validateNotNullRequest(final AdminLoginRequest request) { + if (request == null) { + throw new LoginException(LoginExceptionType.NOT_FOUND_ADMIN_LOGIN_INFORMATION); + } + } + + private void validateAdminLoginInformation(final AdminLoginRequest request) { + if (!(request.getId().equals(adminId) && request.getPassword().equals(adminPassword))) { + throw new LoginException(LoginExceptionType.INVALID_ADMIN_LOGIN_INFORMATION); + } + } +} diff --git a/backend/emm-sale/src/main/java/com/emmsale/admin/login/application/dto/AdminLoginRequest.java b/backend/emm-sale/src/main/java/com/emmsale/admin/login/application/dto/AdminLoginRequest.java new file mode 100644 index 000000000..ed02c9ece --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/admin/login/application/dto/AdminLoginRequest.java @@ -0,0 +1,13 @@ +package com.emmsale.admin.login.application.dto; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class AdminLoginRequest { + + private final String id; + private final String password; + +} diff --git a/backend/emm-sale/src/main/java/com/emmsale/admin/login/application/dto/AdminTokenResponse.java b/backend/emm-sale/src/main/java/com/emmsale/admin/login/application/dto/AdminTokenResponse.java new file mode 100644 index 000000000..120c07e91 --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/admin/login/application/dto/AdminTokenResponse.java @@ -0,0 +1,11 @@ +package com.emmsale.admin.login.application.dto; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Getter +public class AdminTokenResponse { + + private final String accessToken; +} diff --git a/backend/emm-sale/src/main/java/com/emmsale/admin/login/utils/AdminValidator.java b/backend/emm-sale/src/main/java/com/emmsale/admin/login/utils/AdminValidator.java new file mode 100644 index 000000000..6ae80eb7d --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/admin/login/utils/AdminValidator.java @@ -0,0 +1,24 @@ +package com.emmsale.admin.login.utils; + +import com.emmsale.login.exception.LoginException; +import com.emmsale.login.exception.LoginExceptionType; +import com.emmsale.member.domain.Member; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class AdminValidator { + + private static Long adminMemberId; + + public static void validateAuthorization(final Member admin) { + if (admin.isNotMe(adminMemberId)) { + throw new LoginException(LoginExceptionType.INVALID_ADMIN_ACCESS_TOKEN); + } + } + + @Value("${data.admin_login.member_id}") + public void setAdminMemberId(final Long adminMemberId) { + AdminValidator.adminMemberId = adminMemberId; + } +} diff --git a/backend/emm-sale/src/main/java/com/emmsale/admin/report/api/AdminReportApi.java b/backend/emm-sale/src/main/java/com/emmsale/admin/report/api/AdminReportApi.java new file mode 100644 index 000000000..00c9c9895 --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/admin/report/api/AdminReportApi.java @@ -0,0 +1,23 @@ +package com.emmsale.admin.report.api; + +import com.emmsale.admin.report.application.ReportQueryService; +import com.emmsale.member.domain.Member; +import com.emmsale.report.application.dto.ReportFindResponse; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/admin/reports") +@RequiredArgsConstructor +public class AdminReportApi { + + private final ReportQueryService reportQueryService; + + @GetMapping + public List findReports(final Member admin) { + return reportQueryService.findReports(admin); + } +} diff --git a/backend/emm-sale/src/main/java/com/emmsale/report/application/ReportQueryService.java b/backend/emm-sale/src/main/java/com/emmsale/admin/report/application/ReportQueryService.java similarity index 65% rename from backend/emm-sale/src/main/java/com/emmsale/report/application/ReportQueryService.java rename to backend/emm-sale/src/main/java/com/emmsale/admin/report/application/ReportQueryService.java index 6ca29076a..1535b0b45 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/report/application/ReportQueryService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/admin/report/application/ReportQueryService.java @@ -1,5 +1,8 @@ -package com.emmsale.report.application; +package com.emmsale.admin.report.application; +import static com.emmsale.admin.login.utils.AdminValidator.validateAuthorization; + +import com.emmsale.member.domain.Member; import com.emmsale.report.application.dto.ReportFindResponse; import com.emmsale.report.domain.repository.ReportRepository; import java.util.List; @@ -14,7 +17,8 @@ public class ReportQueryService { private final ReportRepository reportRepository; - public List findReports() { + public List findReports(final Member admin) { + validateAuthorization(admin); return ReportFindResponse.from(reportRepository.findAll()); } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/admin/tag/api/AdminTagApi.java b/backend/emm-sale/src/main/java/com/emmsale/admin/tag/api/AdminTagApi.java new file mode 100644 index 000000000..182c050b2 --- /dev/null +++ b/backend/emm-sale/src/main/java/com/emmsale/admin/tag/api/AdminTagApi.java @@ -0,0 +1,27 @@ +package com.emmsale.admin.tag.api; + +import com.emmsale.admin.tag.application.TagCommandService; +import com.emmsale.member.domain.Member; +import com.emmsale.tag.application.dto.TagRequest; +import com.emmsale.tag.application.dto.TagResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/admin/tags") +@RequiredArgsConstructor +public class AdminTagApi { + + private final TagCommandService commandService; + + @PostMapping + public ResponseEntity create(@RequestBody final TagRequest tagRequest, + final Member admin) { + return ResponseEntity.status(HttpStatus.CREATED).body(commandService.addTag(tagRequest, admin)); + } +} diff --git a/backend/emm-sale/src/main/java/com/emmsale/tag/application/TagCommandService.java b/backend/emm-sale/src/main/java/com/emmsale/admin/tag/application/TagCommandService.java similarity index 75% rename from backend/emm-sale/src/main/java/com/emmsale/tag/application/TagCommandService.java rename to backend/emm-sale/src/main/java/com/emmsale/admin/tag/application/TagCommandService.java index e81fbfda0..57ed1375e 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/tag/application/TagCommandService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/admin/tag/application/TagCommandService.java @@ -1,5 +1,8 @@ -package com.emmsale.tag.application; +package com.emmsale.admin.tag.application; +import static com.emmsale.admin.login.utils.AdminValidator.validateAuthorization; + +import com.emmsale.member.domain.Member; import com.emmsale.tag.application.dto.TagRequest; import com.emmsale.tag.application.dto.TagResponse; import com.emmsale.tag.domain.Tag; @@ -17,7 +20,9 @@ public class TagCommandService { private final TagRepository tagRepository; - public TagResponse addTag(final TagRequest request) { + public TagResponse addTag(final TagRequest request, + final Member admin) { + validateAuthorization(admin); final String name = request.getName(); validateAlreadyExist(name); return TagResponse.from(tagRepository.save(new Tag(name))); 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 7aebba943..c719bc0b7 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 @@ -1,30 +1,19 @@ package com.emmsale.event.api; -import com.emmsale.event.application.EventCommandService; import com.emmsale.event.application.EventQueryService; -import com.emmsale.event.application.dto.EventDetailRequest; import com.emmsale.event.application.dto.EventResponse; import com.emmsale.event.domain.EventStatus; import com.emmsale.event.domain.EventType; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; -import javax.validation.Valid; import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RequestPart; -import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.multipart.MultipartFile; @RestController @RequestMapping("/events") @@ -32,7 +21,6 @@ public class EventApi { private final EventQueryService eventQueryService; - private final EventCommandService eventCommandService; @GetMapping("/{id}") public ResponseEntity findEventById(@PathVariable final Long id) { @@ -52,25 +40,4 @@ public ResponseEntity> findEvents( statuses, keyword)); } - - @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - @ResponseStatus(HttpStatus.CREATED) - public EventResponse addEvent(@RequestPart @Valid final EventDetailRequest request, - @RequestPart final List images) { - return eventCommandService.addEvent(request, images); - } - - @PutMapping(path = "/{eventId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - @ResponseStatus(HttpStatus.OK) - public EventResponse updateEvent(@PathVariable final Long eventId, - @RequestPart @Valid final EventDetailRequest request, - @RequestPart final List images) { - return eventCommandService.updateEvent(eventId, request, images); - } - - @DeleteMapping("/{eventId}") - @ResponseStatus(HttpStatus.NO_CONTENT) - public void deleteEvent(@PathVariable final Long eventId) { - eventCommandService.deleteEvent(eventId); - } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/api/RecruitmentPostApi.java b/backend/emm-sale/src/main/java/com/emmsale/event/api/RecruitmentPostApi.java index 96d4f7b83..7dcc592e6 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/api/RecruitmentPostApi.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/api/RecruitmentPostApi.java @@ -12,7 +12,6 @@ import java.util.List; import javax.validation.Valid; import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -22,7 +21,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; @RestController @@ -95,11 +93,12 @@ public ResponseEntity isAlreadyRecruit( } @GetMapping("/recruitment-posts") - @ResponseStatus(HttpStatus.OK) - public List findRecruitmentPostsByMemberId( + public ResponseEntity> findRecruitmentPostsByMemberId( final Member member, @RequestParam("member-id") final Long memberId ) { - return postQueryService.findRecruitmentPostsByMemberId(member, memberId); + final List responses + = postQueryService.findRecruitmentPostsByMemberId(member, memberId); + return ResponseEntity.ok(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 index de14d8ab3..e4cfed34b 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 @@ -6,7 +6,7 @@ import com.emmsale.event.domain.EventStatus; import com.emmsale.event.domain.EventTag; import com.emmsale.image.domain.AllImagesOfContent; -import com.emmsale.tag.domain.Tag; +import com.emmsale.tag.application.dto.TagResponse; import com.fasterxml.jackson.annotation.JsonFormat; import java.time.LocalDateTime; import java.util.ArrayList; @@ -34,7 +34,7 @@ public class EventResponse { @JsonFormat(pattern = DATE_TIME_FORMAT) private final LocalDateTime applyEndDate; private final String location; - private final List tags; + private final List tags; private final String thumbnailUrl; private final String type; private final List imageUrls; @@ -46,9 +46,9 @@ public static EventResponse from( final Event event, final AllImagesOfContent images ) { - final List tagNames = event.getTags().stream() + final List tagResponses = event.getTags().stream() .map(EventTag::getTag) - .map(Tag::getName) + .map(TagResponse::from) .collect(toUnmodifiableList()); return new EventResponse( @@ -60,7 +60,7 @@ public static EventResponse from( event.getEventPeriod().getApplyStartDate(), event.getEventPeriod().getApplyEndDate(), event.getLocation(), - tagNames, + tagResponses, images.extractThumbnailImage(), event.getType().toString(), images.extractInformationImages(), diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/application/dto/RecruitmentPostQueryResponse.java b/backend/emm-sale/src/main/java/com/emmsale/event/application/dto/RecruitmentPostQueryResponse.java index 0740f7826..cd6e0e592 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/application/dto/RecruitmentPostQueryResponse.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/application/dto/RecruitmentPostQueryResponse.java @@ -20,6 +20,7 @@ public class RecruitmentPostQueryResponse { private final LocalDate updatedAt; private final MemberReferenceResponse member; private final Long eventId; + private final String eventName; public static RecruitmentPostQueryResponse from(final RecruitmentPost recruitmentPost) { final Member member = recruitmentPost.getMember(); @@ -28,7 +29,8 @@ public static RecruitmentPostQueryResponse from(final RecruitmentPost recruitmen recruitmentPost.getContent(), recruitmentPost.getUpdatedAt().toLocalDate(), MemberReferenceResponse.from(member), - recruitmentPost.getEvent().getId() + recruitmentPost.getEvent().getId(), + recruitmentPost.getEvent().getName() ); } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/domain/repository/RecruitmentPostRepository.java b/backend/emm-sale/src/main/java/com/emmsale/event/domain/repository/RecruitmentPostRepository.java index 260aa41da..9bf80b910 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/domain/repository/RecruitmentPostRepository.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/domain/repository/RecruitmentPostRepository.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; @Repository @@ -14,5 +15,8 @@ public interface RecruitmentPostRepository extends JpaRepository findAllByMember(Member member); } diff --git a/backend/emm-sale/src/main/java/com/emmsale/login/exception/LoginExceptionType.java b/backend/emm-sale/src/main/java/com/emmsale/login/exception/LoginExceptionType.java index 414d3a738..a2b38f375 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/login/exception/LoginExceptionType.java +++ b/backend/emm-sale/src/main/java/com/emmsale/login/exception/LoginExceptionType.java @@ -14,7 +14,7 @@ public enum LoginExceptionType implements BaseExceptionType { "GitHub Profile을 찾을 수 없습니다." ), INVALID_ACCESS_TOKEN( - HttpStatus.BAD_REQUEST, + HttpStatus.UNAUTHORIZED, "토큰이 유효하지 않습니다." ), NOT_FOUND_AUTHORIZATION_TOKEN( @@ -32,6 +32,18 @@ public enum LoginExceptionType implements BaseExceptionType { INVALID_ACCESS_TOKEN_TYPE( HttpStatus.BAD_REQUEST, "Access Token Type이 올바르지 않습니다." + ), + NOT_FOUND_ADMIN_LOGIN_INFORMATION( + HttpStatus.BAD_REQUEST, + "관리자 로그인 정보를 찾을 수 없습니다." + ), + INVALID_ADMIN_LOGIN_INFORMATION( + HttpStatus.BAD_REQUEST, + "관리자 아이디 또는 비밀번호가 올바르지 않습니다." + ), + INVALID_ADMIN_ACCESS_TOKEN( + HttpStatus.BAD_REQUEST, + "관리자 토큰이 유효하지 않습니다." ); private final HttpStatus httpStatus; diff --git a/backend/emm-sale/src/main/java/com/emmsale/report/api/ReportApi.java b/backend/emm-sale/src/main/java/com/emmsale/report/api/ReportApi.java index 3779984ca..2754f24e5 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/report/api/ReportApi.java +++ b/backend/emm-sale/src/main/java/com/emmsale/report/api/ReportApi.java @@ -2,14 +2,10 @@ import com.emmsale.member.domain.Member; import com.emmsale.report.application.ReportCommandService; -import com.emmsale.report.application.ReportQueryService; import com.emmsale.report.application.dto.ReportCreateRequest; import com.emmsale.report.application.dto.ReportCreateResponse; -import com.emmsale.report.application.dto.ReportFindResponse; -import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseStatus; @@ -20,7 +16,6 @@ public class ReportApi { private final ReportCommandService reportCommandService; - private final ReportQueryService reportQueryService; @PostMapping("/reports") @ResponseStatus(HttpStatus.CREATED) @@ -28,9 +23,4 @@ public ReportCreateResponse create(@RequestBody final ReportCreateRequest report final Member member) { return reportCommandService.create(reportRequest, member); } - - @GetMapping("/reports") - public List findReports() { - return reportQueryService.findReports(); - } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/tag/api/TagApi.java b/backend/emm-sale/src/main/java/com/emmsale/tag/api/TagApi.java index 0457dda7a..3534659b6 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/tag/api/TagApi.java +++ b/backend/emm-sale/src/main/java/com/emmsale/tag/api/TagApi.java @@ -1,16 +1,11 @@ package com.emmsale.tag.api; -import com.emmsale.tag.application.TagCommandService; import com.emmsale.tag.application.TagQueryService; -import com.emmsale.tag.application.dto.TagRequest; import com.emmsale.tag.application.dto.TagResponse; import java.util.List; import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -20,15 +15,9 @@ public class TagApi { private final TagQueryService queryService; - private final TagCommandService commandService; @GetMapping public ResponseEntity> findAll() { return ResponseEntity.ok(queryService.findAll()); } - - @PostMapping - public ResponseEntity create(@RequestBody final TagRequest tagRequest) { - return ResponseEntity.status(HttpStatus.CREATED).body(commandService.addTag(tagRequest)); - } } diff --git a/backend/emm-sale/src/main/resources/application.yml b/backend/emm-sale/src/main/resources/application.yml index 652a9a99e..9a4ac3ef9 100644 --- a/backend/emm-sale/src/main/resources/application.yml +++ b/backend/emm-sale/src/main/resources/application.yml @@ -52,6 +52,10 @@ firebase: data: admin-url: http://localhost:3000 + admin_login: + id: admin + password: 1234 + member_id: 3 cloud: aws: diff --git a/backend/emm-sale/src/main/resources/data.sql b/backend/emm-sale/src/main/resources/data.sql index 364184b07..1c4e47221 100644 --- a/backend/emm-sale/src/main/resources/data.sql +++ b/backend/emm-sale/src/main/resources/data.sql @@ -46,6 +46,12 @@ insert into member(id, name, image_url, open_profile_url, description, github_id values (2, 'member2', 'https://imageurl.com', 'https://openprofileurl.com', '반갑습니다.', 2, 'amaran-th22', CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); +insert into member(id, name, image_url, open_profile_url, description, github_id, github_username, + created_at, + updated_at) +values (3, 'admin', 'https://imageurl.com', 'https://openprofileurl.com', '반갑습니다.', 3, + 'amaran-th22', CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); + insert into member_activity(id, activity_id, member_id, created_at, updated_at) values (1, 1, 1, CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); diff --git a/backend/emm-sale/src/main/resources/kerdy-submodule b/backend/emm-sale/src/main/resources/kerdy-submodule index 0de927e9c..b741a5d8d 160000 --- a/backend/emm-sale/src/main/resources/kerdy-submodule +++ b/backend/emm-sale/src/main/resources/kerdy-submodule @@ -1 +1 @@ -Subproject commit 0de927e9c8f427883b94f9d72a51f7879e0fca10 +Subproject commit b741a5d8d4bf78caa57b307d75ab7a7918f4e13e diff --git a/backend/emm-sale/src/test/java/com/emmsale/activity/application/ActivityCommandServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/admin/activity/application/ActivityCommandServiceTest.java similarity index 53% rename from backend/emm-sale/src/test/java/com/emmsale/activity/application/ActivityCommandServiceTest.java rename to backend/emm-sale/src/test/java/com/emmsale/admin/activity/application/ActivityCommandServiceTest.java index b71f3117b..7946259b2 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/activity/application/ActivityCommandServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/admin/activity/application/ActivityCommandServiceTest.java @@ -1,5 +1,7 @@ -package com.emmsale.activity.application; +package com.emmsale.admin.activity.application; +import static com.emmsale.member.MemberFixture.adminMember; +import static com.emmsale.member.MemberFixture.generalMember; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -9,6 +11,8 @@ import com.emmsale.activity.exception.ActivityException; import com.emmsale.activity.exception.ActivityExceptionType; import com.emmsale.helper.ServiceIntegrationTestHelper; +import com.emmsale.login.exception.LoginException; +import com.emmsale.login.exception.LoginExceptionType; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -26,35 +30,53 @@ void findActivity() { final String activityName = "DDD"; final ActivityAddRequest request = new ActivityAddRequest(ActivityType.CLUB, activityName); final ActivityResponse expected = new ActivityResponse( - 7L, - ActivityType.CLUB.getValue(), - activityName + 7L, + ActivityType.CLUB.getValue(), + activityName ); //when final ActivityResponse actual - = activityCommandService.addActivity(request); + = activityCommandService.addActivity(request, adminMember()); //then assertThat(actual) - .usingRecursiveComparison() - .isEqualTo(expected); + .usingRecursiveComparison() + .isEqualTo(expected); } @Test @DisplayName("이미 존재하는 활동을 추가하면 예외를 반환한다.") - void findActivity_duplicate_fail() { + void findActivity_fail_duplicate() { //given final String activityName = "DDD"; final ActivityAddRequest request = new ActivityAddRequest(ActivityType.CLUB, activityName); - activityCommandService.addActivity(request); + activityCommandService.addActivity(request, adminMember()); //when - final ThrowingCallable actual = () -> activityCommandService.addActivity(request); + final ThrowingCallable actual = () -> activityCommandService.addActivity(request, + adminMember()); //then assertThatThrownBy(actual) - .isInstanceOf(ActivityException.class) - .hasMessage(ActivityExceptionType.ALEADY_EXIST_ACTIVITY.errorMessage()); + .isInstanceOf(ActivityException.class) + .hasMessage(ActivityExceptionType.ALEADY_EXIST_ACTIVITY.errorMessage()); + } + + @Test + @DisplayName("관리자가 아닌 회원이 활동을 추가하면 예외를 반환한다.") + void findActivity_fail_authorization() { + //given + final String activityName = "DDD"; + final ActivityAddRequest request = new ActivityAddRequest(ActivityType.CLUB, activityName); + + //when + final ThrowingCallable actual = () -> activityCommandService.addActivity(request, + generalMember()); + + //then + assertThatThrownBy(actual) + .isInstanceOf(LoginException.class) + .hasMessage(LoginExceptionType.INVALID_ADMIN_ACCESS_TOKEN.errorMessage()); } } diff --git a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventCommandServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/admin/event/application/EventCommandServiceTest.java similarity index 82% rename from backend/emm-sale/src/test/java/com/emmsale/event/application/EventCommandServiceTest.java rename to backend/emm-sale/src/test/java/com/emmsale/admin/event/application/EventCommandServiceTest.java index d16ada5a2..fee2afedd 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventCommandServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/admin/event/application/EventCommandServiceTest.java @@ -1,8 +1,6 @@ -package com.emmsale.event.application; +package com.emmsale.admin.event.application; -import static com.emmsale.event.EventFixture.AI_아이디어_공모전; 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.웹_컨퍼런스; @@ -13,6 +11,9 @@ import static com.emmsale.image.ImageFixture.행사_이미지1; import static com.emmsale.image.ImageFixture.행사_이미지2; import static com.emmsale.image.ImageFixture.행사_이미지3; +import static com.emmsale.login.exception.LoginExceptionType.INVALID_ADMIN_ACCESS_TOKEN; +import static com.emmsale.member.MemberFixture.adminMember; +import static com.emmsale.member.MemberFixture.generalMember; import static com.emmsale.tag.TagFixture.AI; import static com.emmsale.tag.TagFixture.IOS; import static com.emmsale.tag.TagFixture.백엔드; @@ -39,11 +40,11 @@ import com.emmsale.event.exception.EventException; import com.emmsale.helper.ServiceIntegrationTestHelper; import com.emmsale.image.domain.repository.ImageRepository; +import com.emmsale.login.exception.LoginException; import com.emmsale.notification.domain.Notification; import com.emmsale.tag.application.dto.TagRequest; import com.emmsale.tag.domain.Tag; import com.emmsale.tag.domain.TagRepository; -import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; import java.util.stream.Collectors; @@ -58,35 +59,6 @@ class EventCommandServiceTest extends ServiceIntegrationTestHelper { - private static final EventResponse 인프콘_2023 = new EventResponse(null, "인프콘 2023", - null, null, null, null, null, "코엑스", List.of("백엔드"), - "이미지1", EventType.CONFERENCE.name(), List.of(), "인프런", PaymentType.PAID.getValue(), - EventMode.OFFLINE.getValue()); - private static final EventResponse 웹_컨퍼런스 = new EventResponse(null, "웹 컨퍼런스", null, - null, null, - null, null, "코엑스", List.of("백엔드"), "이미지1", EventType.CONFERENCE.name(), - List.of(), "주최기관", PaymentType.PAID.getValue(), EventMode.ONLINE.getValue()); - private static final EventResponse 안드로이드_컨퍼런스 = new EventResponse(null, "안드로이드 컨퍼런스", - null, null, null, null, null, "코엑스", List.of("백엔드"), - "이미지1", EventType.CONFERENCE.name(), List.of(), "주최기관", PaymentType.PAID.getValue(), - EventMode.ONLINE.getValue()); - private static final EventResponse AI_컨퍼런스 = new EventResponse(null, "AI 컨퍼런스", - null, null, null, null, null, "코엑스", List.of("백엔드"), - "이미지1", EventType.CONFERENCE.name(), List.of(), "주최기관", PaymentType.PAID.getValue(), - EventMode.ONLINE.getValue()); - private static final EventResponse 모바일_컨퍼런스 = new EventResponse(null, "모바일 컨퍼런스", - null, null, null, null, null, "코엑스", List.of("백엔드"), - "이미지1", EventType.CONFERENCE.name(), List.of(), "주최기관", PaymentType.PAID.getValue(), - EventMode.ONLINE.getValue()); - private static final EventResponse AI_아이디어_공모전 = new EventResponse(null, - "AI 아이디어 공모전", null, null, null, null, null, "코엑스", - List.of("백엔드"), "이미지1", EventType.CONFERENCE.name(), List.of(), "주최기관", - PaymentType.PAID.getValue(), EventMode.ONLINE.getValue()); - private static final EventResponse 구름톤 = new EventResponse(null, "구름톤", null, - null, null, null, null, "코엑스", List.of("백엔드"), - "이미지1", EventType.COMPETITION.name(), List.of(), "주최기관", PaymentType.PAID.getValue(), - EventMode.ONLINE.getValue()); - @Autowired private EventCommandService eventCommandService; @Autowired @@ -113,8 +85,6 @@ void init() { final Event 모바일_컨퍼런스 = eventRepository.save(모바일_컨퍼런스()); final Event 안드로이드_컨퍼런스 = eventRepository.save(안드로이드_컨퍼런스()); final Event 웹_컨퍼런스 = eventRepository.save(웹_컨퍼런스()); - final Event AI_아이디어_공모전 = eventRepository.save(AI_아이디어_공모전()); - final Event 구름톤 = eventRepository.save(구름톤()); eventTagRepository.saveAll(List.of( new EventTag(인프콘_2023, 백엔드), new EventTag(인프콘_2023, 프론트엔드), new EventTag(인프콘_2023, 안드로이드), @@ -157,11 +127,9 @@ class AddEvent { private final String eventName = "새로운 이름"; private final String eventLocation = "새로운 장소"; private final String eventInformationUrl = "https://새로운-상세-URL.com"; - private final String imageUrl = "https://image.com"; private final PaymentType paymentType = PaymentType.FREE_PAID; private final EventMode eventMode = EventMode.ON_OFFLINE; private final EventType type = EventType.CONFERENCE; - private final LocalDate now = LocalDate.now(); private final String organization = "행사기관"; @Test @@ -188,10 +156,17 @@ void addEventTest() { //when final EventResponse response = eventCommandService.addEvent(request, - mockMultipartFiles); + mockMultipartFiles, adminMember()); final Event savedEvent = eventRepository.findById(response.getId()).get(); //then + assertThat(response.getTags()) + .extracting("name") + .containsExactlyInAnyOrderElementsOf( + tagRequests.stream() + .map(TagRequest::getName) + .collect(Collectors.toList()) + ); assertAll( () -> assertEquals(eventName, savedEvent.getName()), () -> assertEquals(eventLocation, savedEvent.getLocation()), @@ -199,12 +174,6 @@ void addEventTest() { () -> assertEquals(beforeDateTime, savedEvent.getEventPeriod().getStartDate()), () -> assertEquals(afterDateTime, savedEvent.getEventPeriod().getEndDate()) ); - assertThat(response.getTags()) - .containsAll( - tagRequests.stream() - .map(TagRequest::getName) - .collect(Collectors.toList()) - ); } @Test @@ -234,7 +203,7 @@ void addEventWithStartDateTimeAfterBeforeDateTimeTest() { //when & then final EventException exception = assertThrowsExactly(EventException.class, - () -> eventCommandService.addEvent(request, mockMultipartFiles)); + () -> eventCommandService.addEvent(request, mockMultipartFiles, adminMember())); assertEquals(START_DATE_TIME_AFTER_END_DATE_TIME, exception.exceptionType()); } @@ -269,10 +238,39 @@ void addEventWithNotExistTagTest() { //when & then final EventException exception = assertThrowsExactly(EventException.class, - () -> eventCommandService.addEvent(request, mockMultipartFiles)); + () -> eventCommandService.addEvent(request, mockMultipartFiles, adminMember())); assertEquals(NOT_FOUND_TAG, exception.exceptionType()); } + + @Test + @DisplayName("관리자가 아닌 회원이 행사를 추가할 경우 LoginException이 발생한다.") + void addEvent_fail_authorization() { + //given + final EventDetailRequest request = new EventDetailRequest( + eventName, + eventLocation, + eventInformationUrl, + beforeDateTime, + afterDateTime, + beforeDateTime, + afterDateTime, + tagRequests, + type, + eventMode, + paymentType, + organization + ); + + doNothing().when(firebaseCloudMessageClient) + .sendMessageTo(any(Notification.class), anyLong()); + + //when & then + final LoginException exception = assertThrowsExactly(LoginException.class, + () -> eventCommandService.addEvent(request, mockMultipartFiles, generalMember())); + + assertEquals(INVALID_ADMIN_ACCESS_TOKEN, exception.exceptionType()); + } } @Nested @@ -287,7 +285,6 @@ class UpdateEvent { private final String newName = "새로운 이름"; private final String newLocation = "새로운 장소"; private final String newInformationUrl = "https://새로운-상세-URL.com"; - private final LocalDate now = LocalDate.now(); private final PaymentType paymentType = PaymentType.FREE_PAID; private final EventMode eventMode = EventMode.ON_OFFLINE; private final String organization = "행사기관"; @@ -319,10 +316,17 @@ void updateEventTest() { //when final EventResponse response = eventCommandService.updateEvent(eventId, updateRequest, - mockMultipartFiles); + mockMultipartFiles, adminMember()); final Event updatedEvent = eventRepository.findById(eventId).get(); //then + assertThat(response.getTags()) + .extracting("name") + .containsExactlyInAnyOrderElementsOf( + newTagRequests.stream() + .map(TagRequest::getName) + .collect(Collectors.toList()) + ); assertAll( () -> assertEquals(newName, updatedEvent.getName()), () -> assertEquals(newLocation, updatedEvent.getLocation()), @@ -330,12 +334,6 @@ void updateEventTest() { () -> assertEquals(newEndDateTime, updatedEvent.getEventPeriod().getEndDate()), () -> assertEquals(newInformationUrl, updatedEvent.getInformationUrl()) ); - assertThat(response.getTags()) - .containsAll( - newTagRequests.stream() - .map(TagRequest::getName) - .collect(Collectors.toList()) - ); } @Test @@ -362,7 +360,7 @@ void updateEventWithNotExistsEventTest() { //when & then final EventException exception = assertThrowsExactly(EventException.class, () -> eventCommandService.updateEvent(notExistsEventId, updateRequest, - mockMultipartFiles)); + mockMultipartFiles, adminMember())); assertEquals(NOT_FOUND_EVENT, exception.exceptionType()); } @@ -394,7 +392,8 @@ void updateEventWithStartDateTimeAfterBeforeDateTimeTest() { //when & then final EventException exception = assertThrowsExactly(EventException.class, - () -> eventCommandService.updateEvent(eventId, updateRequest, mockMultipartFiles)); + () -> eventCommandService.updateEvent(eventId, updateRequest, mockMultipartFiles, + adminMember())); assertEquals(START_DATE_TIME_AFTER_END_DATE_TIME, exception.exceptionType()); } @@ -427,10 +426,41 @@ void updateEventWithNotExistTagTest() { //when & then final EventException exception = assertThrowsExactly(EventException.class, - () -> eventCommandService.updateEvent(eventId, updateRequest, mockMultipartFiles)); + () -> eventCommandService.updateEvent(eventId, updateRequest, mockMultipartFiles, + adminMember())); assertEquals(NOT_FOUND_TAG, exception.exceptionType()); } + + @Test + @DisplayName("관리자가 아닌 회원이 행사를 수정할 경우 LoginException이 발생한다.") + void updateEvent_fail_authorization() { + //given + final EventDetailRequest updateRequest = new EventDetailRequest( + newName, + newLocation, + newInformationUrl, + beforeDateTime, + afterDateTime, + beforeDateTime, + afterDateTime, + newTagRequests, + EventType.CONFERENCE, + eventMode, + paymentType, + organization + ); + + final Event event = eventRepository.save(인프콘_2023()); + final Long eventId = event.getId(); + + //when & then + final LoginException exception = assertThrowsExactly(LoginException.class, + () -> eventCommandService.updateEvent(eventId, updateRequest, mockMultipartFiles, + generalMember())); + + assertEquals(INVALID_ADMIN_ACCESS_TOKEN, exception.exceptionType()); + } } @Nested @@ -444,7 +474,7 @@ void deleteEventTest() { final Long eventId = event.getId(); //when - eventCommandService.deleteEvent(eventId); + eventCommandService.deleteEvent(eventId, adminMember()); //then assertFalse(eventRepository.findById(eventId).isPresent()); @@ -458,10 +488,24 @@ void deleteEventWithNotExistsEventTest() { //when & then final EventException exception = assertThrowsExactly(EventException.class, - () -> eventCommandService.deleteEvent(notExistsEventId)); + () -> eventCommandService.deleteEvent(notExistsEventId, adminMember())); assertEquals(NOT_FOUND_EVENT, exception.exceptionType()); } + + @Test + @DisplayName("관지자가 아닌 회원이 행사를 삭제할 경우 LoginException이 발생한다.") + void deleteEvent_fail_authorization() { + //given + final Event event = eventRepository.save(인프콘_2023()); + final Long eventId = event.getId(); + + //when & then + final LoginException exception = assertThrowsExactly(LoginException.class, + () -> eventCommandService.deleteEvent(eventId, generalMember())); + + assertEquals(INVALID_ADMIN_ACCESS_TOKEN, exception.exceptionType()); + } } -} \ No newline at end of file +} diff --git a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceEventIntegrationTestQuery.java b/backend/emm-sale/src/test/java/com/emmsale/admin/event/application/EventServiceEventIntegrationTestQuery.java similarity index 95% rename from backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceEventIntegrationTestQuery.java rename to backend/emm-sale/src/test/java/com/emmsale/admin/event/application/EventServiceEventIntegrationTestQuery.java index be4533b48..d88606ec0 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceEventIntegrationTestQuery.java +++ b/backend/emm-sale/src/test/java/com/emmsale/admin/event/application/EventServiceEventIntegrationTestQuery.java @@ -1,5 +1,6 @@ -package com.emmsale.event.application; +package com.emmsale.admin.event.application; +import static com.emmsale.member.MemberFixture.adminMember; import static com.emmsale.tag.TagFixture.IOS; import static com.emmsale.tag.TagFixture.백엔드; import static com.emmsale.tag.TagFixture.안드로이드; @@ -77,7 +78,7 @@ void test_publish_event() throws Exception { ); //when - eventCommandService.addEvent(eventDetailRequest, null); + eventCommandService.addEvent(eventDetailRequest, null, adminMember()); //then verify(firebaseCloudMessageClient, times(2)) @@ -121,7 +122,7 @@ void test_publish_event_no_notification_event_has_no_interest_tag() throws Excep ); //when - eventCommandService.addEvent(eventDetailRequest, null); + eventCommandService.addEvent(eventDetailRequest, null, adminMember()); //then verify(firebaseCloudMessageClient, times(0)) @@ -155,7 +156,7 @@ void test_publish_event_no_notification_member_has_no_interest_tag() throws Exce ); //when - eventCommandService.addEvent(eventDetailRequest, null); + eventCommandService.addEvent(eventDetailRequest, null, adminMember()); //then verify(firebaseCloudMessageClient, times(0)) diff --git a/backend/emm-sale/src/test/java/com/emmsale/admin/login/application/AdminLoginServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/admin/login/application/AdminLoginServiceTest.java new file mode 100644 index 000000000..c28049f9c --- /dev/null +++ b/backend/emm-sale/src/test/java/com/emmsale/admin/login/application/AdminLoginServiceTest.java @@ -0,0 +1,97 @@ +package com.emmsale.admin.login.application; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.emmsale.admin.login.application.dto.AdminLoginRequest; +import com.emmsale.admin.login.application.dto.AdminTokenResponse; +import com.emmsale.helper.ServiceIntegrationTestHelper; +import com.emmsale.login.exception.LoginException; +import com.emmsale.login.exception.LoginExceptionType; +import com.emmsale.login.utils.JwtTokenProvider; +import org.assertj.core.api.Assertions; +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class AdminLoginServiceTest extends ServiceIntegrationTestHelper { + + @Autowired + private JwtTokenProvider jwtTokenProvider; + @Autowired + private AdminLoginService adminLoginService; + @Value("${data.admin_login.id}") + private String adminId; + @Value("${data.admin_login.password}") + private String adminPassword; + @Value("${data.admin_login.member_id}") + private Long adminMemberId; + + @Test + @DisplayName("관리자 아이디, 패스워드로 사용자를 조회하여 토큰을 생성한다.") + void createAdminToken_success() { + // given + final Long memberId = adminMemberId; + final AdminLoginRequest request = new AdminLoginRequest(adminId, adminPassword); + final String expectAccessToken = jwtTokenProvider.createToken(String.valueOf(memberId)); + + // when + final AdminTokenResponse actualToken = adminLoginService.createAdminToken(request); + + // then + assertEquals(expectAccessToken, actualToken.getAccessToken()); + } + + @Test + @DisplayName("관리자 정보 요청이 null이면 예외를 반환한다.") + void createAdminToken_fail_not_found_request() { + // given + final LoginExceptionType expectExceptionType = LoginExceptionType.NOT_FOUND_ADMIN_LOGIN_INFORMATION; + + // when + final ThrowingCallable actual = () -> adminLoginService.createAdminToken(null); + + // then + Assertions.assertThatThrownBy(actual) + .isInstanceOf(LoginException.class) + .hasMessage(expectExceptionType.errorMessage()); + } + + @Test + @DisplayName("관리자 아이디가 올바르지 않으면 예외를 반환한다.") + void createAdminToken_fail_invalid_id() { + // given + final AdminLoginRequest request = new AdminLoginRequest("invalid", adminPassword); + final LoginExceptionType expectExceptionType = LoginExceptionType.INVALID_ADMIN_LOGIN_INFORMATION; + + // when + final ThrowingCallable actual = () -> adminLoginService.createAdminToken( + request); + + // then + Assertions.assertThatThrownBy(actual) + .isInstanceOf(LoginException.class) + .hasMessage(expectExceptionType.errorMessage()); + } + + @Test + @DisplayName("관리자 패스워드가 올바르지 않으면 예외를 반환한다.") + void createAdminToken_fail_invalid_password() { + // given + final AdminLoginRequest request = new AdminLoginRequest(adminId, "invalid"); + final LoginExceptionType expectExceptionType = LoginExceptionType.INVALID_ADMIN_LOGIN_INFORMATION; + + // when + final ThrowingCallable actual = () -> adminLoginService.createAdminToken( + request); + + // then + Assertions.assertThatThrownBy(actual) + .isInstanceOf(LoginException.class) + .hasMessage(expectExceptionType.errorMessage()); + } + +} diff --git a/backend/emm-sale/src/test/java/com/emmsale/report/application/ReportQueryServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/admin/report/application/ReportQueryServiceTest.java similarity index 77% rename from backend/emm-sale/src/test/java/com/emmsale/report/application/ReportQueryServiceTest.java rename to backend/emm-sale/src/test/java/com/emmsale/admin/report/application/ReportQueryServiceTest.java index f8312ebac..37af75f8f 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/report/application/ReportQueryServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/admin/report/application/ReportQueryServiceTest.java @@ -1,7 +1,10 @@ -package com.emmsale.report.application; +package com.emmsale.admin.report.application; import static com.emmsale.event.EventFixture.eventFixture; +import static com.emmsale.member.MemberFixture.adminMember; +import static com.emmsale.member.MemberFixture.generalMember; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.emmsale.comment.domain.Comment; import com.emmsale.comment.domain.CommentRepository; @@ -10,14 +13,18 @@ import com.emmsale.feed.domain.Feed; import com.emmsale.feed.domain.repository.FeedRepository; import com.emmsale.helper.ServiceIntegrationTestHelper; +import com.emmsale.login.exception.LoginException; +import com.emmsale.login.exception.LoginExceptionType; import com.emmsale.member.domain.Member; import com.emmsale.member.domain.MemberRepository; +import com.emmsale.report.application.ReportCommandService; import com.emmsale.report.application.dto.ReportCreateRequest; import com.emmsale.report.application.dto.ReportCreateResponse; import com.emmsale.report.application.dto.ReportFindResponse; import com.emmsale.report.domain.ReportType; import java.util.List; import org.assertj.core.api.Assertions; +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -68,13 +75,24 @@ void findReports() { report.getType(), report.getContentId(), report.getCreatedAt())); // when - final List actual = reportQueryService.findReports(); + final List actual = reportQueryService.findReports(adminMember()); // then Assertions.assertThat(actual) .usingRecursiveComparison() .ignoringFields("createdAt") .isEqualTo(expected); + } + + @Test + @DisplayName("관리자가 아닌 회원이 신고 목록을 조회하면 예외를 반환한다.") + void findReports_fail_authorization() { + // given, when + final ThrowingCallable actual = () -> reportQueryService.findReports(generalMember()); + // then + assertThatThrownBy(actual) + .isInstanceOf(LoginException.class) + .hasMessage(LoginExceptionType.INVALID_ADMIN_ACCESS_TOKEN.errorMessage()); } } diff --git a/backend/emm-sale/src/test/java/com/emmsale/tag/application/TagCommandServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/admin/tag/application/TagCommandServiceTest.java similarity index 61% rename from backend/emm-sale/src/test/java/com/emmsale/tag/application/TagCommandServiceTest.java rename to backend/emm-sale/src/test/java/com/emmsale/admin/tag/application/TagCommandServiceTest.java index 0435c2830..bcc2d045d 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/tag/application/TagCommandServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/admin/tag/application/TagCommandServiceTest.java @@ -1,9 +1,13 @@ -package com.emmsale.tag.application; +package com.emmsale.admin.tag.application; +import static com.emmsale.member.MemberFixture.adminMember; +import static com.emmsale.member.MemberFixture.generalMember; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import com.emmsale.helper.ServiceIntegrationTestHelper; +import com.emmsale.login.exception.LoginException; +import com.emmsale.login.exception.LoginExceptionType; import com.emmsale.tag.application.dto.TagRequest; import com.emmsale.tag.application.dto.TagResponse; import com.emmsale.tag.exception.TagException; @@ -27,7 +31,7 @@ void findAll() { final TagResponse expected = new TagResponse(1L, tagName); //when - final TagResponse actual = commandService.addTag(request); + final TagResponse actual = commandService.addTag(request, adminMember()); //then assertThat(actual) @@ -37,14 +41,14 @@ void findAll() { @Test @DisplayName("이미 존재하는 태그를 추가하면 예외를 반환한다.") - void addTag_duplicate_fail() { + void addTag_fail_duplicate() { //given final String tagName = "프론트엔드"; final TagRequest request = new TagRequest(tagName); - commandService.addTag(request); + commandService.addTag(request, adminMember()); //when - final ThrowingCallable actual = () -> commandService.addTag(request); + final ThrowingCallable actual = () -> commandService.addTag(request, adminMember()); //then assertThatThrownBy(actual) @@ -52,5 +56,19 @@ void addTag_duplicate_fail() { .hasMessage(TagExceptionType.ALEADY_EXIST_TAG.errorMessage()); } + @Test + @DisplayName("관리자가 아닌 회원이 태그를 추가하면 예외를 반환한다.") + void addTag_fail_authorization() { + //given + final String tagName = "프론트엔드"; + final TagRequest request = new TagRequest(tagName); + //when + final ThrowingCallable actual = () -> commandService.addTag(request, generalMember()); + + //then + assertThatThrownBy(actual) + .isInstanceOf(LoginException.class) + .hasMessage(LoginExceptionType.INVALID_ADMIN_ACCESS_TOKEN.errorMessage()); + } } diff --git a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventQueryServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventQueryServiceTest.java index 121cf9ffe..dd12b45b5 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventQueryServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventQueryServiceTest.java @@ -39,6 +39,7 @@ import com.emmsale.image.domain.Image; import com.emmsale.image.domain.ImageType; import com.emmsale.image.domain.repository.ImageRepository; +import com.emmsale.tag.application.dto.TagResponse; import com.emmsale.tag.domain.Tag; import com.emmsale.tag.domain.TagRepository; import com.emmsale.tag.exception.TagException; @@ -58,32 +59,33 @@ class EventQueryServiceTest extends ServiceIntegrationTestHelper { + private static final TagResponse 백엔드 = new TagResponse(1L, "백엔드"); private static final EventResponse 인프콘_2023 = new EventResponse(null, "인프콘 2023", - null, null, null, null, null, "코엑스", List.of("백엔드"), + null, null, null, null, null, "코엑스", List.of(백엔드), "이미지1", EventType.CONFERENCE.name(), List.of(), "인프런", PaymentType.PAID.getValue(), EventMode.OFFLINE.getValue()); private static final EventResponse 웹_컨퍼런스 = new EventResponse(null, "웹 컨퍼런스", null, null, null, - null, null, "코엑스", List.of("백엔드"), "이미지1", EventType.CONFERENCE.name(), + null, null, "코엑스", List.of(백엔드), "이미지1", EventType.CONFERENCE.name(), List.of(), "주최기관", PaymentType.PAID.getValue(), EventMode.ONLINE.getValue()); private static final EventResponse 안드로이드_컨퍼런스 = new EventResponse(null, "안드로이드 컨퍼런스", - null, null, null, null, null, "코엑스", List.of("백엔드"), + null, null, null, null, null, "코엑스", List.of(백엔드), "이미지1", EventType.CONFERENCE.name(), List.of(), "주최기관", PaymentType.PAID.getValue(), EventMode.ONLINE.getValue()); private static final EventResponse AI_컨퍼런스 = new EventResponse(null, "AI 컨퍼런스", - null, null, null, null, null, "코엑스", List.of("백엔드"), + null, null, null, null, null, "코엑스", List.of(백엔드), "이미지1", EventType.CONFERENCE.name(), List.of(), "주최기관", PaymentType.PAID.getValue(), EventMode.ONLINE.getValue()); private static final EventResponse 모바일_컨퍼런스 = new EventResponse(null, "모바일 컨퍼런스", - null, null, null, null, null, "코엑스", List.of("백엔드"), + null, null, null, null, null, "코엑스", List.of(백엔드), "이미지1", EventType.CONFERENCE.name(), List.of(), "주최기관", PaymentType.PAID.getValue(), EventMode.ONLINE.getValue()); private static final EventResponse AI_아이디어_공모전 = new EventResponse(null, "AI 아이디어 공모전", null, null, null, null, null, "코엑스", - List.of("백엔드"), "이미지1", EventType.CONFERENCE.name(), List.of(), "주최기관", + List.of(백엔드), "이미지1", EventType.CONFERENCE.name(), List.of(), "주최기관", PaymentType.PAID.getValue(), EventMode.ONLINE.getValue()); private static final EventResponse 구름톤 = new EventResponse(null, "구름톤", null, - null, null, null, null, "코엑스", List.of("백엔드"), + null, null, null, null, "코엑스", List.of(백엔드), "이미지1", EventType.COMPETITION.name(), List.of(), "주최기관", PaymentType.PAID.getValue(), EventMode.ONLINE.getValue()); @@ -468,7 +470,7 @@ void findEvents_tags_filter() { final List actualEvents = eventQueryService.findEvents( EventType.CONFERENCE, TODAY, - null, null, List.of("안드로이드", "백엔드"), null, null); + null, null, List.of("안드로이드", 백엔드.getName()), null, null); // then assertThat(actualEvents) @@ -539,7 +541,8 @@ void findEvents_period_tags_filter() { final List actualEvents = eventQueryService.findEvents( EventType.CONFERENCE, TODAY, - "2023-09-01", "2023-09-30", List.of("안드로이드", "백엔드"), List.of(EventStatus.UPCOMING), null); + "2023-09-01", "2023-09-30", List.of("안드로이드", 백엔드.getName()) + , List.of(EventStatus.UPCOMING), null); // then assertThat(actualEvents) diff --git a/backend/emm-sale/src/test/java/com/emmsale/event/application/RecruitmentPostQueryServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/event/application/RecruitmentPostQueryServiceTest.java index 82cd71375..300c42d10 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/event/application/RecruitmentPostQueryServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/event/application/RecruitmentPostQueryServiceTest.java @@ -67,9 +67,9 @@ void findRecruitmentPosts() { final List expected = List.of( new RecruitmentPostQueryResponse(멤버1_참가글_ID, requestMember1.getContent(), LocalDate.now(), - MemberReferenceResponse.from(사용자1), 인프콘.getId()), + MemberReferenceResponse.from(사용자1), 인프콘.getId(), 인프콘.getName()), new RecruitmentPostQueryResponse(멤버2_참가글_ID, requestMember2.getContent(), LocalDate.now(), - MemberReferenceResponse.from(사용자2), 인프콘.getId()) + MemberReferenceResponse.from(사용자2), 인프콘.getId(), 인프콘.getName()) ); //when @@ -93,7 +93,7 @@ void findRecruitmentPost() { final RecruitmentPostQueryResponse expected = new RecruitmentPostQueryResponse(멤버1_참가글_ID, requestMember1.getContent(), LocalDate.now(), MemberReferenceResponse.from(사용자1), - 인프콘.getId()); + 인프콘.getId(), 인프콘.getName()); //when final RecruitmentPostQueryResponse actual = postQueryService.findRecruitmentPost( diff --git a/backend/emm-sale/src/test/java/com/emmsale/member/MemberFixture.java b/backend/emm-sale/src/test/java/com/emmsale/member/MemberFixture.java index b6520bb38..7e969a425 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/member/MemberFixture.java +++ b/backend/emm-sale/src/test/java/com/emmsale/member/MemberFixture.java @@ -5,8 +5,7 @@ public class MemberFixture { public static Member memberFixture() { - final Member member = new Member( - 1234L, + final Member member = new Member(1234L, "https://avatars.githubusercontent.com/0/4", "아마란스" ); @@ -14,6 +13,29 @@ public static Member memberFixture() { return member; } + public static Member generalMember() { + final Member member = new Member(1L, + 1234L, + "https://avatars.githubusercontent.com/0/4", + "아마란스", + "amaran-th" + ); + member.updateName("우르"); + return member; + } + + public static Member adminMember() { + final long adminMemberId = 3L; + final Member member = new Member(adminMemberId, + 1234L, + "https://avatars.githubusercontent.com/0/4", + "아마란스", + "amaran-th" + ); + member.updateName("관리자"); + return member; + } + public static Member create( final Long githubId, final String githubUsername, diff --git a/backend/emm-sale/src/test/java/com/emmsale/scrap/application/ScrapQueryServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/scrap/application/ScrapQueryServiceTest.java index 0112c4709..752fe42e3 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/scrap/application/ScrapQueryServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/scrap/application/ScrapQueryServiceTest.java @@ -17,7 +17,7 @@ import com.emmsale.member.domain.MemberRepository; import com.emmsale.scrap.domain.Scrap; import com.emmsale.scrap.domain.ScrapRepository; -import com.emmsale.tag.domain.Tag; +import com.emmsale.tag.application.dto.TagResponse; import java.util.List; import java.util.stream.Collectors; import org.junit.jupiter.api.DisplayName; @@ -63,7 +63,7 @@ void findAllScrapsTest() { event1.getTags() .stream() .map(EventTag::getTag) - .map(Tag::getName) + .map(TagResponse::from) .collect(Collectors.toList()), 행사_이미지1(event1.getId()).getName(), event1.getType().name(), List.of(행사_이미지2(event1.getId()).getName(), 행사_이미지3(event1.getId()).getName(), @@ -77,7 +77,7 @@ void findAllScrapsTest() { event2.getTags() .stream() .map(EventTag::getTag) - .map(Tag::getName) + .map(TagResponse::from) .collect(Collectors.toList()), null, event2.getType().name(), List.of(),