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

내 정보 조회 API 구현 #45

Merged
merged 1 commit into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.net.URI;

import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -13,12 +14,14 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.ajou.hertz.common.auth.UserPrincipal;
import com.ajou.hertz.common.validator.PhoneNumber;
import com.ajou.hertz.domain.user.dto.UserDto;
import com.ajou.hertz.domain.user.dto.request.SignUpRequest;
import com.ajou.hertz.domain.user.dto.response.UserEmailResponse;
import com.ajou.hertz.domain.user.dto.response.UserExistenceResponse;
import com.ajou.hertz.domain.user.dto.response.UserResponse;
import com.ajou.hertz.domain.user.dto.response.UserWithLinkedAccountInfoResponse;
import com.ajou.hertz.domain.user.service.UserCommandService;
import com.ajou.hertz.domain.user.service.UserQueryService;

Expand All @@ -27,6 +30,7 @@
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Email;
Expand All @@ -43,6 +47,19 @@ public class UserControllerV1 {
private final UserCommandService userCommandService;
private final UserQueryService userQueryService;

@Operation(
summary = "내 정보 조회",
description = "내 정보를 조회합니다.",
security = @SecurityRequirement(name = "access-token")
)
@GetMapping(value = "/me", headers = API_MINOR_VERSION_HEADER_NAME + "=" + 1)
public UserWithLinkedAccountInfoResponse getMyInfoV1_1(
@AuthenticationPrincipal UserPrincipal userPrincipal
) {
UserDto userDto = userQueryService.getDtoById(userPrincipal.getUserId());
return UserWithLinkedAccountInfoResponse.from(userDto);
}

@Operation(
summary = "회원 존재 여부 조회",
description = "전달받은 값들에 일치하는 회원이 존재하는지 확인힙니다."
Expand Down Expand Up @@ -83,13 +100,10 @@ public UserEmailResponse getUserEmailByPhoneV1_1(
)
@ApiResponses({
@ApiResponse(responseCode = "200"),
@ApiResponse(
responseCode = "409", content = @Content,
description = """
<p>[2200] 이미 다른 사용자가 사용 중인 이메일로 신규 회원을 등록하려고 하는 경우.
<p>[2203] 이미 다른 사용자가 사용 중인 전화번호로 신규 회원을 등록하려고 하는 경우.
"""
)
@ApiResponse(responseCode = "409", content = @Content, description = """
<p>[2200] 이미 다른 사용자가 사용 중인 이메일로 신규 회원을 등록하려고 하는 경우.
<p>[2203] 이미 다른 사용자가 사용 중인 전화번호로 신규 회원을 등록하려고 하는 경우.
""")
})
@PostMapping(headers = API_MINOR_VERSION_HEADER_NAME + "=" + 1)
public ResponseEntity<UserResponse> signUpV1_1(
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/com/ajou/hertz/domain/user/dto/UserDto.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.ajou.hertz.domain.user.dto;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Set;

import com.ajou.hertz.domain.user.constant.Gender;
Expand All @@ -25,6 +26,7 @@ public class UserDto {
private Gender gender;
private String phone;
private String contactLink;
private LocalDateTime createdAt;

public static UserDto from(User user) {
return new UserDto(
Expand All @@ -37,7 +39,8 @@ public static UserDto from(User user) {
user.getBirth(),
user.getGender(),
user.getPhone(),
user.getContactLink()
user.getContactLink(),
user.getCreatedAt()
);
}
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,52 @@
package com.ajou.hertz.domain.user.dto.response;

import java.time.LocalDate;
import java.time.LocalDateTime;

import com.ajou.hertz.domain.user.constant.Gender;
import com.ajou.hertz.domain.user.dto.UserDto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class UserResponse {

@Schema(description = "Id of user", example = "1")
private Long id;

@Schema(description = "이메일", example = "[email protected]")
private String email;

@Schema(description = "프로필 이미지 url", example = "https://user-profile-image")
private String profileImageUrl;

@Schema(description = "생년월일")
private LocalDate birth;

@Schema(description = "성별")
private Gender gender;

@Schema(description = "연락 수단")
private String contactLink;

@Schema(description = "계정 생성일자 (가입일)")
private LocalDateTime createdAt;

public static UserResponse from(UserDto userDto) {
return new UserResponse(
userDto.getId(),
userDto.getEmail(),
userDto.getProfileImageUrl(),
userDto.getBirth(),
userDto.getGender(),
userDto.getContactLink()
userDto.getContactLink(),
userDto.getCreatedAt()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.ajou.hertz.domain.user.dto.response;

import java.time.LocalDate;
import java.time.LocalDateTime;

import org.springframework.util.StringUtils;

import com.ajou.hertz.domain.user.constant.Gender;
import com.ajou.hertz.domain.user.dto.UserDto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public class UserWithLinkedAccountInfoResponse extends UserResponse {

@Schema(description = "카카오 계정 연동 여부", example = "true")
private Boolean isKakaoAccountLinked;

private UserWithLinkedAccountInfoResponse(
Long id,
String email,
String profileImageUrl,
LocalDate birth,
Gender gender,
String contactLink,
LocalDateTime createdAt,
Boolean isKakaoAccountLinked
) {
super(id, email, profileImageUrl, birth, gender, contactLink, createdAt);
this.isKakaoAccountLinked = isKakaoAccountLinked;
}

public static UserWithLinkedAccountInfoResponse from(UserDto userDto) {
return new UserWithLinkedAccountInfoResponse(
userDto.getId(),
userDto.getEmail(),
userDto.getProfileImageUrl(),
userDto.getBirth(),
userDto.getGender(),
userDto.getContactLink(),
userDto.getCreatedAt(),
StringUtils.hasText(userDto.getKakaoUid())
);
}
}
7 changes: 5 additions & 2 deletions src/test/java/com/ajou/hertz/config/TestSecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import java.lang.reflect.Constructor;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Set;

import org.springframework.boot.test.context.TestConfiguration;
Expand Down Expand Up @@ -46,7 +47,8 @@ public void securitySetUp() throws Exception {
private UserDto createUserDto() throws Exception {
Constructor<UserDto> userResponseConstructor = UserDto.class.getDeclaredConstructor(
Long.class, Set.class, String.class, String.class, String.class,
String.class, LocalDate.class, Gender.class, String.class, String.class
String.class, LocalDate.class, Gender.class, String.class, String.class,
LocalDateTime.class
);
userResponseConstructor.setAccessible(true);
return userResponseConstructor.newInstance(
Expand All @@ -59,7 +61,8 @@ private UserDto createUserDto() throws Exception {
LocalDate.of(2024, 1, 1),
Gender.ETC,
"01012345678",
"https://contack-link"
"https://contack-link",
LocalDateTime.of(2024, 1, 1, 0, 0)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ private JwtTokenInfoDto createJwtTokenInfoDto() {
private UserDto createUserDto(long id) throws Exception {
Constructor<UserDto> userResponseConstructor = UserDto.class.getDeclaredConstructor(
Long.class, Set.class, String.class, String.class, String.class,
String.class, LocalDate.class, Gender.class, String.class, String.class
String.class, LocalDate.class, Gender.class, String.class, String.class,
LocalDateTime.class
);
userResponseConstructor.setAccessible(true);
return userResponseConstructor.newInstance(
Expand All @@ -122,7 +123,8 @@ private UserDto createUserDto(long id) throws Exception {
LocalDate.of(2024, 1, 1),
Gender.ETC,
"01012345678",
"https://contack-link"
"https://contack-link",
LocalDateTime.of(2024, 1, 1, 0, 0)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ private void verifyEveryMocksShouldHaveNoMoreInteractions() {
private UserDto createUserDto(long id) throws Exception {
Constructor<UserDto> userResponseConstructor = UserDto.class.getDeclaredConstructor(
Long.class, Set.class, String.class, String.class, String.class,
String.class, LocalDate.class, Gender.class, String.class, String.class
String.class, LocalDate.class, Gender.class, String.class, String.class,
LocalDateTime.class
);
userResponseConstructor.setAccessible(true);
return userResponseConstructor.newInstance(
Expand All @@ -153,7 +154,8 @@ private UserDto createUserDto(long id) throws Exception {
LocalDate.of(2024, 1, 1),
Gender.ETC,
"01012345678",
"https://contack-link"
"https://contack-link",
LocalDateTime.of(2024, 1, 1, 0, 0)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import static com.ajou.hertz.common.constant.GlobalConstants.*;
import static org.mockito.BDDMockito.*;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

import java.lang.reflect.Constructor;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Set;

import org.junit.jupiter.api.DisplayName;
Expand All @@ -17,6 +19,7 @@
import org.springframework.context.annotation.Import;
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext;
import org.springframework.http.MediaType;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.test.context.event.annotation.BeforeTestMethod;
import org.springframework.test.web.servlet.MockMvc;

Expand All @@ -26,6 +29,7 @@
import com.ajou.hertz.common.auth.JwtAuthenticationFilter;
import com.ajou.hertz.common.auth.JwtExceptionFilter;
import com.ajou.hertz.common.auth.JwtTokenProvider;
import com.ajou.hertz.common.auth.UserPrincipal;
import com.ajou.hertz.common.config.SecurityConfig;
import com.ajou.hertz.domain.user.constant.Gender;
import com.ajou.hertz.domain.user.constant.RoleType;
Expand Down Expand Up @@ -71,6 +75,25 @@ public void securitySetUp() throws Exception {
given(userQueryService.getDtoById(anyLong())).willReturn(createUserDto());
}

@Test
void 내_정보를_조회한다() throws Exception {
// given
long userId = 1L;
UserDto expectedResult = createUserDto(userId);
given(userQueryService.getDtoById(userId)).willReturn(expectedResult);

// when & then
mvc.perform(
get("/v1/users/me")
.header(API_MINOR_VERSION_HEADER_NAME, 1)
.with(user(createTestUser(userId)))
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(expectedResult.getId()));
then(userQueryService).should().getDtoById(userId);
verifyEveryMocksShouldHaveNoMoreInteractions();
}

@Test
void 이메일이_주어지고_주어진_이메일을_사용_중인_회원의_존재_여부를_조회한다() throws Exception {
// given
Expand Down Expand Up @@ -219,7 +242,8 @@ private SignUpRequest createSignUpRequest() throws Exception {
private UserDto createUserDto(long id) throws Exception {
Constructor<UserDto> userResponseConstructor = UserDto.class.getDeclaredConstructor(
Long.class, Set.class, String.class, String.class, String.class,
String.class, LocalDate.class, Gender.class, String.class, String.class
String.class, LocalDate.class, Gender.class, String.class, String.class,
LocalDateTime.class
);
userResponseConstructor.setAccessible(true);
return userResponseConstructor.newInstance(
Expand All @@ -232,11 +256,16 @@ private UserDto createUserDto(long id) throws Exception {
LocalDate.of(2024, 1, 1),
Gender.ETC,
"01012345678",
"https://contack-link"
"https://contack-link",
LocalDateTime.of(2024, 1, 1, 0, 0)
);
}

private UserDto createUserDto() throws Exception {
return createUserDto(1L);
}

private UserDetails createTestUser(Long userId) throws Exception {
return new UserPrincipal(createUserDto(userId));
}
}
Loading