Skip to content

Commit

Permalink
#119 feat: 회원 동네 목록 조회 컨트롤러 및 서비스 구현 (#123)
Browse files Browse the repository at this point in the history
  • Loading branch information
yonghwankim-dev authored Sep 30, 2023
1 parent 8428311 commit 99ccc02
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package codesquard.app.api.member;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -9,7 +10,11 @@
import org.springframework.web.multipart.MultipartFile;

import codesquard.app.api.member.response.MemberProfileResponse;
import codesquard.app.api.membertown.MemberTownService;
import codesquard.app.api.membertown.response.MemberTownListResponse;
import codesquard.app.api.response.ApiResponse;
import codesquard.app.domain.oauth.support.AuthPrincipal;
import codesquard.app.domain.oauth.support.Principal;
import lombok.RequiredArgsConstructor;

@RestController
Expand All @@ -18,11 +23,17 @@
public class MemberController {

private final MemberService memberService;
private final MemberTownService memberTownService;

@PutMapping(value = "/{loginId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ApiResponse<MemberProfileResponse> modifyProfileImage(@RequestPart MultipartFile updateImageFile,
@PathVariable String loginId) {
return ApiResponse.ok("프로필 사진이 수정되었습니다.",
memberService.modifyProfileImage(loginId, updateImageFile));
}

@GetMapping(value = "/regions")
public ApiResponse<MemberTownListResponse> readAllMemberTowns(@AuthPrincipal Principal principal) {
return ApiResponse.ok("회원 동네 목록 조회를 완료하였습니다.", memberTownService.readAll(principal));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package codesquard.app.api.membertown;

import java.util.List;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -12,6 +13,8 @@
import codesquard.app.api.membertown.request.MemberTownAddRequest;
import codesquard.app.api.membertown.request.MemberTownRemoveRequest;
import codesquard.app.api.membertown.response.MemberAddRegionResponse;
import codesquard.app.api.membertown.response.MemberTownItemResponse;
import codesquard.app.api.membertown.response.MemberTownListResponse;
import codesquard.app.api.membertown.response.MemberTownRemoveResponse;
import codesquard.app.api.region.request.RegionSelectionRequest;
import codesquard.app.domain.member.Member;
Expand Down Expand Up @@ -108,4 +111,13 @@ private void validateExistRegion(Long regionId) {
throw new RestApiException(RegionErrorCode.NOT_FOUND_REGION);
}
}

@Transactional(readOnly = true)
public MemberTownListResponse readAll(Principal principal) {
List<MemberTownItemResponse> itemResponses = memberTownRepository.findAllByMemberId(principal.getMemberId())
.stream()
.map(MemberTownItemResponse::from)
.collect(Collectors.toUnmodifiableList());
return new MemberTownListResponse(itemResponses);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package codesquard.app.api.membertown.response;

import codesquard.app.domain.membertown.MemberTown;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class MemberTownItemResponse {
private Long addressId;
private String fullAddressName;
private String addressName;
private Boolean isSelected;

public static MemberTownItemResponse from(MemberTown memberTown) {
return new MemberTownItemResponse(
memberTown.getId(),
memberTown.getRegion().getName(),
memberTown.getRegion().getShortAddress(),
memberTown.isSelected()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package codesquard.app.api.membertown.response;

import java.util.List;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class MemberTownListResponse {
private List<MemberTownItemResponse> addresses;

public MemberTownListResponse(List<MemberTownItemResponse> addresses) {
this.addresses = addresses;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package codesquard.app.api.member;

import static codesquard.app.MemberTestSupport.*;
import static codesquard.app.MemberTownTestSupport.*;
import static codesquard.app.RegionTestSupport.*;
import static org.hamcrest.Matchers.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.*;
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.util.List;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import codesquard.app.ControllerTestSupport;
import codesquard.app.api.membertown.MemberTownService;
import codesquard.app.api.membertown.response.MemberTownItemResponse;
import codesquard.app.api.membertown.response.MemberTownListResponse;
import codesquard.app.domain.member.Member;
import codesquard.app.domain.membertown.MemberTown;
import codesquard.app.domain.oauth.support.Principal;
import codesquard.app.domain.region.Region;

@WebMvcTest(controllers = MemberController.class)
class MemberControllerTest extends ControllerTestSupport {

private MockMvc mockMvc;

@Autowired
private MemberController memberController;

@MockBean
private MemberTownService memberTownService;

@MockBean
private MemberService memberService;

@BeforeEach
public void setup() {
mockMvc = MockMvcBuilders.standaloneSetup(memberController)
.setControllerAdvice(globalExceptionHandler)
.setCustomArgumentResolvers(authPrincipalArgumentResolver)
.alwaysDo(print())
.build();

given(authPrincipalArgumentResolver.supportsParameter(any())).willReturn(true);

Principal principal = new Principal(1L, "[email protected]", "23Yong", null, null);
given(authPrincipalArgumentResolver.resolveArgument(any(), any(), any(), any())).willReturn(principal);
}

@DisplayName("회원은 회원의 동네를 조회할 수 있다")
@Test
public void readALlMemberTowns() throws Exception {
// given
Member member = createMember("avatarUrl", "[email protected]", "23Yong");
Region region = createRegion("서울 송파구 가락동");
MemberTown memberTown = createMemberTown(member, region, true);
List<MemberTownItemResponse> itemResponses = List.of(MemberTownItemResponse.from(memberTown));
MemberTownListResponse response = new MemberTownListResponse(itemResponses);
given(memberTownService.readAll(
ArgumentMatchers.any(Principal.class)))
.willReturn(response);

// when & then
mockMvc.perform(get("/api/members/regions"))
.andExpect(status().isOk())
.andExpect(jsonPath("statusCode").value(equalTo(200)))
.andExpect(jsonPath("message").value(equalTo("회원 동네 목록 조회를 완료하였습니다.")))
.andExpect(jsonPath("data.addresses[*].fullAddressName").value(containsInAnyOrder("서울 송파구 가락동")))
.andExpect(jsonPath("data.addresses[*].addressName").value(containsInAnyOrder("가락동")))
.andExpect(jsonPath("data.addresses[*].isSelected").value(containsInAnyOrder(true)));

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import codesquard.app.api.membertown.request.MemberTownAddRequest;
import codesquard.app.api.membertown.request.MemberTownRemoveRequest;
import codesquard.app.api.membertown.response.MemberAddRegionResponse;
import codesquard.app.api.membertown.response.MemberTownListResponse;
import codesquard.app.api.membertown.response.MemberTownRemoveResponse;
import codesquard.app.api.region.request.RegionSelectionRequest;
import codesquard.app.domain.member.Member;
Expand Down Expand Up @@ -332,4 +333,19 @@ public void selectRegionWithNotRegisteredRegionId() throws JsonProcessingExcepti
.extracting("errorCode.message")
.isEqualTo("회원이 등록한 동네만 선택할 수 있습니다.");
}

@DisplayName("회원은 자신의 회원 동네를 조회할 수 있다")
@Test
public void readAll() throws JsonProcessingException {
// given
Member member = memberRepository.save(createMember("avatarUrlValue", "[email protected]", "23Yong"));
List<Region> regions = regionRepository.saveAll(List.of(createRegion("서울 송파구 가락동")));
memberTownRepository.saveAll(List.of(createMemberTown(member, regions.get(0), true)));

// when
MemberTownListResponse response = memberTownService.readAll(Principal.from(member));

// then
assertThat(response.getAddresses().size()).isEqualTo(1);
}
}

0 comments on commit 99ccc02

Please sign in to comment.