Skip to content

Commit

Permalink
merge develop into
Browse files Browse the repository at this point in the history
  • Loading branch information
hongdosan committed Nov 26, 2023
2 parents 2dc0689 + 2602526 commit b4049c1
Show file tree
Hide file tree
Showing 12 changed files with 195 additions and 6 deletions.
23 changes: 23 additions & 0 deletions src/main/java/com/moabam/api/application/member/MemberService.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@
import com.moabam.api.dto.member.MemberInfo;
import com.moabam.api.dto.member.MemberInfoResponse;
import com.moabam.api.dto.member.MemberInfoSearchResponse;
import com.moabam.api.dto.member.ModifyMemberRequest;
import com.moabam.global.auth.model.AuthMember;
import com.moabam.global.common.util.ClockHolder;
import com.moabam.global.common.util.GlobalConstant;
import com.moabam.global.error.exception.BadRequestException;
import com.moabam.global.error.exception.ConflictException;
import com.moabam.global.error.exception.NotFoundException;

import io.micrometer.common.util.StringUtils;
import lombok.RequiredArgsConstructor;

@Service
Expand Down Expand Up @@ -82,6 +85,26 @@ public MemberInfoResponse searchInfo(AuthMember authMember, Long memberId) {
return MemberMapper.toMemberInfoResponse(memberInfoSearchResponse, inventories);
}

@Transactional
public void modifyInfo(AuthMember authMember, ModifyMemberRequest modifyMemberRequest, String newProfileUri) {
validateNickname(modifyMemberRequest.nickname());

Member member = memberSearchRepository.findMember(authMember.id())
.orElseThrow(() -> new NotFoundException(MEMBER_NOT_FOUND));

member.changeNickName(modifyMemberRequest.nickname());
member.changeIntro(modifyMemberRequest.intro());
member.changeProfileUri(newProfileUri);

memberRepository.save(member);
}

private void validateNickname(String nickname) {
if (StringUtils.isEmpty(nickname) && memberRepository.existsByNickname(nickname)) {
throw new ConflictException(NICKNAME_CONFLICT);
}
}

