Skip to content

Commit

Permalink
feat: #400 사용자 정보 수정 시 이름만 수정한다면 이미지는 null 전달되는 요청 처리 (#401)
Browse files Browse the repository at this point in the history
* refactor: 사용자 정보 수정 시 이미지만 수정될 수 있도록 수정

* feat: MultipartFile의 null 처리 추가

* refactor: 수정되지 못한 클래스 명 수정

* test: 잘못된 검증 로직 수정

* refactor: 필드명 수정
  • Loading branch information
JJ503 authored Sep 18, 2023
1 parent c63ab2b commit 7790bc9
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.ddang.ddang.image.domain.AuctionImage;
import com.ddang.ddang.image.domain.ProfileImage;
import com.ddang.ddang.image.infrastructure.persistence.JpaAuctionImageRepository;
import com.ddang.ddang.image.infrastructure.persistence.JpaImageRepository;
import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
Expand All @@ -22,7 +22,7 @@ public class ImageService {
@Value("${image.store.dir}")
private String imageStoreDir;

private final JpaImageRepository imageRepository;
private final JpaProfileImageRepository imageRepository;
private final JpaAuctionImageRepository auctionImageRepository;

public Resource readProfileImage(final Long id) throws MalformedURLException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
import com.ddang.ddang.image.domain.ProfileImage;
import org.springframework.data.jpa.repository.JpaRepository;

public interface JpaImageRepository extends JpaRepository<ProfileImage, Long> {
public interface JpaProfileImageRepository extends JpaRepository<ProfileImage, Long> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,19 @@ public ReadUserDto readById(final Long userId) {
public ReadUserDto updateById(final Long userId, final UpdateUserDto userDto) {
final User user = userRepository.findByIdAndDeletedIsFalse(userId)
.orElseThrow(() -> new UserNotFoundException("사용자 정보를 사용할 수 없습니다."));
final StoreImageDto storeImageDto = imageProcessor.storeImageFile(userDto.profileImage());

user.update(userDto.name(), storeImageDto.toProfileImageEntity());
updateUserByReqeust(userDto, user);

return ReadUserDto.from(user);
}

private void updateUserByReqeust(final UpdateUserDto userDto, final User user) {
if (userDto.profileImage() != null) {
final StoreImageDto storeImageDto = imageProcessor.storeImageFile(userDto.profileImage());
user.updateProfileImage(storeImageDto.toProfileImageEntity());
}
if (userDto.name() != null) {
user.updateName(userDto.name());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,12 @@ private User(
this.oauthId = oauthId;
}

public void update(final String name, final ProfileImage profileProfileImage) {
public void updateName(final String name) {
this.name = name;
this.profileImage = profileProfileImage;
}

public void updateProfileImage(final ProfileImage profileImage) {
this.profileImage = profileImage;
}

public void withdrawal() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@ public ResponseEntity<ReadUserResponse> readById(@AuthenticateUser final Authent
@PatchMapping
public ResponseEntity<ReadUserResponse> updateById(
@AuthenticateUser final AuthenticationUserInfo userInfo,
@RequestPart @Valid final UpdateUserRequest request,
@RequestPart final MultipartFile profileImage
@RequestPart(required = false) @Valid final UpdateUserRequest request,
@RequestPart(required = false) final MultipartFile profileImage
) {
final ReadUserDto readUserDto = userService.updateById(
userInfo.userId(),
UpdateUserDto.of(request, profileImage)
);
UpdateUserDto updateUserDto = null;
if (request != null) {
updateUserDto = UpdateUserDto.of(request, profileImage);
}

final ReadUserDto readUserDto = userService.updateById(userInfo.userId(), updateUserDto);
final ReadUserResponse response = ReadUserResponse.from(readUserDto);

return ResponseEntity.ok(response);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import com.ddang.ddang.image.domain.AuctionImage;
import com.ddang.ddang.image.domain.ProfileImage;
import com.ddang.ddang.image.infrastructure.persistence.JpaAuctionImageRepository;
import com.ddang.ddang.image.infrastructure.persistence.JpaImageRepository;
import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Test;
Expand All @@ -27,7 +27,7 @@ class ProfileImageServiceTest {
ImageService imageService;

@Autowired
JpaImageRepository imageRepository;
JpaProfileImageRepository imageRepository;

@Autowired
JpaAuctionImageRepository auctionImageRepository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
@SuppressWarnings("NonAsciiCharacters")
@Import(QuerydslConfiguration.class)
class JpaAuctionProfileImageRepositoryTest {
class JpaAuctionImageRepositoryTest {

@PersistenceContext
EntityManager em;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class JpaProfileImageRepositoryTest {
EntityManager em;

@Autowired
JpaImageRepository imageRepository;
JpaProfileImageRepository imageRepository;

@Test
void 지정한_아이디에_해당하는_이미지를_조회한다() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,68 @@ class UserServiceTest {
});
}

@Test
void 사용자_정보를_수정시_이름만_수정한다() {
// given
final User user = User.builder()
.name("사용자")
.profileImage(new ProfileImage("upload.png", "store.png"))
.reliability(4.7d)
.oauthId("12345")
.build();

userRepository.save(user);

final UpdateUserDto updateUserDto = new UpdateUserDto("updateName", null);

// when
userService.updateById(user.getId(), updateUserDto);

// then
SoftAssertions.assertSoftly(softAssertions -> {
softAssertions.assertThat(user.getName()).isEqualTo("updateName");
softAssertions.assertThat(user.getProfileImage().getImage().getStoreName()).isEqualTo("store.png");
softAssertions.assertThat(user.getReliability()).isEqualTo(4.7d);
softAssertions.assertThat(user.getOauthId()).isEqualTo("12345");
});
}

@Test
void 사용자_정보를_수정시_이미지만_수정한다() {
// given
final User user = User.builder()
.name("사용자")
.profileImage(new ProfileImage("upload.png", "store.png"))
.reliability(4.7d)
.oauthId("12345")
.build();

userRepository.save(user);

final StoreImageDto storeImageDto = new StoreImageDto("newUpload.png", "newStore.png");
given(imageProcessor.storeImageFile(any())).willReturn(storeImageDto);

final MockMultipartFile updateImage = new MockMultipartFile(
"updateImage.png",
"updateImage.png",
MediaType.IMAGE_PNG.toString(),
new byte[]{1}
);

final UpdateUserDto updateUserDto = new UpdateUserDto(null, updateImage);

// when
userService.updateById(user.getId(), updateUserDto);

// then
SoftAssertions.assertSoftly(softAssertions -> {
softAssertions.assertThat(user.getName()).isEqualTo("사용자");
softAssertions.assertThat(user.getProfileImage().getImage().getStoreName()).isEqualTo("newStore.png");
softAssertions.assertThat(user.getReliability()).isEqualTo(4.7d);
softAssertions.assertThat(user.getOauthId()).isEqualTo("12345");
});
}

@Test
void 사용자_정보_수정시_존재하지_않는_사용자라면_예외가_발생한다() {
// given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
class UserTest {

@Test
void 회원_정보를_수정한다() {
void 회원_정보의_이름을_수정한다() {
// given
final User user = User.builder()
.name("kakao12345")
Expand All @@ -22,12 +22,32 @@ class UserTest {
.build();

// when
user.update("newName", new ProfileImage("newUpload.png", "newStore.png"));
user.updateName("newName");

// then
SoftAssertions.assertSoftly(softAssertions -> {
softAssertions.assertThat(user.getName()).isEqualTo("newName");
softAssertions.assertThat(user.getProfileImage()).isEqualTo(new ProfileImage("newUpload.png", "newStore.png"));
softAssertions.assertThat(user.getProfileImage()).isEqualTo(new ProfileImage("upload.png", "store.png"));
softAssertions.assertThat(user.getReliability()).isEqualTo(5.0d);
});
}

@Test
void 회원_정보의_이미지를_수정한다() {
// given
final User user = User.builder()
.name("kakao12345")
.profileImage(new ProfileImage("upload.png", "store.png"))
.reliability(5.0d)
.build();

// when
user.updateProfileImage(new ProfileImage("updateUpload.png", "updateStore.png"));

// then
SoftAssertions.assertSoftly(softAssertions -> {
softAssertions.assertThat(user.getName()).isEqualTo("kakao12345");
softAssertions.assertThat(user.getProfileImage()).isEqualTo(new ProfileImage("updateUpload.png", "updateStore.png"));
softAssertions.assertThat(user.getReliability()).isEqualTo(5.0d);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ void setUp(@Autowired RestDocumentationContextProvider provider) {
}

@Test
void 사용자_정보를_수정한다() throws Exception {
void 사용자_정보를_모두_수정한다() throws Exception {
// given
final MockMultipartFile profileImage = new MockMultipartFile(
"profileImage",
Expand Down Expand Up @@ -218,14 +218,84 @@ void setUp(@Autowired RestDocumentationContextProvider provider) {
),
responseFields(
fieldWithPath("name").type(JsonFieldType.STRING).description("사용자 닉네임"),
fieldWithPath("profileImage").type(JsonFieldType.STRING)
.description("사용자 프로필 이미지"),
fieldWithPath("profileImage").type(JsonFieldType.STRING).description("사용자 프로필 이미지"),
fieldWithPath("reliability").type(JsonFieldType.NUMBER).description("사용자 신뢰도")
)
)
);
}

@Test
void 사용자_정보를_이름만_수정한다() throws Exception {
// given
final MockMultipartFile profileImage = new MockMultipartFile(
"profileImage",
(byte[]) null
);
final UpdateUserRequest updateUserRequest = new UpdateUserRequest("updateName");
final MockMultipartFile request = new MockMultipartFile(
"request",
"request",
MediaType.APPLICATION_JSON_VALUE,
objectMapper.writeValueAsBytes(updateUserRequest)
);

final ReadUserDto readUserDto = new ReadUserDto(1L, "사용자1", 1L, 4.6d, "12345", false);
final PrivateClaims privateClaims = new PrivateClaims(1L);

given(userService.updateById(anyLong(), any())).willReturn(readUserDto);
given(mockTokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(privateClaims));

// when & then
mockMvc.perform(multipart(HttpMethod.PATCH, "/users")
.file(request)
.file(profileImage)
.contentType(MediaType.MULTIPART_FORM_DATA_VALUE)
.header(HttpHeaders.AUTHORIZATION, "Bearer accessToken")
)
.andExpectAll(
status().isOk(),
jsonPath("$.name", is(readUserDto.name())),
jsonPath("$.profileImage").exists(),
jsonPath("$.reliability", is(readUserDto.reliability()))
);
}

@Test
void 사용자_정보를_이미지만_수정한다() throws Exception {
// given
final MockMultipartFile profileImage = new MockMultipartFile(
"profileImage",
"image.png",
MediaType.IMAGE_PNG_VALUE,
new byte[]{1}
);
final MockMultipartFile request = new MockMultipartFile(
"request",
(byte[]) null
);

final ReadUserDto readUserDto = new ReadUserDto(1L, "사용자1", 1L, 4.6d, "12345", false);
final PrivateClaims privateClaims = new PrivateClaims(1L);

given(userService.updateById(anyLong(), any())).willReturn(readUserDto);
given(mockTokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(privateClaims));

// when & then
mockMvc.perform(multipart(HttpMethod.PATCH, "/users")
.file(request)
.file(profileImage)
.contentType(MediaType.MULTIPART_FORM_DATA_VALUE)
.header(HttpHeaders.AUTHORIZATION, "Bearer accessToken")
)
.andExpectAll(
status().isOk(),
jsonPath("$.name", is(readUserDto.name())),
jsonPath("$.profileImage").exists(),
jsonPath("$.reliability", is(readUserDto.reliability()))
);
}

@Test
void 존재하지_않는_사용자_정보_조회시_404를_반환한다() throws Exception {
// given
Expand Down

0 comments on commit 7790bc9

Please sign in to comment.