From b2ddd7eeddb24dd48aa2f1d7d9fbf5039e60b2a7 Mon Sep 17 00:00:00 2001 From: Dabeen Jeong Date: Fri, 28 Jul 2023 18:02:31 +0900 Subject: [PATCH] =?UTF-8?q?[BE]=20=EC=B9=B4=EC=B9=B4=EC=98=A4=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EA=B8=B0=EB=8A=A5=EC=9D=84=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#123)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 카카오 OAuth2 기능 추가 * feat: 로그인 기능 추가 * feat: 테스트 전용 PlatformUserProvider 추가 * test: 로그인 관련 테스트시 쿠키를 얻을 수 있는 공용 메서드 추가 * refactor: 패키지명 변경 * feat: 카카오 로그인시, 사이트에 등록된 회원이면 등록된 정보를 반환하고, 아니라면 등록한 후 정보를 반환하는 기능 추가 * refactor: 팀 컨벤션에 맞게 리팩터링 * test: platformId를 통해 유저를 반환하는 테스트 추가 * refactor: 멤버 생성자 수정으로 인한 테스트 코드 변경 * feat: 가입된 유저라면 201 OK 반환, 가입되지 않은 유저라면 302 FOUND 반환 * refactor: 팀원 피드백 반영 * feat: 로그아웃 기능 추가 * feat: 카카오 로그인 환경 변수 설정 --- .../funeat/auth/application/AuthService.java | 31 +++++ .../com/funeat/auth/dto/KakaoTokenDto.java | 53 ++++++++ .../com/funeat/auth/dto/KakaoUserInfoDto.java | 61 +++++++++ .../com/funeat/auth/dto/LoginRequest.java | 14 ++ .../java/com/funeat/auth/dto/SignUserDto.java | 26 ++++ .../com/funeat/auth/dto/TokenResponse.java | 14 ++ .../java/com/funeat/auth/dto/UserInfoDto.java | 40 ++++++ .../auth/presentation/AuthController.java | 55 ++++++++ .../auth/util/AuthArgumentResolver.java | 31 +++++ .../auth/util/AuthHandlerInterceptor.java | 20 +++ .../auth/util/AuthenticationPrincipal.java | 11 ++ .../auth/util/KakaoPlatformUserProvider.java | 122 ++++++++++++++++++ .../auth/util/PlatformUserProvider.java | 10 ++ .../java/com/funeat/common/WebConfig.java | 7 +- .../member/application/MemberService.java | 35 +++++ .../java/com/funeat/member/domain/Member.java | 11 +- .../member/persistence/MemberRepository.java | 3 + backend/src/main/resources/application.yml | 4 + .../acceptance/auth/AuthAcceptanceTest.java | 40 ++++++ .../funeat/acceptance/common/LoginSteps.java | 21 +++ .../common/TestPlatformUserProvider.java | 21 +++ .../product/ProductAcceptanceTest.java | 6 +- .../review/ReviewAcceptanceTest.java | 50 +++---- .../auth/application/AuthServiceTest.java | 41 ++++++ .../auth/presentation/AuthControllerTest.java | 65 ++++++++++ .../member/application/MemberServiceTest.java | 74 +++++++++++ .../persistence/MemberRepositoryTest.java | 39 ++++++ .../ReviewFavoriteRepositoryTest.java | 2 +- .../persistence/ProductRepositoryTest.java | 2 +- .../review/application/ReviewServiceTest.java | 20 +-- .../persistence/ReviewRepositoryTest.java | 14 +- .../persistence/ReviewTagRepositoryTest.java | 2 +- 32 files changed, 894 insertions(+), 51 deletions(-) create mode 100644 backend/src/main/java/com/funeat/auth/application/AuthService.java create mode 100644 backend/src/main/java/com/funeat/auth/dto/KakaoTokenDto.java create mode 100644 backend/src/main/java/com/funeat/auth/dto/KakaoUserInfoDto.java create mode 100644 backend/src/main/java/com/funeat/auth/dto/LoginRequest.java create mode 100644 backend/src/main/java/com/funeat/auth/dto/SignUserDto.java create mode 100644 backend/src/main/java/com/funeat/auth/dto/TokenResponse.java create mode 100644 backend/src/main/java/com/funeat/auth/dto/UserInfoDto.java create mode 100644 backend/src/main/java/com/funeat/auth/presentation/AuthController.java create mode 100644 backend/src/main/java/com/funeat/auth/util/AuthArgumentResolver.java create mode 100644 backend/src/main/java/com/funeat/auth/util/AuthHandlerInterceptor.java create mode 100644 backend/src/main/java/com/funeat/auth/util/AuthenticationPrincipal.java create mode 100644 backend/src/main/java/com/funeat/auth/util/KakaoPlatformUserProvider.java create mode 100644 backend/src/main/java/com/funeat/auth/util/PlatformUserProvider.java create mode 100644 backend/src/main/java/com/funeat/member/application/MemberService.java create mode 100644 backend/src/test/java/com/funeat/acceptance/auth/AuthAcceptanceTest.java create mode 100644 backend/src/test/java/com/funeat/acceptance/common/LoginSteps.java create mode 100644 backend/src/test/java/com/funeat/acceptance/common/TestPlatformUserProvider.java create mode 100644 backend/src/test/java/com/funeat/auth/application/AuthServiceTest.java create mode 100644 backend/src/test/java/com/funeat/auth/presentation/AuthControllerTest.java create mode 100644 backend/src/test/java/com/funeat/member/application/MemberServiceTest.java create mode 100644 backend/src/test/java/com/funeat/member/persistence/MemberRepositoryTest.java diff --git a/backend/src/main/java/com/funeat/auth/application/AuthService.java b/backend/src/main/java/com/funeat/auth/application/AuthService.java new file mode 100644 index 000000000..0918aa601 --- /dev/null +++ b/backend/src/main/java/com/funeat/auth/application/AuthService.java @@ -0,0 +1,31 @@ +package com.funeat.auth.application; + +import com.funeat.auth.dto.SignUserDto; +import com.funeat.auth.dto.UserInfoDto; +import com.funeat.auth.util.PlatformUserProvider; +import com.funeat.member.application.MemberService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +public class AuthService { + + private final MemberService memberService; + private final PlatformUserProvider platformUserProvider; + + public AuthService(final MemberService memberService, final PlatformUserProvider platformUserProvider) { + this.memberService = memberService; + this.platformUserProvider = platformUserProvider; + } + + public SignUserDto loginWithKakao(final String code) { + final UserInfoDto userInfoDto = platformUserProvider.getPlatformUser(code); + final SignUserDto signUserDto = memberService.findOrCreateMember(userInfoDto); + return signUserDto; + } + + public String getLoginRedirectUri() { + return platformUserProvider.getRedirectURI(); + } +} diff --git a/backend/src/main/java/com/funeat/auth/dto/KakaoTokenDto.java b/backend/src/main/java/com/funeat/auth/dto/KakaoTokenDto.java new file mode 100644 index 000000000..6b4f0995e --- /dev/null +++ b/backend/src/main/java/com/funeat/auth/dto/KakaoTokenDto.java @@ -0,0 +1,53 @@ +package com.funeat.auth.dto; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class KakaoTokenDto { + + private final String accessToken; + private final String tokenType; + private final String refreshToken; + private final String expiresIn; + private final String scope; + private final String refreshTokenExpiresIn; + + @JsonCreator + public KakaoTokenDto(@JsonProperty("access_token") final String accessToken, + @JsonProperty("token_type") final String tokenType, + @JsonProperty("refresh_token") final String refreshToken, + @JsonProperty("expires_in") final String expiresIn, + @JsonProperty("scope") final String scope, + @JsonProperty("refresh_token_expires_in") final String refreshTokenExpiresIn) { + this.accessToken = accessToken; + this.tokenType = tokenType; + this.refreshToken = refreshToken; + this.expiresIn = expiresIn; + this.scope = scope; + this.refreshTokenExpiresIn = refreshTokenExpiresIn; + } + + public String getAccessToken() { + return accessToken; + } + + public String getTokenType() { + return tokenType; + } + + public String getRefreshToken() { + return refreshToken; + } + + public String getExpiresIn() { + return expiresIn; + } + + public String getScope() { + return scope; + } + + public String getRefreshTokenExpiresIn() { + return refreshTokenExpiresIn; + } +} diff --git a/backend/src/main/java/com/funeat/auth/dto/KakaoUserInfoDto.java b/backend/src/main/java/com/funeat/auth/dto/KakaoUserInfoDto.java new file mode 100644 index 000000000..8b9424045 --- /dev/null +++ b/backend/src/main/java/com/funeat/auth/dto/KakaoUserInfoDto.java @@ -0,0 +1,61 @@ +package com.funeat.auth.dto; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class KakaoUserInfoDto { + + private final Long id; + private final KakaoAccount kakaoAccount; + + @JsonCreator + public KakaoUserInfoDto(@JsonProperty("id") final Long id, + @JsonProperty("kakao_account") final KakaoAccount kakaoAccount) { + this.id = id; + this.kakaoAccount = kakaoAccount; + } + + public Long getId() { + return id; + } + + public KakaoAccount getKakaoAccount() { + return kakaoAccount; + } + + public static class KakaoAccount { + + private final KakaoProfile profile; + + @JsonCreator + public KakaoAccount(@JsonProperty("profile") final KakaoProfile profile) { + this.profile = profile; + } + + public KakaoProfile getProfile() { + return profile; + } + } + + public static class KakaoProfile { + + private final String nickname; + private final String profileImageUrl; + + @JsonCreator + public KakaoProfile( + @JsonProperty("nickname") final String nickname, + @JsonProperty("profile_image_url") final String profileImageUrl) { + this.nickname = nickname; + this.profileImageUrl = profileImageUrl; + } + + public String getNickname() { + return nickname; + } + + public String getProfileImageUrl() { + return profileImageUrl; + } + } +} diff --git a/backend/src/main/java/com/funeat/auth/dto/LoginRequest.java b/backend/src/main/java/com/funeat/auth/dto/LoginRequest.java new file mode 100644 index 000000000..0479c3932 --- /dev/null +++ b/backend/src/main/java/com/funeat/auth/dto/LoginRequest.java @@ -0,0 +1,14 @@ +package com.funeat.auth.dto; + +public class LoginRequest { + + private final Long id; + + public LoginRequest(final Long id) { + this.id = id; + } + + public Long getId() { + return id; + } +} diff --git a/backend/src/main/java/com/funeat/auth/dto/SignUserDto.java b/backend/src/main/java/com/funeat/auth/dto/SignUserDto.java new file mode 100644 index 000000000..170ef9591 --- /dev/null +++ b/backend/src/main/java/com/funeat/auth/dto/SignUserDto.java @@ -0,0 +1,26 @@ +package com.funeat.auth.dto; + +import com.funeat.member.domain.Member; + +public class SignUserDto { + + private final boolean isSignIn; + private final Member member; + + public SignUserDto(final boolean isSignIn, final Member member) { + this.isSignIn = isSignIn; + this.member = member; + } + + public static SignUserDto of(final boolean isSignIn, final Member member) { + return new SignUserDto(isSignIn, member); + } + + public boolean isSignIn() { + return isSignIn; + } + + public Member getMember() { + return member; + } +} diff --git a/backend/src/main/java/com/funeat/auth/dto/TokenResponse.java b/backend/src/main/java/com/funeat/auth/dto/TokenResponse.java new file mode 100644 index 000000000..842cea22b --- /dev/null +++ b/backend/src/main/java/com/funeat/auth/dto/TokenResponse.java @@ -0,0 +1,14 @@ +package com.funeat.auth.dto; + +public class TokenResponse { + + private String accessToken; + + public TokenResponse(final String accessToken) { + this.accessToken = accessToken; + } + + public String getAccessToken() { + return accessToken; + } +} diff --git a/backend/src/main/java/com/funeat/auth/dto/UserInfoDto.java b/backend/src/main/java/com/funeat/auth/dto/UserInfoDto.java new file mode 100644 index 000000000..3861eac64 --- /dev/null +++ b/backend/src/main/java/com/funeat/auth/dto/UserInfoDto.java @@ -0,0 +1,40 @@ +package com.funeat.auth.dto; + +import com.funeat.member.domain.Member; + +public class UserInfoDto { + + private final Long id; + private final String nickname; + private final String profileImageUrl; + + public UserInfoDto(final Long id, final String nickname, final String profileImageUrl) { + this.id = id; + this.nickname = nickname; + this.profileImageUrl = profileImageUrl; + } + + public static UserInfoDto from(final KakaoUserInfoDto kakaoUserInfoDto) { + return new UserInfoDto( + kakaoUserInfoDto.getId(), + kakaoUserInfoDto.getKakaoAccount().getProfile().getNickname(), + kakaoUserInfoDto.getKakaoAccount().getProfile().getProfileImageUrl() + ); + } + + public Member toMember() { + return new Member(this.nickname, this.profileImageUrl, this.id.toString()); + } + + public Long getId() { + return id; + } + + public String getNickname() { + return nickname; + } + + public String getProfileImageUrl() { + return profileImageUrl; + } +} diff --git a/backend/src/main/java/com/funeat/auth/presentation/AuthController.java b/backend/src/main/java/com/funeat/auth/presentation/AuthController.java new file mode 100644 index 000000000..21de92552 --- /dev/null +++ b/backend/src/main/java/com/funeat/auth/presentation/AuthController.java @@ -0,0 +1,55 @@ +package com.funeat.auth.presentation; + +import com.funeat.auth.application.AuthService; +import com.funeat.auth.dto.LoginRequest; +import com.funeat.auth.dto.SignUserDto; +import com.funeat.auth.util.AuthenticationPrincipal; +import java.net.URI; +import javax.servlet.http.HttpServletRequest; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class AuthController { + + private final AuthService authService; + + public AuthController(final AuthService authService) { + this.authService = authService; + } + + @GetMapping("/api/auth/kakao") + public ResponseEntity kakaoLogin() { + return ResponseEntity.status(HttpStatus.FOUND) + .location(URI.create(authService.getLoginRedirectUri())) + .build(); + } + + @GetMapping("/login/oauth2/code/kakao") + public ResponseEntity loginAuthorizeUser(@RequestParam("code") final String code, + final HttpServletRequest request) { + final SignUserDto signUserDto = authService.loginWithKakao(code); + final Long memberId = signUserDto.getMember().getId(); + request.getSession().setAttribute("member", memberId); + + if (signUserDto.isSignIn()) { + return ResponseEntity.status(HttpStatus.FOUND) + .location(URI.create("/")) + .build(); + } + return ResponseEntity.status(HttpStatus.FOUND) + .location(URI.create("/profile")) + .build(); + } + + @GetMapping("/api/logout") + public ResponseEntity logout(@AuthenticationPrincipal final LoginRequest loginRequest, + final HttpServletRequest request) { + request.getSession().removeAttribute("member"); + + return ResponseEntity.ok().build(); + } +} diff --git a/backend/src/main/java/com/funeat/auth/util/AuthArgumentResolver.java b/backend/src/main/java/com/funeat/auth/util/AuthArgumentResolver.java new file mode 100644 index 000000000..fe7ed3628 --- /dev/null +++ b/backend/src/main/java/com/funeat/auth/util/AuthArgumentResolver.java @@ -0,0 +1,31 @@ +package com.funeat.auth.util; + +import com.funeat.auth.dto.LoginRequest; +import java.util.Objects; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import org.springframework.core.MethodParameter; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +@Component +public class AuthArgumentResolver implements HandlerMethodArgumentResolver { + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return parameter.hasParameterAnnotation(AuthenticationPrincipal.class); + } + + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { + final HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); + final HttpSession session = Objects.requireNonNull(request).getSession(); + final String id = String.valueOf(session.getAttribute("member")); + + return new LoginRequest(Long.valueOf(id)); + } +} diff --git a/backend/src/main/java/com/funeat/auth/util/AuthHandlerInterceptor.java b/backend/src/main/java/com/funeat/auth/util/AuthHandlerInterceptor.java new file mode 100644 index 000000000..1f68a9e02 --- /dev/null +++ b/backend/src/main/java/com/funeat/auth/util/AuthHandlerInterceptor.java @@ -0,0 +1,20 @@ +package com.funeat.auth.util; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +@Component +public class AuthHandlerInterceptor implements HandlerInterceptor { + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + final HttpSession session = request.getSession(); + if (session.getAttribute("member") == null) { + throw new IllegalArgumentException("login error"); + } + return true; + } +} diff --git a/backend/src/main/java/com/funeat/auth/util/AuthenticationPrincipal.java b/backend/src/main/java/com/funeat/auth/util/AuthenticationPrincipal.java new file mode 100644 index 000000000..a7c0b0cdc --- /dev/null +++ b/backend/src/main/java/com/funeat/auth/util/AuthenticationPrincipal.java @@ -0,0 +1,11 @@ +package com.funeat.auth.util; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface AuthenticationPrincipal { +} diff --git a/backend/src/main/java/com/funeat/auth/util/KakaoPlatformUserProvider.java b/backend/src/main/java/com/funeat/auth/util/KakaoPlatformUserProvider.java new file mode 100644 index 000000000..17f3b7065 --- /dev/null +++ b/backend/src/main/java/com/funeat/auth/util/KakaoPlatformUserProvider.java @@ -0,0 +1,122 @@ +package com.funeat.auth.util; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.funeat.auth.dto.KakaoTokenDto; +import com.funeat.auth.dto.KakaoUserInfoDto; +import com.funeat.auth.dto.UserInfoDto; +import java.util.StringJoiner; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Profile; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +@Component +@Profile("!test") +public class KakaoPlatformUserProvider implements PlatformUserProvider { + + private static final String AUTHORIZATION_BASE_URL = "https://kauth.kakao.com"; + private static final String RESOURCE_BASE_URL = "https://kapi.kakao.com"; + private static final String ACCESS_TOKEN_URI = "/oauth/token"; + private static final String USER_INFO_URI = "/v2/user/me"; + private static final String AUTHORIZATION_CODE = "authorization_code"; + + private final RestTemplate restTemplate; + private final ObjectMapper objectMapper; + private final String kakaoRestApiKey; + private final String redirectUri; + + public KakaoPlatformUserProvider(final RestTemplateBuilder restTemplateBuilder, + final ObjectMapper objectMapper, + @Value("${kakao.rest-api-key}") final String kakaoRestApiKey, + @Value("${kakao.redirect-uri}") final String redirectUri) { + this.restTemplate = restTemplateBuilder.build(); + this.objectMapper = objectMapper; + this.kakaoRestApiKey = kakaoRestApiKey; + this.redirectUri = redirectUri; + } + + public UserInfoDto getPlatformUser(final String code) { + final KakaoTokenDto accessTokenDto = findAccessToken(code); + final KakaoUserInfoDto kakaoUserInfoDto = findKakaoUserInfo(accessTokenDto.getAccessToken()); + return UserInfoDto.from(kakaoUserInfoDto); + } + + private KakaoTokenDto findAccessToken(final String code) { + final ResponseEntity response = requestAccessToken(code); + validateResponse(response, HttpStatus.OK); + return convertJsonToKakaoTokenDto(response.getBody()); + } + + private ResponseEntity requestAccessToken(final String code) { + final HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + + final MultiValueMap body = new LinkedMultiValueMap<>(); + body.add("grant_type", AUTHORIZATION_CODE); + body.add("client_id", kakaoRestApiKey); + body.add("redirect_uri", redirectUri); + body.add("code", code); + + final HttpEntity> request = new HttpEntity<>(body, headers); + final ResponseEntity response = restTemplate.postForEntity(AUTHORIZATION_BASE_URL + ACCESS_TOKEN_URI, + request, String.class); + + return response; + } + + private void validateResponse(final ResponseEntity response, final HttpStatus status) { + if (response.getStatusCode() != status) { + throw new IllegalArgumentException(); + } + } + + private KakaoTokenDto convertJsonToKakaoTokenDto(final String responseBody) { + try { + return objectMapper.readValue(responseBody, KakaoTokenDto.class); + } catch (final JsonProcessingException e) { + throw new IllegalArgumentException(); + } + } + + private KakaoUserInfoDto findKakaoUserInfo(final String accessToken) { + final ResponseEntity response = requestKakaoUserInfo(accessToken); + validateResponse(response, HttpStatus.OK); + return convertJsonToKakaoUserDto(response.getBody()); + } + + private ResponseEntity requestKakaoUserInfo(final String accessToken) { + final HttpHeaders headers = new HttpHeaders(); + headers.setBearerAuth(accessToken); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + + final HttpEntity> request = new HttpEntity<>(null, headers); + return restTemplate.postForEntity(RESOURCE_BASE_URL + USER_INFO_URI, request, String.class); + } + + private KakaoUserInfoDto convertJsonToKakaoUserDto(final String responseBody) { + try { + return objectMapper.readValue(responseBody, KakaoUserInfoDto.class); + } catch (final JsonProcessingException e) { + throw new IllegalArgumentException(); + } + } + + @Override + public String getRedirectURI() { + final StringJoiner joiner = new StringJoiner("&"); + joiner.add("response_type=code"); + joiner.add("client_id=" + kakaoRestApiKey); + joiner.add("redirect_uri=" + redirectUri); + + return AUTHORIZATION_BASE_URL + "?" + joiner; + } +} diff --git a/backend/src/main/java/com/funeat/auth/util/PlatformUserProvider.java b/backend/src/main/java/com/funeat/auth/util/PlatformUserProvider.java new file mode 100644 index 000000000..2d77b4411 --- /dev/null +++ b/backend/src/main/java/com/funeat/auth/util/PlatformUserProvider.java @@ -0,0 +1,10 @@ +package com.funeat.auth.util; + +import com.funeat.auth.dto.UserInfoDto; + +public interface PlatformUserProvider { + + UserInfoDto getPlatformUser(final String code); + + String getRedirectURI(); +} diff --git a/backend/src/main/java/com/funeat/common/WebConfig.java b/backend/src/main/java/com/funeat/common/WebConfig.java index 4ef4cb3d4..b72556759 100644 --- a/backend/src/main/java/com/funeat/common/WebConfig.java +++ b/backend/src/main/java/com/funeat/common/WebConfig.java @@ -1,5 +1,6 @@ package com.funeat.common; +import com.funeat.auth.util.AuthArgumentResolver; import java.util.List; import org.springframework.context.annotation.Configuration; import org.springframework.format.FormatterRegistry; @@ -10,9 +11,12 @@ public class WebConfig implements WebMvcConfigurer { private final CustomPageableHandlerMethodArgumentResolver customPageableHandlerMethodArgumentResolver; + private final AuthArgumentResolver authArgumentResolver; - public WebConfig(final CustomPageableHandlerMethodArgumentResolver customPageableHandlerMethodArgumentResolver) { + public WebConfig(final CustomPageableHandlerMethodArgumentResolver customPageableHandlerMethodArgumentResolver, + final AuthArgumentResolver authArgumentResolver) { this.customPageableHandlerMethodArgumentResolver = customPageableHandlerMethodArgumentResolver; + this.authArgumentResolver = authArgumentResolver; } @Override @@ -23,5 +27,6 @@ public void addFormatters(final FormatterRegistry registry) { @Override public void addArgumentResolvers(List resolvers) { resolvers.add(customPageableHandlerMethodArgumentResolver); + resolvers.add(authArgumentResolver); } } diff --git a/backend/src/main/java/com/funeat/member/application/MemberService.java b/backend/src/main/java/com/funeat/member/application/MemberService.java new file mode 100644 index 000000000..b1d55931a --- /dev/null +++ b/backend/src/main/java/com/funeat/member/application/MemberService.java @@ -0,0 +1,35 @@ +package com.funeat.member.application; + +import com.funeat.auth.dto.SignUserDto; +import com.funeat.auth.dto.UserInfoDto; +import com.funeat.member.domain.Member; +import com.funeat.member.persistence.MemberRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +public class MemberService { + + private final MemberRepository memberRepository; + + public MemberService(final MemberRepository memberRepository) { + this.memberRepository = memberRepository; + } + + public SignUserDto findOrCreateMember(final UserInfoDto userInfoDto) { + final String platformId = userInfoDto.getId().toString(); + + return memberRepository.findByPlatformId(platformId) + .map(member -> SignUserDto.of(false, member)) + .orElseGet(() -> save(userInfoDto)); + } + + @Transactional + public SignUserDto save(final UserInfoDto userInfoDto) { + final Member member = userInfoDto.toMember(); + memberRepository.save(member); + + return SignUserDto.of(true, member); + } +} diff --git a/backend/src/main/java/com/funeat/member/domain/Member.java b/backend/src/main/java/com/funeat/member/domain/Member.java index 7ab8a8746..94d5b28a7 100644 --- a/backend/src/main/java/com/funeat/member/domain/Member.java +++ b/backend/src/main/java/com/funeat/member/domain/Member.java @@ -23,6 +23,8 @@ public class Member { private String profileImage; + private String platformId; + @OneToMany(mappedBy = "member") private List reviewFavorites = new ArrayList<>(); @@ -38,9 +40,10 @@ public class Member { protected Member() { } - public Member(final String nickName, final String profileImage) { - this.nickname = nickName; + public Member(final String nickname, final String profileImage, final String platformId) { + this.nickname = nickname; this.profileImage = profileImage; + this.platformId = platformId; } public Long getId() { @@ -55,6 +58,10 @@ public String getProfileImage() { return profileImage; } + public String getPlatformId() { + return platformId; + } + public List getReviewFavorites() { return reviewFavorites; } diff --git a/backend/src/main/java/com/funeat/member/persistence/MemberRepository.java b/backend/src/main/java/com/funeat/member/persistence/MemberRepository.java index 4bad6f3fd..832c48a38 100644 --- a/backend/src/main/java/com/funeat/member/persistence/MemberRepository.java +++ b/backend/src/main/java/com/funeat/member/persistence/MemberRepository.java @@ -1,7 +1,10 @@ package com.funeat.member.persistence; import com.funeat.member.domain.Member; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; public interface MemberRepository extends JpaRepository { + + Optional findByPlatformId(final String platformId); } diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 27bdd3448..77e3c0520 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -7,3 +7,7 @@ springdoc: path: /funeat-api enabled: true tags-sorter: alpha + +kakao: + rest-api-key: { REST_API_KEY } + redirect-uri: { REDIRECT_URI } diff --git a/backend/src/test/java/com/funeat/acceptance/auth/AuthAcceptanceTest.java b/backend/src/test/java/com/funeat/acceptance/auth/AuthAcceptanceTest.java new file mode 100644 index 000000000..32667362d --- /dev/null +++ b/backend/src/test/java/com/funeat/acceptance/auth/AuthAcceptanceTest.java @@ -0,0 +1,40 @@ +package com.funeat.acceptance.auth; + +import static io.restassured.RestAssured.given; +import static org.assertj.core.api.Assertions.assertThat; + +import com.funeat.acceptance.common.AcceptanceTest; +import com.funeat.auth.application.AuthService; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +@SuppressWarnings("NonAsciiCharacters") +public class AuthAcceptanceTest extends AcceptanceTest { + + @Autowired + private AuthService authService; + + @Test + void 유저가_카카오_로그인_버튼을_누르면_카카오_로그인_페이지로_리다이렉트할_수_있다() { + // given + final var response = 카카오_로그인_버튼_클릭(); + final var expected = authService.getLoginRedirectUri(); + + // when + final String actual = response.header("Location"); + + // then + assertThat(actual).isEqualTo(expected); + } + + private ExtractableResponse 카카오_로그인_버튼_클릭() { + return given() + .redirects().follow(false) + .when() + .get("/api/auth/kakao") + .then() + .extract(); + } +} diff --git a/backend/src/test/java/com/funeat/acceptance/common/LoginSteps.java b/backend/src/test/java/com/funeat/acceptance/common/LoginSteps.java new file mode 100644 index 000000000..f97507e3d --- /dev/null +++ b/backend/src/test/java/com/funeat/acceptance/common/LoginSteps.java @@ -0,0 +1,21 @@ +package com.funeat.acceptance.common; + +import io.restassured.RestAssured; +import io.restassured.http.Cookies; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; + +@SuppressWarnings("NonAsciiCharacters") +public class LoginSteps { + + public static Cookies 로그인_쿠키를_얻는다() { + final ExtractableResponse response = RestAssured.given() + .queryParam("code", "test") + .when() + .get("/login/oauth2/code/kakao") + .then() + .extract(); + + return response.detailedCookies(); + } +} diff --git a/backend/src/test/java/com/funeat/acceptance/common/TestPlatformUserProvider.java b/backend/src/test/java/com/funeat/acceptance/common/TestPlatformUserProvider.java new file mode 100644 index 000000000..20b041e2b --- /dev/null +++ b/backend/src/test/java/com/funeat/acceptance/common/TestPlatformUserProvider.java @@ -0,0 +1,21 @@ +package com.funeat.acceptance.common; + +import com.funeat.auth.dto.UserInfoDto; +import com.funeat.auth.util.PlatformUserProvider; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +@Component +@Profile("test") +public class TestPlatformUserProvider implements PlatformUserProvider { + + @Override + public UserInfoDto getPlatformUser(final String code) { + return new UserInfoDto(1L, "test", "https://www.test.com"); + } + + @Override + public String getRedirectURI() { + return "https://www.test.com"; + } +} diff --git a/backend/src/test/java/com/funeat/acceptance/product/ProductAcceptanceTest.java b/backend/src/test/java/com/funeat/acceptance/product/ProductAcceptanceTest.java index 3356a2426..3cc9d47ca 100644 --- a/backend/src/test/java/com/funeat/acceptance/product/ProductAcceptanceTest.java +++ b/backend/src/test/java/com/funeat/acceptance/product/ProductAcceptanceTest.java @@ -305,7 +305,7 @@ class 리뷰수_기준_내림차순으로_카테고리별_상품_목록_조회 { final List products = List.of(product1, product2, product3); 복수_상품_추가_요청(products); - Member member = 멤버_추가_요청(new Member("test", "image.png")); + Member member = 멤버_추가_요청(new Member("test", "image.png", "1")); final Review review1_1 = new Review(member, product1, "review.png", 3L, "이 삼각김밥은 맛있다", true); final Review review1_2 = new Review(member, product1, "review.png", 3L, "이 삼각김밥은 맛있다", true); final Review review1_3 = new Review(member, product1, "review.png", 4L, "이 삼각김밥은 좀 맛있다", true); @@ -341,7 +341,7 @@ class 리뷰수_기준_내림차순으로_카테고리별_상품_목록_조회 { final List products = List.of(product1, product2, product3, product4, product5); 복수_상품_추가_요청(products); - final Member member = 멤버_추가_요청(new Member("test", "image.png")); + final Member member = 멤버_추가_요청(new Member("test", "image.png", "1")); final Review review1_1 = new Review(member, product1, "review.png", 3L, "이 삼각김밥은 맛있다", true); final Review review1_2 = new Review(member, product1, "review.png", 3L, "이 삼각김밥은 맛있다", true); final Review review1_3 = new Review(member, product1, "review.png", 4L, "이 삼각김밥은 좀 맛있다", true); @@ -429,7 +429,7 @@ class 리뷰수_기준_내림차순으로_카테고리별_상품_목록_조회 { } private Long 기본_멤버_추가_요청() { - final Member testMember = memberRepository.save(new Member("test", "image.png")); + final Member testMember = memberRepository.save(new Member("test", "image.png", "1")); return testMember.getId(); } diff --git a/backend/src/test/java/com/funeat/acceptance/review/ReviewAcceptanceTest.java b/backend/src/test/java/com/funeat/acceptance/review/ReviewAcceptanceTest.java index 33334a2bc..a06c66994 100644 --- a/backend/src/test/java/com/funeat/acceptance/review/ReviewAcceptanceTest.java +++ b/backend/src/test/java/com/funeat/acceptance/review/ReviewAcceptanceTest.java @@ -119,7 +119,7 @@ class ReviewAcceptanceTest extends AcceptanceTest { } private Long 멤버_추가_요청() { - final Member testMember = memberRepository.save(new Member("test", "image.png")); + final Member testMember = memberRepository.save(new Member("test", "image.png", "1")); return testMember.getId(); } @@ -133,9 +133,9 @@ class 좋아요_기준_내림차순으로_리뷰_목록_조회 { final var category = new Category("간편식사", CategoryType.FOOD); 카테고리_추가_요청(category); - final var member1 = new Member("test1", "test1.png"); - final var member2 = new Member("test2", "test2.png"); - final var member3 = new Member("test3", "test3.png"); + final var member1 = new Member("test1", "test1.png", "1"); + final var member2 = new Member("test2", "test2.png", "2'"); + final var member3 = new Member("test3", "test3.png", "3'"); final var members = List.of(member1, member2, member3); 복수_유저_추가_요청(members); @@ -165,10 +165,10 @@ class 좋아요_기준_내림차순으로_리뷰_목록_조회 { final var category = new Category("간편식사", CategoryType.FOOD); 카테고리_추가_요청(category); - final var member1 = new Member("test1", "test1.png"); - final var member2 = new Member("test2", "test2.png"); - final var member3 = new Member("test3", "test3.png"); - final var member4 = new Member("test4", "test4.png"); + final var member1 = new Member("test1", "test1.png", "1"); + final var member2 = new Member("test2", "test2.png", "2"); + final var member3 = new Member("test3", "test3.png", "3"); + final var member4 = new Member("test4", "test4.png", "4"); final var members = List.of(member1, member2, member3, member4); 복수_유저_추가_요청(members); @@ -203,9 +203,9 @@ class 평점_기준_오름차순으로_리뷰_목록을_조회 { final var category = new Category("간편식사", CategoryType.FOOD); 카테고리_추가_요청(category); - final var member1 = new Member("test1", "test1.png"); - final var member2 = new Member("test2", "test2.png"); - final var member3 = new Member("test3", "test3.png"); + final var member1 = new Member("test1", "test1.png", "1"); + final var member2 = new Member("test2", "test2.png", "2"); + final var member3 = new Member("test3", "test3.png", "3"); final var members = List.of(member1, member2, member3); 복수_유저_추가_요청(members); @@ -235,10 +235,10 @@ class 평점_기준_오름차순으로_리뷰_목록을_조회 { final var category = new Category("간편식사", CategoryType.FOOD); 카테고리_추가_요청(category); - final var member1 = new Member("test1", "test1.png"); - final var member2 = new Member("test2", "test2.png"); - final var member3 = new Member("test3", "test3.png"); - final var member4 = new Member("test4", "test4.png"); + final var member1 = new Member("test1", "test1.png", "1"); + final var member2 = new Member("test2", "test2.png", "2"); + final var member3 = new Member("test3", "test3.png", "3"); + final var member4 = new Member("test4", "test4.png", "4"); final var members = List.of(member1, member2, member3, member4); 복수_유저_추가_요청(members); @@ -273,9 +273,9 @@ class 평점_기준_내림차순으로_리뷰_목록_조회 { final var category = new Category("간편식사", CategoryType.FOOD); 카테고리_추가_요청(category); - final var member1 = new Member("test1", "test1.png"); - final var member2 = new Member("test2", "test2.png"); - final var member3 = new Member("test3", "test3.png"); + final var member1 = new Member("test1", "test1.png", "1"); + final var member2 = new Member("test2", "test2.png", "2"); + final var member3 = new Member("test3", "test3.png", "3"); final var members = List.of(member1, member2, member3); 복수_유저_추가_요청(members); @@ -305,10 +305,10 @@ class 평점_기준_내림차순으로_리뷰_목록_조회 { final var category = new Category("간편식사", CategoryType.FOOD); 카테고리_추가_요청(category); - final var member1 = new Member("test1", "test1.png"); - final var member2 = new Member("test2", "test2.png"); - final var member3 = new Member("test3", "test3.png"); - final var member4 = new Member("test4", "test4.png"); + final var member1 = new Member("test1", "test1.png", "1"); + final var member2 = new Member("test2", "test2.png", "2"); + final var member3 = new Member("test3", "test3.png", "3"); + final var member4 = new Member("test4", "test4.png", "4"); final var members = List.of(member1, member2, member3, member4); 복수_유저_추가_요청(members); @@ -340,9 +340,9 @@ class 평점_기준_내림차순으로_리뷰_목록_조회 { final var category = new Category("간편식사", CategoryType.FOOD); 카테고리_추가_요청(category); - final var member1 = new Member("test1", "test1.png"); - final var member2 = new Member("test2", "test2.png"); - final var member3 = new Member("test3", "test3.png"); + final var member1 = new Member("test1", "test1.png", "1"); + final var member2 = new Member("test2", "test2.png", "2"); + final var member3 = new Member("test3", "test3.png", "3"); final var members = List.of(member1, member2, member3); 복수_유저_추가_요청(members); diff --git a/backend/src/test/java/com/funeat/auth/application/AuthServiceTest.java b/backend/src/test/java/com/funeat/auth/application/AuthServiceTest.java new file mode 100644 index 000000000..3e74d9bf4 --- /dev/null +++ b/backend/src/test/java/com/funeat/auth/application/AuthServiceTest.java @@ -0,0 +1,41 @@ +package com.funeat.auth.application; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.funeat.auth.dto.SignUserDto; +import com.funeat.common.DataClearExtension; +import com.funeat.member.domain.Member; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; + +@Transactional +@SpringBootTest +@ExtendWith(DataClearExtension.class) +@SuppressWarnings("NonAsciiCharacters") +@DisplayNameGeneration(ReplaceUnderscores.class) +public class AuthServiceTest { + + @Autowired + private AuthService authService; + + @Test + void 카카오_로그인을_하여_유저_정보를_가져온다() { + // given + final var code = "test"; + final var member = new Member("test", "https://www.test.com", "1"); + final var expected = SignUserDto.of(true, member); + + // when + final var actual = authService.loginWithKakao(code); + + // then + assertThat(actual).usingRecursiveComparison() + .ignoringFields("member.id") + .isEqualTo(expected); + } +} diff --git a/backend/src/test/java/com/funeat/auth/presentation/AuthControllerTest.java b/backend/src/test/java/com/funeat/auth/presentation/AuthControllerTest.java new file mode 100644 index 000000000..cac2b8879 --- /dev/null +++ b/backend/src/test/java/com/funeat/auth/presentation/AuthControllerTest.java @@ -0,0 +1,65 @@ +package com.funeat.auth.presentation; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.funeat.auth.application.AuthService; +import com.funeat.auth.dto.SignUserDto; +import com.funeat.member.domain.Member; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +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; + +@WebMvcTest(AuthController.class) +@SuppressWarnings("NonAsciiCharacters") +public class AuthControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private AuthService authService; + + @Nested + class loginAuthorizeUser_테스트 { + + @Test + void 이미_가입된_유저라면_홈_경로로_리다이렉트한다() throws Exception { + // given + final var code = "test"; + final var member = new Member("test", "www.test.com", "1"); + final var signUserDto = SignUserDto.of(true, member); + + // when + when(authService.loginWithKakao(code)).thenReturn(signUserDto); + + // then + mockMvc.perform(get("/login/oauth2/code/kakao") + .param("code", code)) + .andExpect(status().isFound()) + .andExpect(redirectedUrl("/")); + } + + @Test + void 가입되지_않은_유저라면_프로필_경로로_리다이렉트한다() throws Exception { + // given + final var code = "test"; + final var member = new Member("test", "www.test.com", "1"); + final var signUserDto = SignUserDto.of(false, member); + + // when + when(authService.loginWithKakao(code)).thenReturn(signUserDto); + + // then + mockMvc.perform(get("/login/oauth2/code/kakao") + .param("code", code)) + .andExpect(status().isFound()) + .andExpect(redirectedUrl("/profile")); + } + } +} diff --git a/backend/src/test/java/com/funeat/member/application/MemberServiceTest.java b/backend/src/test/java/com/funeat/member/application/MemberServiceTest.java new file mode 100644 index 000000000..65967f853 --- /dev/null +++ b/backend/src/test/java/com/funeat/member/application/MemberServiceTest.java @@ -0,0 +1,74 @@ +package com.funeat.member.application; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.funeat.auth.dto.UserInfoDto; +import com.funeat.common.DataClearExtension; +import com.funeat.member.domain.Member; +import com.funeat.member.persistence.MemberRepository; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; + +@Transactional +@SpringBootTest +@ExtendWith(DataClearExtension.class) +@SuppressWarnings("NonAsciiCharacters") +@DisplayNameGeneration(ReplaceUnderscores.class) +class MemberServiceTest { + + @Autowired + private MemberService memberService; + + @Autowired + private MemberRepository memberRepository; + + @Nested + class findOrCreateMember_테스트 { + + @Test + void 이미_가입된_사용자면_가입하지_않고_반환한다() { + // given + final var member = new Member("test", "www.test.com", "1"); + memberRepository.save(member); + + final var userInfoDto = new UserInfoDto(1L, "test", "www.test.com"); + final var expected = memberRepository.findAll(); + + // when + final var actual = memberService.findOrCreateMember(userInfoDto); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + Assertions.assertFalse(actual.isSignIn()); + assertThat(expected).containsExactly(actual.getMember()); + }); + } + + @Test + void 가입되지_않은_사용자면_가입하고_반환하다() { + // given + final var member = new Member("test", "www.test.com", "1"); + memberRepository.save(member); + + final var userInfoDto = new UserInfoDto(2L, "test", "www.test.com"); + final var expected = memberRepository.findAll(); + + // when + final var actual = memberService.findOrCreateMember(userInfoDto); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + Assertions.assertTrue(actual.isSignIn()); + assertThat(expected).doesNotContain(actual.getMember()); + }); + } + } +} diff --git a/backend/src/test/java/com/funeat/member/persistence/MemberRepositoryTest.java b/backend/src/test/java/com/funeat/member/persistence/MemberRepositoryTest.java new file mode 100644 index 000000000..5e475cbdf --- /dev/null +++ b/backend/src/test/java/com/funeat/member/persistence/MemberRepositoryTest.java @@ -0,0 +1,39 @@ +package com.funeat.member.persistence; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.funeat.common.DataCleaner; +import com.funeat.common.DataClearExtension; +import com.funeat.member.domain.Member; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +@DataJpaTest +@Import(DataCleaner.class) +@ExtendWith(DataClearExtension.class) +@SuppressWarnings("NonAsciiCharacters") +@DisplayNameGeneration(ReplaceUnderscores.class) +public class MemberRepositoryTest { + + @Autowired + private MemberRepository memberRepository; + + @Test + void platform_id를_통해_유저를_반환한다() { + // given + final var platformId = "1234"; + final var member = new Member("test", "www.test.com", platformId); + memberRepository.save(member); + + // when + final var actual = memberRepository.findByPlatformId(platformId).get(); + + // then + assertThat(actual).usingRecursiveComparison().isEqualTo(member); + } +} diff --git a/backend/src/test/java/com/funeat/member/persistence/ReviewFavoriteRepositoryTest.java b/backend/src/test/java/com/funeat/member/persistence/ReviewFavoriteRepositoryTest.java index cf396b140..c27671838 100644 --- a/backend/src/test/java/com/funeat/member/persistence/ReviewFavoriteRepositoryTest.java +++ b/backend/src/test/java/com/funeat/member/persistence/ReviewFavoriteRepositoryTest.java @@ -61,7 +61,7 @@ class ReviewFavoriteRepositoryTest { } private Member 멤버_추가_요청() { - return memberRepository.save(new Member("test", "image.png")); + return memberRepository.save(new Member("test", "image.png", "1")); } private Product 상품_추가_요청() { diff --git a/backend/src/test/java/com/funeat/product/persistence/ProductRepositoryTest.java b/backend/src/test/java/com/funeat/product/persistence/ProductRepositoryTest.java index e19b04a7d..a3f38fb97 100644 --- a/backend/src/test/java/com/funeat/product/persistence/ProductRepositoryTest.java +++ b/backend/src/test/java/com/funeat/product/persistence/ProductRepositoryTest.java @@ -158,7 +158,7 @@ class ProductRepositoryTest { productRepository.saveAll( List.of(product1, product2, product3, product4, product5)); - final var member = memberRepository.save(new Member("test", "image.png")); + final var member = memberRepository.save(new Member("test", "image.png", "1")); final var review1_1 = new Review(member, product1, "review.png", 5L, "이 삼각김밥은 최고!!", true); final var review1_2 = new Review(member, product1, "review.png", 4L, "이 삼각김밥은 좀 맛있다", true); diff --git a/backend/src/test/java/com/funeat/review/application/ReviewServiceTest.java b/backend/src/test/java/com/funeat/review/application/ReviewServiceTest.java index 0957277bd..8efa7dad2 100644 --- a/backend/src/test/java/com/funeat/review/application/ReviewServiceTest.java +++ b/backend/src/test/java/com/funeat/review/application/ReviewServiceTest.java @@ -178,7 +178,7 @@ void init() { } private Member 멤버_추가_요청() { - return memberRepository.save(new Member("test", "image.png")); + return memberRepository.save(new Member("test", "image.png", "1")); } @Nested @@ -187,9 +187,9 @@ class sortingReviews_페이징_테스트 { @Test void 좋아요_기준으로_내림차순_정렬을_할_수_있다() { // given - final var member1 = new Member("test1", "test1.png"); - final var member2 = new Member("test2", "test2.png"); - final var member3 = new Member("test3", "test3.png"); + final var member1 = new Member("test1", "test1.png", "1"); + final var member2 = new Member("test2", "test2.png", "2"); + final var member3 = new Member("test3", "test3.png", "3"); final var members = List.of(member1, member2, member3); 복수_유저_추가(members); @@ -218,9 +218,9 @@ class sortingReviews_페이징_테스트 { @Test void 평점_기준으로_오름차순_정렬을_할_수_있다() { // given - final var member1 = new Member("test1", "test1.png"); - final var member2 = new Member("test2", "test2.png"); - final var member3 = new Member("test3", "test3.png"); + final var member1 = new Member("test1", "test1.png", "1"); + final var member2 = new Member("test2", "test2.png", "2"); + final var member3 = new Member("test3", "test3.png", "3"); final var members = List.of(member1, member2, member3); 복수_유저_추가(members); @@ -249,9 +249,9 @@ class sortingReviews_페이징_테스트 { @Test void 평점_기준으로_내림차순_정렬을_할_수_있다() { // given - final var member1 = new Member("test1", "test1.png"); - final var member2 = new Member("test2", "test2.png"); - final var member3 = new Member("test3", "test3.png"); + final var member1 = new Member("test1", "test1.png", "1"); + final var member2 = new Member("test2", "test2.png", "2"); + final var member3 = new Member("test3", "test3.png", "3"); final var members = List.of(member1, member2, member3); 복수_유저_추가(members); diff --git a/backend/src/test/java/com/funeat/review/persistence/ReviewRepositoryTest.java b/backend/src/test/java/com/funeat/review/persistence/ReviewRepositoryTest.java index f47f9d3d8..b642db9f7 100644 --- a/backend/src/test/java/com/funeat/review/persistence/ReviewRepositoryTest.java +++ b/backend/src/test/java/com/funeat/review/persistence/ReviewRepositoryTest.java @@ -45,7 +45,7 @@ class ReviewRepositoryTest { @Test void 상품에_달린_리뷰의_숫자를_반환한다() { // given - Member member = memberRepository.save(new Member("test", "image.png")); + Member member = memberRepository.save(new Member("test", "image.png", "1")); Category category = categoryRepository.save(new Category("간편식사", CategoryType.FOOD)); Product product1 = productRepository.save(new Product("삼각김밥", 1000L, "image.png", "맛있는 삼각김밥", category)); Product product2 = productRepository.save(new Product("라면", 2000L, "image.png", "맛있는 라면", category)); @@ -63,9 +63,9 @@ class ReviewRepositoryTest { @Test void 특정_상품에_대한_좋아요_기준_내림차순으로_정렬한다() { // given - final var member1 = new Member("test1", "test1.png"); - final var member2 = new Member("test2", "test2.png"); - final var member3 = new Member("test3", "test3.png"); + final var member1 = new Member("test1", "test1.png", "1"); + final var member2 = new Member("test2", "test2.png", "2"); + final var member3 = new Member("test3", "test3.png", "3"); final var members = List.of(member1, member2, member3); memberRepository.saveAll(members); @@ -94,9 +94,9 @@ class ReviewRepositoryTest { void 전체_리뷰_목록에서_가장_좋아요가_높은_상위_3개의_리뷰를_가져온다() { // given - final var member1 = new Member("test1", "test1.png"); - final var member2 = new Member("test2", "test2.png"); - final var member3 = new Member("test3", "test3.png"); + final var member1 = new Member("test1", "test1.png", "1"); + final var member2 = new Member("test2", "test2.png", "2"); + final var member3 = new Member("test3", "test3.png", "3"); final var members = List.of(member1, member2, member3); memberRepository.saveAll(members); diff --git a/backend/src/test/java/com/funeat/review/persistence/ReviewTagRepositoryTest.java b/backend/src/test/java/com/funeat/review/persistence/ReviewTagRepositoryTest.java index 22cf8f5b1..88cb2137a 100644 --- a/backend/src/test/java/com/funeat/review/persistence/ReviewTagRepositoryTest.java +++ b/backend/src/test/java/com/funeat/review/persistence/ReviewTagRepositoryTest.java @@ -48,7 +48,7 @@ class ReviewTagRepositoryTest { @Test void 리뷰_목록에서_상위_3개에_해당하는_태그를_조회한다() { // given - final var member = new Member("test1", "test1.png"); + final var member = new Member("test1", "test1.png", "1"); memberRepository.save(member); final var product = new Product("망고", 1_000L, "mango.png", "망고망고", null);