Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

\backend-main -> main 동기화 #910

Merged
merged 25 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8a95686
refactor: admin 패키지 분리
Nov 18, 2023
d44fb36
feat: 관리자 로그인 구현
Nov 19, 2023
dc9acef
feat: 관리자 권한 검증 구현
Nov 20, 2023
84b5493
feat: dev application.yml 변경사항 업데이트
Nov 24, 2023
2d56921
feat: prod application.yml 변경사항 업데이트
Nov 27, 2023
98c5c3d
feat: 파일 마지막 줄에 빈 줄 추가
Nov 27, 2023
42a2a52
Merge branch 'backend-main' of https://github.com/woowacourse-teams/2…
Nov 27, 2023
9d2a118
refactor: dto 필드에 private 접근 제어자 추가
Nov 27, 2023
2f2de41
refactor: @Mockbean 필드를 ServiceIntegrationTestHelper로 이동
Nov 27, 2023
27bb2aa
refactor: 관리자 토큰 검증 실패 시 발생하는 예외 유형을 INVALID_ADMIN_ACCESS_TOKEN으로 변경
Nov 28, 2023
5160b41
refactor: JwtTokenProvider를 Mocking하지 않도록 수정
Nov 28, 2023
342c752
feat: 서브모듈 업데이트
hong-sile Nov 28, 2023
2968c47
merge: Feature/#156 관리자 권한 설정
amaran-th Nov 28, 2023
b07ab31
fix: 로그인관련 에러코드를 400이 아닌 401로 변경
hong-sile Dec 1, 2023
e9fe5b9
merge: 로그인관련 에러코드 변경
hong-sile Dec 1, 2023
c915b06
feat: Event 반환값 변경
hong-sile Jan 12, 2024
972a8fa
test: scrapAPITest 코드 수정
hong-sile Jan 12, 2024
60e8b72
test: service에 있는 테스트 코드들 수정
hong-sile Jan 12, 2024
f298073
test: EventCommandServiceTest 오류 수정
hong-sile Jan 12, 2024
e14f942
merge: 행사 목록 조회 API 반환값 변경
hong-sile Jan 12, 2024
56b07c1
test: 함께해요 요청 반환값 API Test 변경
hong-sile Feb 6, 2024
289740c
feat: RecruitmentPostQueryResponse 반환값에 eventName 추가
hong-sile Feb 6, 2024
92d260b
refactor: findAllByMember에서 event이름도 가져오므로 event fetch join
hong-sile Feb 6, 2024
7b2a61b
test: 테스트 수정
hong-sile Feb 6, 2024
4c7572a
merge: 함꼐해요_요청_반환값_변경
hong-sile Feb 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions backend/emm-sale/src/documentTest/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -27,64 +29,67 @@
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
@DisplayName("Activity를 전제 조회할 수 있으면 200 OK를 반환한다.")
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<ActivityResponse> 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
@DisplayName("새로운 활동을 생성할 수 있다.")
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));
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -110,11 +121,14 @@ class EventApiTest extends MockMvcTestHelper {
void findEvent() throws Exception {
//given
final Long eventId = 1L;
final List<TagResponse> 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"), "인프런", "유료", "온라인");

Expand Down Expand Up @@ -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(),
Expand All @@ -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(),
Expand Down Expand Up @@ -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);
Expand All @@ -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);

Expand All @@ -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())
Expand Down Expand Up @@ -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);
Expand All @@ -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())
Expand Down Expand Up @@ -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());
}
Expand Down Expand Up @@ -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());
}
Expand Down Expand Up @@ -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());
}
Expand Down Expand Up @@ -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());
}
Expand Down Expand Up @@ -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());
}
Expand Down
Loading
Loading