diff --git a/src/main/java/com/server/bbo_gak/domain/auth/controller/AuthController.java b/src/main/java/com/server/bbo_gak/domain/auth/controller/AuthController.java index d663f80..6b96021 100644 --- a/src/main/java/com/server/bbo_gak/domain/auth/controller/AuthController.java +++ b/src/main/java/com/server/bbo_gak/domain/auth/controller/AuthController.java @@ -5,7 +5,6 @@ import com.server.bbo_gak.domain.auth.dto.request.RefreshTokenRequest; import com.server.bbo_gak.domain.auth.service.AuthService; import com.server.bbo_gak.domain.auth.service.oauth.GoogleService; -import com.server.bbo_gak.domain.user.entity.OauthProvider; import com.server.bbo_gak.domain.user.entity.User; import com.server.bbo_gak.global.annotation.AuthUser; import com.server.bbo_gak.global.security.jwt.dto.TokenDto; @@ -32,7 +31,7 @@ public class AuthController { @PostMapping("/social-login") public ResponseEntity socialLogin( @RequestHeader(SOCIAL_TOKEN_NAME) final String socialAccessToken, - @RequestParam(name = "provider") OauthProvider provider + @RequestParam(name = "provider") String provider ) { LoginResponse response = authService.socialLogin(socialAccessToken, provider); //TODO: 쿠키 만들어서 헤더에 넘겨야함. diff --git a/src/main/java/com/server/bbo_gak/domain/auth/dto/response/LoginResponse.java b/src/main/java/com/server/bbo_gak/domain/auth/dto/response/LoginResponse.java index 04dcde9..1a07f9a 100644 --- a/src/main/java/com/server/bbo_gak/domain/auth/dto/response/LoginResponse.java +++ b/src/main/java/com/server/bbo_gak/domain/auth/dto/response/LoginResponse.java @@ -6,13 +6,15 @@ @Builder public record LoginResponse( String accessToken, - String refreshToken + String refreshToken, + Boolean isFirstLogin ) { - public static LoginResponse of(TokenDto tokenDto) { + public static LoginResponse of(TokenDto tokenDto, Boolean isFirstLogin) { return LoginResponse.builder() .accessToken(tokenDto.accessToken()) .refreshToken(tokenDto.refreshToken()) + .isFirstLogin(isFirstLogin) .build(); } } diff --git a/src/main/java/com/server/bbo_gak/domain/auth/service/AuthService.java b/src/main/java/com/server/bbo_gak/domain/auth/service/AuthService.java index fffa7c5..941a033 100644 --- a/src/main/java/com/server/bbo_gak/domain/auth/service/AuthService.java +++ b/src/main/java/com/server/bbo_gak/domain/auth/service/AuthService.java @@ -2,7 +2,6 @@ import com.server.bbo_gak.domain.auth.dto.request.LoginRequest; import com.server.bbo_gak.domain.auth.dto.response.LoginResponse; -import com.server.bbo_gak.domain.user.entity.OauthProvider; import com.server.bbo_gak.domain.auth.dto.request.RefreshTokenRequest; import com.server.bbo_gak.domain.user.entity.User; import com.server.bbo_gak.global.security.jwt.dto.TokenDto; @@ -11,7 +10,7 @@ @Service public interface AuthService { - LoginResponse socialLogin(String socialAccessToken, OauthProvider provider); + LoginResponse socialLogin(String socialAccessToken, String provider); TokenDto login(LoginRequest request); diff --git a/src/main/java/com/server/bbo_gak/domain/auth/service/AuthServiceImpl.java b/src/main/java/com/server/bbo_gak/domain/auth/service/AuthServiceImpl.java index c3a6293..6c0823d 100644 --- a/src/main/java/com/server/bbo_gak/domain/auth/service/AuthServiceImpl.java +++ b/src/main/java/com/server/bbo_gak/domain/auth/service/AuthServiceImpl.java @@ -7,13 +7,13 @@ import com.server.bbo_gak.domain.auth.entity.AuthTestUser; import com.server.bbo_gak.domain.auth.entity.AuthTestUserRepository; import com.server.bbo_gak.domain.auth.service.oauth.GoogleService; +import com.server.bbo_gak.domain.user.entity.Job; import com.server.bbo_gak.domain.user.entity.OauthProvider; import com.server.bbo_gak.domain.user.entity.User; import com.server.bbo_gak.domain.user.entity.UserRepository; import com.server.bbo_gak.domain.user.service.UserService; import com.server.bbo_gak.global.error.exception.BusinessException; import com.server.bbo_gak.global.error.exception.ErrorCode; -import com.server.bbo_gak.global.error.exception.InvalidValueException; import com.server.bbo_gak.global.error.exception.NotFoundException; import com.server.bbo_gak.global.security.jwt.dto.AccessTokenDto; import com.server.bbo_gak.global.security.jwt.dto.TokenDto; @@ -37,9 +37,10 @@ public class AuthServiceImpl implements AuthService { @Override @Transactional - public LoginResponse socialLogin(String socialAccessToken, OauthProvider provider) { + public LoginResponse socialLogin(String socialAccessToken, String provider) { + // accessToken으로 사용자 정보 얻어오기 - OauthUserInfoResponse oauthUserInfo = getMemberInfo(socialAccessToken, provider); + OauthUserInfoResponse oauthUserInfo = getMemberInfo(socialAccessToken, OauthProvider.findByName(provider)); // DB에서 회원 찾기 User user = userRepository.findUserByOauthInfo(oauthUserInfo.toEntity()) @@ -51,7 +52,10 @@ public LoginResponse socialLogin(String socialAccessToken, OauthProvider provide } TokenDto tokenDto = jwtTokenService.createTokenDto(user.getId(), user.getRole()); // 토큰 발급 - return LoginResponse.of(tokenDto); + // Job이 UNDEFINED인지 확인 (UNDEFINED라면 isFirstLogin 최초로그인값 true) + boolean isJobUndefined = user.getJob() == Job.UNDEFINE; + + return LoginResponse.of(tokenDto, isJobUndefined); } @Override @@ -100,7 +104,6 @@ public void logout(User user) { private OauthUserInfoResponse getMemberInfo(String socialAccessToken, OauthProvider provider) { return switch (provider) { case GOOGLE -> googleService.getOauthUserInfo(socialAccessToken); - default -> throw new InvalidValueException(ErrorCode.INVALID_PROVIDER_TYPE); }; } } diff --git a/src/main/java/com/server/bbo_gak/domain/user/controller/UserController.java b/src/main/java/com/server/bbo_gak/domain/user/controller/UserController.java index 0207c82..a9c63b3 100644 --- a/src/main/java/com/server/bbo_gak/domain/user/controller/UserController.java +++ b/src/main/java/com/server/bbo_gak/domain/user/controller/UserController.java @@ -1,9 +1,15 @@ package com.server.bbo_gak.domain.user.controller; +import com.server.bbo_gak.domain.user.dto.request.UserJobUpdateRequest; import com.server.bbo_gak.domain.user.dto.response.UserInfoResponse; +import com.server.bbo_gak.domain.user.entity.User; +import com.server.bbo_gak.domain.user.service.UserService; +import com.server.bbo_gak.global.annotation.AuthUser; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -12,10 +18,20 @@ @RequiredArgsConstructor public class UserController { + private final UserService userService; + @GetMapping("/me") public ResponseEntity memberInfo() { return ResponseEntity.ok().body(null); } + @PutMapping("/job") + public ResponseEntity updateMemberJob( + @AuthUser User user, + @RequestBody UserJobUpdateRequest request + ) { + userService.updateUserJob(user, request.job()); + return ResponseEntity.ok(null); + } } diff --git a/src/main/java/com/server/bbo_gak/domain/user/dto/request/UserJobUpdateRequest.java b/src/main/java/com/server/bbo_gak/domain/user/dto/request/UserJobUpdateRequest.java new file mode 100644 index 0000000..8991d65 --- /dev/null +++ b/src/main/java/com/server/bbo_gak/domain/user/dto/request/UserJobUpdateRequest.java @@ -0,0 +1,4 @@ +package com.server.bbo_gak.domain.user.dto.request; + +public record UserJobUpdateRequest(String job) { +} diff --git a/src/main/java/com/server/bbo_gak/domain/user/entity/Job.java b/src/main/java/com/server/bbo_gak/domain/user/entity/Job.java index b87809e..035a224 100644 --- a/src/main/java/com/server/bbo_gak/domain/user/entity/Job.java +++ b/src/main/java/com/server/bbo_gak/domain/user/entity/Job.java @@ -1,5 +1,8 @@ package com.server.bbo_gak.domain.user.entity; +import com.server.bbo_gak.global.error.exception.ErrorCode; +import com.server.bbo_gak.global.error.exception.NotFoundException; +import java.util.Arrays; import lombok.AllArgsConstructor; import lombok.Getter; @@ -8,7 +11,15 @@ public enum Job { ALL("공통"), DESIGNER("디자이너"), - DEVELOPER("개발자"); + DEVELOPER("개발자"), + UNDEFINE("미설정"); private final String value; + + public static Job findByValue(String value) { + return Arrays.stream(Job.values()) + .filter(job -> job.getValue().equals(value)) + .findFirst() + .orElseThrow((() -> new NotFoundException(ErrorCode.JOB_NOT_FOUND))); + } } diff --git a/src/main/java/com/server/bbo_gak/domain/user/entity/OauthProvider.java b/src/main/java/com/server/bbo_gak/domain/user/entity/OauthProvider.java index db563be..09bebf0 100644 --- a/src/main/java/com/server/bbo_gak/domain/user/entity/OauthProvider.java +++ b/src/main/java/com/server/bbo_gak/domain/user/entity/OauthProvider.java @@ -1,5 +1,16 @@ package com.server.bbo_gak.domain.user.entity; +import com.server.bbo_gak.global.error.exception.ErrorCode; +import com.server.bbo_gak.global.error.exception.InvalidValueException; +import java.util.Arrays; + public enum OauthProvider { - GOOGLE + GOOGLE; + + public static OauthProvider findByName(String name) { + return Arrays.stream(OauthProvider.values()) + .filter(oauthProvider -> oauthProvider.name().equalsIgnoreCase(name)) + .findFirst() + .orElseThrow(() -> new InvalidValueException(ErrorCode.INVALID_PROVIDER_TYPE)); + } } diff --git a/src/main/java/com/server/bbo_gak/domain/user/entity/User.java b/src/main/java/com/server/bbo_gak/domain/user/entity/User.java index ad27d37..3c04048 100644 --- a/src/main/java/com/server/bbo_gak/domain/user/entity/User.java +++ b/src/main/java/com/server/bbo_gak/domain/user/entity/User.java @@ -45,7 +45,11 @@ public static User from(OauthInfo oauthInfo) { return User.builder() .role(UserRole.USER) .oauthInfo(oauthInfo) - .job(Job.DEVELOPER) + .job(Job.UNDEFINE) .build(); } + + public void updateJob(Job job) { + this.job = job; + } } diff --git a/src/main/java/com/server/bbo_gak/domain/user/service/UserService.java b/src/main/java/com/server/bbo_gak/domain/user/service/UserService.java index 7360ead..bef4c4b 100644 --- a/src/main/java/com/server/bbo_gak/domain/user/service/UserService.java +++ b/src/main/java/com/server/bbo_gak/domain/user/service/UserService.java @@ -9,6 +9,8 @@ public interface UserService { void updateUser(); + void updateUserJob(User user, String job); + void getUser(); void deleteUser(); diff --git a/src/main/java/com/server/bbo_gak/domain/user/service/UserServiceImpl.java b/src/main/java/com/server/bbo_gak/domain/user/service/UserServiceImpl.java index 1f55844..264069d 100644 --- a/src/main/java/com/server/bbo_gak/domain/user/service/UserServiceImpl.java +++ b/src/main/java/com/server/bbo_gak/domain/user/service/UserServiceImpl.java @@ -1,10 +1,12 @@ package com.server.bbo_gak.domain.user.service; import com.server.bbo_gak.domain.auth.dto.response.oauth.OauthUserInfoResponse; +import com.server.bbo_gak.domain.user.entity.Job; import com.server.bbo_gak.domain.user.entity.User; import com.server.bbo_gak.domain.user.entity.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor @@ -26,6 +28,12 @@ public void updateUser() { } + @Transactional + public void updateUserJob(User user, String job) { + user.updateJob(Job.findByValue(job)); + userRepository.save(user); + } + @Override public void getUser() { diff --git a/src/main/java/com/server/bbo_gak/global/error/exception/ErrorCode.java b/src/main/java/com/server/bbo_gak/global/error/exception/ErrorCode.java index 58b0160..8cdf7dd 100644 --- a/src/main/java/com/server/bbo_gak/global/error/exception/ErrorCode.java +++ b/src/main/java/com/server/bbo_gak/global/error/exception/ErrorCode.java @@ -26,7 +26,7 @@ public enum ErrorCode { //OAuth AUTH_GET_USER_INFO_FAILED(HttpStatus.UNAUTHORIZED, "SocialAccessToken을 통해 사용자 정보를 가져오는 데에 실패했습니다."), - INVALID_PROVIDER_TYPE(HttpStatus.BAD_REQUEST, "지원하지 않는 방식의 로그인입니다."), + INVALID_PROVIDER_TYPE(HttpStatus.BAD_REQUEST, "지원하지 않는 provider를 입력하셨습니다."), PASSWORD_NOT_MATCHES(HttpStatus.BAD_REQUEST, "비밀번호를 잘못 입력하셨습니다."), diff --git a/src/test/java/com/server/bbo_gak/domain/auth/controller/AuthControllerTest.java b/src/test/java/com/server/bbo_gak/domain/auth/controller/AuthControllerTest.java index 018c99e..0c28d78 100644 --- a/src/test/java/com/server/bbo_gak/domain/auth/controller/AuthControllerTest.java +++ b/src/test/java/com/server/bbo_gak/domain/auth/controller/AuthControllerTest.java @@ -6,7 +6,6 @@ import static com.epages.restdocs.apispec.ResourceDocumentation.parameterWithName; import static com.epages.restdocs.apispec.ResourceDocumentation.resource; import static org.hamcrest.Matchers.matchesPattern; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; @@ -21,9 +20,7 @@ import com.epages.restdocs.apispec.ResourceSnippetParameters; import com.server.bbo_gak.domain.auth.dto.request.LoginRequest; -import com.server.bbo_gak.domain.auth.dto.response.LoginResponse; import com.server.bbo_gak.domain.auth.dto.response.oauth.OauthUserInfoResponse; -import com.server.bbo_gak.domain.auth.service.AuthService; import com.server.bbo_gak.domain.auth.service.oauth.GoogleService; import com.server.bbo_gak.domain.user.entity.OauthProvider; import com.server.bbo_gak.domain.auth.dto.request.RefreshTokenRequest; @@ -146,7 +143,8 @@ class 소셜_로그인 { ) .responseFields( // 응답 필드 fieldWithPath("accessToken").description("accessToken"), - fieldWithPath("refreshToken").description("refreshToken") + fieldWithPath("refreshToken").description("refreshToken"), + fieldWithPath("isFirstLogin").description("isFirstLogin") ) .build() ))); diff --git a/src/test/java/com/server/bbo_gak/domain/user/controller/UserControllerTest.java b/src/test/java/com/server/bbo_gak/domain/user/controller/UserControllerTest.java new file mode 100644 index 0000000..e2ae63f --- /dev/null +++ b/src/test/java/com/server/bbo_gak/domain/user/controller/UserControllerTest.java @@ -0,0 +1,43 @@ +package com.server.bbo_gak.domain.user.controller; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.server.bbo_gak.domain.user.dto.request.UserJobUpdateRequest; +import com.server.bbo_gak.global.AbstractRestDocsTests; +import com.server.bbo_gak.global.RestDocsFactory; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpMethod; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.transaction.annotation.Transactional; + +@Transactional +@SpringBootTest +@ActiveProfiles("test") +@Sql({"/all-data-delete.sql", "/user-test-data.sql"}) +public class UserControllerTest extends AbstractRestDocsTests { + private static final String DEFAULT_URL = "/api/v1/users"; + + @Autowired + private RestDocsFactory restDocsFactory; + + @Nested + class 직군선택 { + + @Test + public void 성공() throws Exception { + + //given + UserJobUpdateRequest request = new UserJobUpdateRequest("개발자"); + //then + mockMvc.perform(restDocsFactory.createRequest(DEFAULT_URL + "/job", request, HttpMethod.PUT, + objectMapper)) + .andExpect(status().isOk()) + .andDo(restDocsFactory.getSuccessResource("[직군선택] 성공", "직군 선택", "auth", request, null)); + + } + } +} diff --git a/src/test/resources/user-test-data.sql b/src/test/resources/user-test-data.sql new file mode 100644 index 0000000..b39437a --- /dev/null +++ b/src/test/resources/user-test-data.sql @@ -0,0 +1,28 @@ + +delete +from refresh_token; + +delete +from notification; + +delete +from recruit_schedule; + +delete +from recruit; + +delete +from recruit_season; + +delete +from users; + +INSERT INTO users (deleted, created_at, update_at, user_id, dtype, email, login_id, name, password, role, job) +VALUES (false, '2024-07-24 21:27:20.000000', '2024-07-24 21:27:21.000000', 1, 'AuthTestUser', 'email', 'test', 'test', + 'test123', 'USER', 'UNDEFINE'); + +INSERT INTO users( deleted, created_at, update_at, user_id, dtype, role, oauth_id, name, email, provider, job) +VALUES(false, '2024-07-24 21:27:20.000000', '2024-07-24 21:27:21.000000', 2, 'User', 'USER', 'oauthId', 'name', 'email', 'GOOGLE', 'UNDEFINE'); + +INSERT INTO refresh_token (id, token) +VALUES (1, 'abcd1234');