Skip to content

Commit

Permalink
feat: 프로필 이미지 수정 API 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
TaeyeonRoyce committed Jan 28, 2024
1 parent ddcf4cf commit fee3bf3
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/main/java/com/baro/member/presentation/MemberController.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.baro.member.application.MemberService;
import com.baro.member.application.dto.GetMemberProfileResult;
import com.baro.member.application.dto.UpdateMemberProfileCommand;
import com.baro.member.application.dto.UpdateProfileImageCommand;
import com.baro.member.presentation.dto.UpdateMemberProfileRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
Expand All @@ -13,6 +14,7 @@
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@RequiredArgsConstructor
@RequestMapping("/members")
Expand Down Expand Up @@ -47,4 +49,14 @@ public ResponseEntity<Void> deleteProfileImage(
memberService.deleteProfileImage(authMember.id());
return ResponseEntity.noContent().build();
}

@PatchMapping("/image")
public ResponseEntity<Void> updateProfileImage(
AuthMember authMember,
@RequestBody MultipartFile profileImage
) {
UpdateProfileImageCommand command = new UpdateProfileImageCommand(authMember.id(), profileImage);
memberService.updateProfileImage(command);
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static com.baro.common.RestApiTest.requestSpec;
import static com.baro.common.acceptance.AcceptanceSteps.예외_응답;
import static com.epages.restdocs.apispec.RestAssuredRestDocumentationWrapper.document;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
Expand All @@ -13,9 +14,14 @@
import com.baro.auth.domain.Token;
import com.baro.member.presentation.dto.UpdateMemberProfileRequest;
import io.restassured.RestAssured;
import io.restassured.builder.MultiPartSpecBuilder;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
import io.restassured.specification.MultiPartSpecification;
import java.io.IOException;
import org.springframework.http.HttpHeaders;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;

public class MemberAcceptanceSteps {

Expand All @@ -24,6 +30,9 @@ public class MemberAcceptanceSteps {
"닉네임".repeat(11));
public static final UpdateMemberProfileRequest 빈_닉네임_프로필_수정_바디 = new UpdateMemberProfileRequest("바로", "");

public static final MultipartFile 프로필_이미지 = new MockMultipartFile("image", "image", "multipart/form-data",
"image".getBytes());

public static ExtractableResponse<Response> 내_프로필_조회_요청(Token 토큰) {
return RestAssured.given(requestSpec).log().all()
.filter(document(DEFAULT_REST_DOCS_PATH,
Expand Down Expand Up @@ -107,4 +116,33 @@ public class MemberAcceptanceSteps {
.then().log().all()
.extract();
}

public static ExtractableResponse<Response> 프로필_이미지_수정_요청(Token 토큰, MultipartFile 이미지) {
var multiPart = 멀티_파트_파일_생성(이미지);

return RestAssured.given(requestSpec).log().all()
.filter(document(DEFAULT_REST_DOCS_PATH,
requestHeaders(
headerWithName(HttpHeaders.AUTHORIZATION).description("인증 토큰")
)
))
.contentType("multipart/form-data")
.multiPart(multiPart)
.header(HttpHeaders.AUTHORIZATION, "Bearer " + 토큰.accessToken())
.when().patch("/members/image")
.then().log().all()
.extract();
}

private static MultiPartSpecification 멀티_파트_파일_생성(MultipartFile 이미지) {
try {
return new MultiPartSpecBuilder(이미지.getBytes())
.controlName("profileImage")
.fileName(이미지.getName())
.charset(UTF_8)
.build();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
27 changes: 27 additions & 0 deletions src/test/java/com/baro/member/presentation/MemberApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,23 @@
import static com.baro.common.acceptance.member.MemberAcceptanceSteps.잘못된_내_프로필_수정_요청;
import static com.baro.common.acceptance.member.MemberAcceptanceSteps.잘못된_프로필_조회_요청;
import static com.baro.common.acceptance.member.MemberAcceptanceSteps.프로필_수정_바디;
import static com.baro.common.acceptance.member.MemberAcceptanceSteps.프로필_이미지;
import static com.baro.common.acceptance.member.MemberAcceptanceSteps.프로필_이미지_삭제_요청;
import static com.baro.common.acceptance.member.MemberAcceptanceSteps.프로필_이미지_수정_요청;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;

import com.baro.auth.application.TokenTranslator;
import com.baro.auth.domain.Token;
import com.baro.common.RestApiTest;
import com.baro.common.image.ImageStorageClient;
import com.baro.common.image.dto.ImageUploadResult;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.web.multipart.MultipartFile;

@DisplayNameGeneration(ReplaceUnderscores.class)
@SuppressWarnings("NonAsciiCharacters")
Expand All @@ -31,6 +38,9 @@ public class MemberApiTest extends RestApiTest {
@SpyBean
private TokenTranslator tokenTranslator;

@MockBean
private ImageStorageClient imageStorageClient;

@Test
void 내_프로필_정보를_조회_한다() {
// given
Expand Down Expand Up @@ -136,4 +146,21 @@ public class MemberApiTest extends RestApiTest {
// then
응답값을_검증한다(응답, 잘못된_요청);
}

@Test
void 프로필_이미지를_수정한다() {
// given
var 토큰 = 로그인(태연());
이미지를_등록한다(프로필_이미지);

// when
var 응답 = 프로필_이미지_수정_요청(토큰, 프로필_이미지);

// then
응답값을_검증한다(응답, 응답값_없음);
}

private void 이미지를_등록한다(MultipartFile 이미지) {
given(imageStorageClient.upload(any())).willReturn(new ImageUploadResult(이미지.getOriginalFilename()));
}
}

0 comments on commit fee3bf3

Please sign in to comment.