private List<Inventory> getDefaultSkin(Long searchId) {
List<Inventory> inventories = inventorySearchRepository.findDefaultSkin(searchId);
if (inventories.size() != GlobalConstant.DEFAULT_SKIN_SIZE) {
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/com/moabam/api/domain/member/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ private Member(Long id, String socialId, Bug bug) {
this.id = id;
this.socialId = requireNonNull(socialId);
this.nickname = createNickName();
this.intro = "";
this.profileImage = BaseImageUrl.MEMBER_PROFILE_URL;
this.bug = requireNonNull(bug);
this.role = Role.USER;
Expand Down Expand Up @@ -124,7 +125,15 @@ public void delete(LocalDateTime now) {
}

public void changeNickName(String nickname) {
this.nickname = nickname;
this.nickname = requireNonNullElse(nickname, this.nickname);
}

public void changeIntro(String intro) {
this.intro = requireNonNullElse(intro, this.intro);
}

public void changeProfileUri(String newProfileUri) {
this.profileImage = requireNonNullElse(newProfileUri, profileImage);
}

private String createNickName() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@
public interface MemberRepository extends JpaRepository<Member, Long> {

Optional<Member> findBySocialId(String id);

boolean existsByNickname(String nickname);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.moabam.api.dto.member;

public record ModifyMemberRequest(
String intro,
String nickname
) {

}
24 changes: 24 additions & 0 deletions src/main/java/com/moabam/api/presentation/MemberController.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
package com.moabam.api.presentation;

import java.util.List;

import org.springframework.http.HttpStatus;
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.RequestBody;
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;

import com.moabam.api.application.auth.AuthorizationService;
import com.moabam.api.application.image.ImageService;
import com.moabam.api.application.member.MemberService;
import com.moabam.api.domain.image.ImageType;
import com.moabam.api.dto.auth.AuthorizationCodeResponse;
import com.moabam.api.dto.auth.AuthorizationTokenInfoResponse;
import com.moabam.api.dto.auth.AuthorizationTokenResponse;
import com.moabam.api.dto.auth.LoginResponse;
import com.moabam.api.dto.member.MemberInfoResponse;
import com.moabam.api.dto.member.ModifyMemberRequest;
import com.moabam.global.auth.annotation.Auth;
import com.moabam.global.auth.model.AuthMember;
import com.moabam.global.error.exception.BadRequestException;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
Expand All @@ -31,6 +39,7 @@ public class MemberController {

private final AuthorizationService authorizationService;
private final MemberService memberService;
private final ImageService imageService;

@GetMapping("/login/oauth")
public void socialLogin(HttpServletResponse httpServletResponse) {
Expand Down Expand Up @@ -65,4 +74,19 @@ public void deleteMember(@Auth AuthMember authMember) {
public MemberInfoResponse searchInfo(@Auth AuthMember authMember, @PathVariable(required = false) Long memberId) {
return memberService.searchInfo(authMember, memberId);
}

@PostMapping("/modify")
public void modifyMember(@Auth AuthMember authMember,
@RequestPart(required = false) ModifyMemberRequest modifyMemberRequest,
@RequestPart(name = "profileImage", required = false) MultipartFile newProfileImage) {
String newProfileUri = null;

try {
newProfileUri = imageService.uploadImages(List.of(newProfileImage), ImageType.PROFILE_IMAGE).get(0);
} catch (BadRequestException | NullPointerException e) {
// Do nothing
}

memberService.modifyInfo(authMember, modifyMemberRequest, newProfileUri);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public enum ErrorMessage {
MEMBER_NOT_FOUND_BY_MANAGER_OR_NULL("방의 매니저거나 회원이 존재하지 않습니다."),
MEMBER_ROOM_EXCEED("참여할 수 있는 방의 개수가 모두 찼습니다."),
UNLINK_REQUEST_FAIL_ROLLBACK_SUCCESS("카카오 연결 요청 실패로 Rollback하였습니다."),
NICKNAME_CONFLICT("이미 존재하는 닉네임입니다."),

INVALID_DEFAULT_SKIN_SIZE("기본 스킨은 2개여야 합니다. 관리자에게 문의하세요"),

Expand Down
6 changes: 3 additions & 3 deletions src/main/resources/static/docs/coupon.html
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ <h4 id="_요청" class="discrete">요청</h4>
<div class="content">
<pre class="highlight nowrap"><code class="language-http" data-lang="http">POST /admins/coupons HTTP/1.1
Content-Type: application/json;charset=UTF-8
Content-Length: 175
Content-Length: 183
Host: localhost:8080

{
Expand Down Expand Up @@ -571,7 +571,7 @@ <h4 id="_요청_4">요청</h4>
<div class="content">
<pre class="highlight nowrap"><code class="language-http" data-lang="http">POST /coupons/search HTTP/1.1
Content-Type: application/json;charset=UTF-8
Content-Length: 41
Content-Length: 44
Host: localhost:8080

{
Expand Down Expand Up @@ -637,7 +637,7 @@ <h4 id="_응답_5" class="discrete">응답</h4>
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 3600
Content-Type: application/json
Content-Length: 64
Content-Length: 66

{
"message" : "쿠폰 발급 가능 기간이 아닙니다."
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/static/docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ <h4 id="_상태코드httpstatus"><a class="link" href="#_상태코드httpstatus"
<div id="footer">
<div id="footer-text">
Version 0.0.1-SNAPSHOT<br>
Last updated 2023-11-06 23:30:09 +0900
Last updated 2023-11-26 16:03:25 +0900
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.3/highlight.min.js"></script>
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/static/docs/notification.html
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ <h4 id="_응답_2" class="discrete">응답</h4>
<div id="footer">
<div id="footer-text">
Version 0.0.1-SNAPSHOT<br>
Last updated 2023-11-21 17:10:26 +0900
Last updated 2023-11-26 16:03:25 +0900
</div>
</div>
</body>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.moabam.api.dto.auth.AuthorizationTokenInfoResponse;
import com.moabam.api.dto.auth.LoginResponse;
import com.moabam.api.dto.member.MemberInfoResponse;
import com.moabam.api.dto.member.ModifyMemberRequest;
import com.moabam.global.auth.model.AuthMember;
import com.moabam.global.common.util.ClockHolder;
import com.moabam.global.error.exception.BadRequestException;
Expand All @@ -37,6 +38,7 @@
import com.moabam.support.fixture.ItemFixture;
import com.moabam.support.fixture.MemberFixture;
import com.moabam.support.fixture.MemberInfoSearchFixture;
import com.moabam.support.fixture.ModifyImageFixture;

@ExtendWith({MockitoExtension.class, FilterProcessExtension.class})
class MemberServiceTest {
Expand Down Expand Up @@ -224,4 +226,24 @@ void failBy_overSize(@WithMember AuthMember authMember) {
.hasMessage(INVALID_DEFAULT_SKIN_SIZE.getMessage());
}
}

@DisplayName("사용자 정보 수정 성공")
@Test
void modify_success_test(@WithMember AuthMember authMember) {
// given
Member member = MemberFixture.member();
ModifyMemberRequest modifyMemberRequest = ModifyImageFixture.modifyMemberRequest();
given(memberSearchRepository.findMember(authMember.id())).willReturn(Optional.ofNullable(member));

// when
memberService.modifyInfo(authMember, modifyMemberRequest, "/main");

// Then
assertAll(
() -> assertThat(member.getNickname()).isEqualTo(modifyMemberRequest.nickname()),
() -> assertThat(member.getIntro()).isEqualTo(modifyMemberRequest.intro()),
() -> assertThat(member.getProfileImage()).isEqualTo("/main")
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import static com.moabam.global.common.util.GlobalConstant.*;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.BDDMockito.*;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.*;
import static org.springframework.test.web.client.response.MockRestResponseCreators.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;

Expand All @@ -19,15 +21,18 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.client.AutoConfigureMockRestServiceServer;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.test.web.client.match.MockRestRequestMatchers;
Expand All @@ -39,7 +44,9 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import com.moabam.api.application.auth.OAuth2AuthorizationServerRequestService;
import com.moabam.api.application.image.ImageService;
import com.moabam.api.domain.auth.repository.TokenRepository;
import com.moabam.api.domain.image.ImageType;
import com.moabam.api.domain.item.Inventory;
import com.moabam.api.domain.item.Item;
import com.moabam.api.domain.item.repository.InventoryRepository;
Expand All @@ -55,6 +62,7 @@
import com.moabam.api.domain.room.repository.ParticipantRepository;
import com.moabam.api.domain.room.repository.RoomRepository;
import com.moabam.api.dto.auth.TokenSaveValue;
import com.moabam.api.dto.member.ModifyMemberRequest;
import com.moabam.global.config.OAuthConfig;
import com.moabam.global.error.exception.UnauthorizedException;
import com.moabam.global.error.handler.RestTemplateResponseHandler;
Expand Down Expand Up @@ -111,6 +119,9 @@ class MemberControllerTest extends WithoutFilterSupporter {
@Autowired
OAuthConfig oAuthConfig;

@SpyBean
ImageService imageService;

RestTemplateBuilder restTemplateBuilder;

MockRestServiceServer mockRestServiceServer;
Expand Down Expand Up @@ -417,4 +428,65 @@ void search_member_failBy_default_skin_size() throws Exception {
.andExpect(status().is4xxClientError());

}

@DisplayName("회원 정보 요청 성공")
@WithMember
@ParameterizedTest
@CsvSource({"intro,", ", nickname", ",", "intro, nickname"})
void member_modify_request_success(String intro, String nickname) throws Exception {
// given
ModifyMemberRequest request = new ModifyMemberRequest(intro, nickname);
MockMultipartFile newProfileImage =
new MockMultipartFile(
"profileImage",
"tooth.png",
"multipart/form-data",
"uploadFile".getBytes(StandardCharsets.UTF_8));
MockMultipartFile modifyMemberRequest =
new MockMultipartFile(
"modifyMemberRequest",
null,
"application/json",
objectMapper.writeValueAsString(request).getBytes(StandardCharsets.UTF_8));

willReturn(List.of("/main"))
.given(imageService).uploadImages(List.of(newProfileImage), ImageType.PROFILE_IMAGE);

// expected
mockMvc.perform(multipart(HttpMethod.POST, "/members/modify")
.file(modifyMemberRequest)
.file(newProfileImage)
.contentType("multipart/form-data")

.characterEncoding("UTF-8"))
.andExpect(status().is2xxSuccessful())
.andDo(print());
}

@DisplayName("회원 프로필없이 성공 ")
@WithMember
@ParameterizedTest
@CsvSource({"intro,", ", nickname", ",", "intro, nickname"})
void member_modify_no_image_request_success(String intro, String nickname) throws Exception {
// given
ModifyMemberRequest request = new ModifyMemberRequest(intro, nickname);
MockMultipartFile modifyMemberRequest =
new MockMultipartFile(
"modifyMemberRequest",
null,
"application/json",
objectMapper.writeValueAsString(request).getBytes(StandardCharsets.UTF_8));

willThrow(NullPointerException.class)
.given(imageService).uploadImages(any(), any());

// expected
mockMvc.perform(multipart(HttpMethod.POST, "/members/modify")
.file(modifyMemberRequest)
.contentType("multipart/form-data")

.characterEncoding("UTF-8"))
.andExpect(status().is2xxSuccessful())
.andDo(print());
}
}
28 changes: 28 additions & 0 deletions src/test/java/com/moabam/support/fixture/ModifyImageFixture.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.moabam.support.fixture;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import org.springframework.mock.web.MockMultipartFile;

import com.moabam.api.dto.member.ModifyMemberRequest;

public class ModifyImageFixture {

public static MockMultipartFile makeMultipartFile() {
try {
File file = new File("src/test/resources/image.png");
FileInputStream fileInputStream = new FileInputStream(file);

return new MockMultipartFile("1", "image.png", "image/png", fileInputStream);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}

public static ModifyMemberRequest modifyMemberRequest() {
return new ModifyMemberRequest("intro", "sldsldsld");
}

}

0 comments on commit b4049c1

Please sign in to comment.