diff --git a/src/main/java/land/leets/domain/auth/AuthService.java b/src/main/java/land/leets/domain/auth/AuthService.java index 9c8f13c..f272646 100644 --- a/src/main/java/land/leets/domain/auth/AuthService.java +++ b/src/main/java/land/leets/domain/auth/AuthService.java @@ -87,11 +87,14 @@ public User getUser(String idToken) throws GeneralSecurityException, IOException return bySub.get(); } - User user = User.builder() - .sub(userId) - .name((String) payload.get("name")) - .email(payload.getEmail()) - .build(); + User user = new User( + null, + (String) payload.get("name"), + null, + payload.getEmail(), + userId, + null + ); return userRepository.save(user); } diff --git a/src/main/java/land/leets/domain/auth/UserAuthDetailsService.java b/src/main/java/land/leets/domain/auth/UserAuthDetailsService.java index 50278be..e2e27bf 100644 --- a/src/main/java/land/leets/domain/auth/UserAuthDetailsService.java +++ b/src/main/java/land/leets/domain/auth/UserAuthDetailsService.java @@ -19,6 +19,6 @@ public AuthDetails loadUserByUsername(String email) throws UsernameNotFoundExcep User user = this.userRepository .findByEmail(email) .orElseThrow(() -> new UsernameNotFoundException(ErrorCode.USER_NOT_FOUND.getMessage())); - return new AuthDetails(user.getUid(), user.getEmail(), AuthRole.ROLE_USER); + return new AuthDetails(user.getId(), user.getEmail(), AuthRole.ROLE_USER); } } diff --git a/src/main/java/land/leets/domain/auth/presentation/AuthController.java b/src/main/java/land/leets/domain/auth/presentation/AuthController.java index 63d0c04..923dd5c 100644 --- a/src/main/java/land/leets/domain/auth/presentation/AuthController.java +++ b/src/main/java/land/leets/domain/auth/presentation/AuthController.java @@ -38,8 +38,8 @@ public class AuthController { @GetMapping("/login/oauth2/callback/google") public JwtResponse get(@RequestParam("code") String code) throws GeneralSecurityException, IOException { User user = authService.getGoogleToken(code); - String accessToken = this.jwtProvider.generateToken(user.getUid(), user.getEmail(), AuthRole.ROLE_USER, false); - String refreshToken = this.jwtProvider.generateToken(user.getUid(), user.getEmail(), AuthRole.ROLE_USER, true); + String accessToken = this.jwtProvider.generateToken(user.getId(), user.getEmail(), AuthRole.ROLE_USER, false); + String refreshToken = this.jwtProvider.generateToken(user.getId(), user.getEmail(), AuthRole.ROLE_USER, true); return new JwtResponse(accessToken, refreshToken); } diff --git a/src/main/java/land/leets/domain/user/domain/User.java b/src/main/java/land/leets/domain/user/domain/User.java deleted file mode 100644 index 3b8dae2..0000000 --- a/src/main/java/land/leets/domain/user/domain/User.java +++ /dev/null @@ -1,56 +0,0 @@ -package land.leets.domain.user.domain; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import land.leets.domain.shared.BaseTimeEntity; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import java.util.UUID; - -@Entity(name = "users") -@Builder -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor -public class User extends BaseTimeEntity { - - @Id - @GeneratedValue(strategy = GenerationType.UUID) - @Column(columnDefinition = "BINARY(16)") - private UUID uid; - - @Column - private String sid; - - @Column(nullable = false) - private String name; - - @Column - private String phone; - - @Column(nullable = false) - private String email; - - @Column(nullable = false) - private String sub; - - public UUID getUid() { - return uid; - } - - public String getPhone() { - return phone; - } - - public void updateUserInfo(String sid, String phone) { - this.sid = sid; - this.phone = phone; - } -} diff --git a/src/main/java/land/leets/domain/user/domain/repository/UserRepository.java b/src/main/java/land/leets/domain/user/domain/repository/UserRepository.java deleted file mode 100644 index e4582dd..0000000 --- a/src/main/java/land/leets/domain/user/domain/repository/UserRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package land.leets.domain.user.domain.repository; - -import land.leets.domain.user.domain.User; -import org.springframework.data.jpa.repository.JpaRepository; - -import java.util.Optional; -import java.util.UUID; - -public interface UserRepository extends JpaRepository { - Optional findBySub(String sub); - Optional findByEmail(String email); - Optional findByUid(UUID uid); -} diff --git a/src/main/java/land/leets/domain/user/exception/UserNotFoundException.java b/src/main/java/land/leets/domain/user/exception/UserNotFoundException.java deleted file mode 100644 index d27a1d9..0000000 --- a/src/main/java/land/leets/domain/user/exception/UserNotFoundException.java +++ /dev/null @@ -1,10 +0,0 @@ -package land.leets.domain.user.exception; - -import land.leets.global.error.ErrorCode; -import land.leets.global.error.exception.ServiceException; - -public class UserNotFoundException extends ServiceException { - public UserNotFoundException() { - super(ErrorCode.USER_NOT_FOUND); - } -} diff --git a/src/main/java/land/leets/domain/user/presentation/UserController.java b/src/main/java/land/leets/domain/user/presentation/UserController.java deleted file mode 100644 index b894587..0000000 --- a/src/main/java/land/leets/domain/user/presentation/UserController.java +++ /dev/null @@ -1,69 +0,0 @@ -package land.leets.domain.user.presentation; - - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import land.leets.domain.auth.AuthDetails; -import land.leets.domain.auth.AuthService; -import land.leets.domain.shared.AuthRole; -import land.leets.domain.user.domain.User; -import land.leets.domain.user.presentation.dto.LoginRequest; -import land.leets.domain.user.presentation.dto.UserDetailsResponse; -import land.leets.domain.user.usecase.GetUserDetails; -import land.leets.global.error.ErrorResponse; -import land.leets.global.jwt.JwtProvider; -import land.leets.global.jwt.dto.JwtResponse; -import lombok.RequiredArgsConstructor; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.GetMapping; -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.RestController; - -import java.io.IOException; -import java.security.GeneralSecurityException; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/user") -public class UserController { - - private final GetUserDetails getUserDetails; - private final AuthService authService; - private final JwtProvider jwtProvider; - - @Operation(summary = "(비로그인) 유저 로그인", description = "유저 계정으로 로그인합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400", content = @Content(schema = @Schema(implementation = ErrorResponse.class))), - @ApiResponse(responseCode = "403", content = @Content(schema = @Schema(implementation = ErrorResponse.class))), - @ApiResponse(responseCode = "404", content = @Content(schema = @Schema(implementation = ErrorResponse.class))), - @ApiResponse(responseCode = "500", content = @Content(schema = @Schema(implementation = ErrorResponse.class))) - }) - @PostMapping("/login") - public JwtResponse getUserDetails(@RequestBody LoginRequest request) throws GeneralSecurityException, IOException { - User user = authService.getUser(request.getIdToken()); - - String accessToken = this.jwtProvider.generateToken(user.getUid(), user.getEmail(), AuthRole.ROLE_USER, false); - String refreshToken = this.jwtProvider.generateToken(user.getUid(), user.getEmail(), AuthRole.ROLE_USER, true); - - return new JwtResponse(accessToken, refreshToken); - } - - @Operation(summary = "(유저) 유저 정보 상세 조회", description = "유저 정보를 상세 조회합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400", content = @Content(schema = @Schema(implementation = ErrorResponse.class))), - @ApiResponse(responseCode = "403", content = @Content(schema = @Schema(implementation = ErrorResponse.class))), - @ApiResponse(responseCode = "404", content = @Content(schema = @Schema(implementation = ErrorResponse.class))), - @ApiResponse(responseCode = "500", content = @Content(schema = @Schema(implementation = ErrorResponse.class))) - }) - @GetMapping("/me") - public UserDetailsResponse getUserDetails(@AuthenticationPrincipal AuthDetails authDetails) { - return getUserDetails.execute(authDetails); - } -} diff --git a/src/main/java/land/leets/domain/user/presentation/dto/LoginRequest.java b/src/main/java/land/leets/domain/user/presentation/dto/LoginRequest.java deleted file mode 100644 index 5e0220a..0000000 --- a/src/main/java/land/leets/domain/user/presentation/dto/LoginRequest.java +++ /dev/null @@ -1,12 +0,0 @@ -package land.leets.domain.user.presentation.dto; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@AllArgsConstructor -@NoArgsConstructor -public class LoginRequest { - private String idToken; -} diff --git a/src/main/java/land/leets/domain/user/presentation/dto/UserDetailsResponse.java b/src/main/java/land/leets/domain/user/presentation/dto/UserDetailsResponse.java deleted file mode 100644 index 78d3feb..0000000 --- a/src/main/java/land/leets/domain/user/presentation/dto/UserDetailsResponse.java +++ /dev/null @@ -1,33 +0,0 @@ -package land.leets.domain.user.presentation.dto; - -import land.leets.domain.application.type.SubmitStatus; -import land.leets.domain.user.domain.User; -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.util.UUID; - -@Getter -@AllArgsConstructor -public class UserDetailsResponse { - - private UUID uid; - private String sid; - private String name; - private String phone; - private String email; - private String major; - private SubmitStatus submitStatus; - - public static UserDetailsResponse of(User user, SubmitStatus submitStatus) { - return new UserDetailsResponse( - user.getUid(), - user.getSid(), - user.getName(), - user.getPhone(), - user.getEmail(), - null, - submitStatus - ); - } -} diff --git a/src/main/java/land/leets/domain/user/usecase/GetUserDetails.java b/src/main/java/land/leets/domain/user/usecase/GetUserDetails.java deleted file mode 100644 index e9167c6..0000000 --- a/src/main/java/land/leets/domain/user/usecase/GetUserDetails.java +++ /dev/null @@ -1,9 +0,0 @@ -package land.leets.domain.user.usecase; - -import land.leets.domain.auth.AuthDetails; -import land.leets.domain.user.presentation.dto.UserDetailsResponse; - -public interface GetUserDetails { - - UserDetailsResponse execute(AuthDetails authDetails); -} diff --git a/src/main/java/land/leets/domain/user/usecase/GetUserDetailsImpl.java b/src/main/java/land/leets/domain/user/usecase/GetUserDetailsImpl.java deleted file mode 100644 index d32c48c..0000000 --- a/src/main/java/land/leets/domain/user/usecase/GetUserDetailsImpl.java +++ /dev/null @@ -1,31 +0,0 @@ -package land.leets.domain.user.usecase; - -import land.leets.domain.application.domain.Application; -import land.leets.domain.application.domain.repository.ApplicationRepository; -import land.leets.domain.application.type.SubmitStatus; -import land.leets.domain.auth.AuthDetails; -import land.leets.domain.user.domain.User; -import land.leets.domain.user.domain.repository.UserRepository; -import land.leets.domain.user.exception.UserNotFoundException; -import land.leets.domain.user.presentation.dto.UserDetailsResponse; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -import java.util.UUID; - -@Service -@RequiredArgsConstructor -public class GetUserDetailsImpl implements GetUserDetails { - - private final UserRepository userRepository; - private final ApplicationRepository applicationRepository; - - @Override - public UserDetailsResponse execute(AuthDetails authDetails) { - UUID uid = authDetails.getUid(); - User user = userRepository.findById(uid).orElseThrow(UserNotFoundException::new); - Application application = applicationRepository.findByUser_Uid(uid); - - return UserDetailsResponse.of(user, application == null ? SubmitStatus.NONE : application.getSubmitStatus()); - } -} diff --git a/src/main/java/land/leets/domain/user/usecase/UpdateUser.java b/src/main/java/land/leets/domain/user/usecase/UpdateUser.java deleted file mode 100644 index 07435bb..0000000 --- a/src/main/java/land/leets/domain/user/usecase/UpdateUser.java +++ /dev/null @@ -1,10 +0,0 @@ -package land.leets.domain.user.usecase; - -import land.leets.domain.application.presentation.dto.ApplicationRequest; -import land.leets.domain.user.domain.User; - -import java.util.UUID; - -public interface UpdateUser { - User execute(UUID uid, ApplicationRequest request); -} diff --git a/src/main/java/land/leets/domain/user/usecase/UpdateUserImpl.java b/src/main/java/land/leets/domain/user/usecase/UpdateUserImpl.java deleted file mode 100644 index 2406872..0000000 --- a/src/main/java/land/leets/domain/user/usecase/UpdateUserImpl.java +++ /dev/null @@ -1,24 +0,0 @@ -package land.leets.domain.user.usecase; - -import land.leets.domain.application.presentation.dto.ApplicationRequest; -import land.leets.domain.user.domain.User; -import land.leets.domain.user.domain.repository.UserRepository; -import land.leets.domain.user.exception.UserNotFoundException; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -import java.util.UUID; - -@Service -@RequiredArgsConstructor -public class UpdateUserImpl implements UpdateUser { - - private final UserRepository userRepository; - - @Override - public User execute(UUID uid, ApplicationRequest request) { - User user = userRepository.findById(uid).orElseThrow(UserNotFoundException::new); - user.updateUserInfo(request.getSid(), request.getPhone()); - return userRepository.save(user); - } -} diff --git a/src/main/java/land/leets/global/jwt/JwtProvider.java b/src/main/java/land/leets/global/jwt/JwtProvider.java index 6829521..1f5274a 100644 --- a/src/main/java/land/leets/global/jwt/JwtProvider.java +++ b/src/main/java/land/leets/global/jwt/JwtProvider.java @@ -51,7 +51,7 @@ public String generateToken(UUID uuid, String sub, AuthRole role, boolean isRefr return Jwts.builder() .claim("role", role.getRole()) - .claim(role == AuthRole.ROLE_USER ? "uid" : "id", uuid.toString()) + .claim("id" , uuid.toString()) .subject(sub) .expiration(isRefreshToken ? Date.from(refreshDate) : Date.from(accessDate)) .signWith(isRefreshToken ? refreshSecret : accessSecret) diff --git a/src/main/kotlin/land/leets/domain/admin/usecase/AdminRefreshTokenImpl.kt b/src/main/kotlin/land/leets/domain/admin/usecase/AdminRefreshTokenImpl.kt index 3bc0e3b..fb90046 100644 --- a/src/main/kotlin/land/leets/domain/admin/usecase/AdminRefreshTokenImpl.kt +++ b/src/main/kotlin/land/leets/domain/admin/usecase/AdminRefreshTokenImpl.kt @@ -15,7 +15,7 @@ class AdminRefreshTokenImpl( jwtProvider.validateToken(refreshToken, true) val claims = jwtProvider.parseClaims(refreshToken, true) val role = claims.get("role", String::class.java) - val uuid = UUID.fromString(claims.get("uid", String::class.java)) + val uuid = UUID.fromString(claims.get("id", String::class.java)) val newAccessToken = jwtProvider.generateToken(uuid, claims.subject, AuthRole.valueOf(role), false) return JwtResponse(newAccessToken, null) } diff --git a/src/main/kotlin/land/leets/domain/application/domain/Application.kt b/src/main/kotlin/land/leets/domain/application/domain/Application.kt index 617cfe8..c65d2c0 100644 --- a/src/main/kotlin/land/leets/domain/application/domain/Application.kt +++ b/src/main/kotlin/land/leets/domain/application/domain/Application.kt @@ -12,7 +12,7 @@ import java.time.LocalDateTime @Entity(name = "applications") class Application( @OneToOne - @JoinColumn(name = "uid") + @JoinColumn(name = "id") var user: User, @Column(nullable = false) diff --git a/src/main/kotlin/land/leets/domain/application/usecase/CreateApplicationImpl.kt b/src/main/kotlin/land/leets/domain/application/usecase/CreateApplicationImpl.kt index 316b2c2..a34e681 100644 --- a/src/main/kotlin/land/leets/domain/application/usecase/CreateApplicationImpl.kt +++ b/src/main/kotlin/land/leets/domain/application/usecase/CreateApplicationImpl.kt @@ -21,7 +21,7 @@ class CreateApplicationImpl( override fun execute(authDetails: AuthDetails, request: ApplicationRequest): Application { val user: User = userRepository.findById(authDetails.uid).orElseThrow { UserNotFoundException() } - if (applicationRepository.findByUser_Uid(user.getUid()) != null) { + if (applicationRepository.findByUser_Uid(user.id!!) != null) { throw ApplicationAlreadyExistsException() } diff --git a/src/main/kotlin/land/leets/domain/application/usecase/GetAllApplicationImpl.kt b/src/main/kotlin/land/leets/domain/application/usecase/GetAllApplicationImpl.kt index ae97f09..f841567 100644 --- a/src/main/kotlin/land/leets/domain/application/usecase/GetAllApplicationImpl.kt +++ b/src/main/kotlin/land/leets/domain/application/usecase/GetAllApplicationImpl.kt @@ -31,7 +31,7 @@ class GetAllApplicationImpl( private fun mapApplications(applications: List): List { return applications.map { application -> val interview = getInterview.execute(application) - val phone = application.user.getPhone() + val phone = application.user.phone ?: "" ApplicationResponse.of(application, interview, phone) } } diff --git a/src/main/kotlin/land/leets/domain/application/usecase/GetApplicationDetailsImpl.kt b/src/main/kotlin/land/leets/domain/application/usecase/GetApplicationDetailsImpl.kt index a038874..4564f22 100644 --- a/src/main/kotlin/land/leets/domain/application/usecase/GetApplicationDetailsImpl.kt +++ b/src/main/kotlin/land/leets/domain/application/usecase/GetApplicationDetailsImpl.kt @@ -26,7 +26,7 @@ class GetApplicationDetailsImpl( private fun getDetails(application: Application): ApplicationDetailsResponse { val interview = getInterviewDetails.execute(application) - val phone = application.user.getPhone() + val phone = application.user.phone ?: "" return ApplicationDetailsResponse.of(application, interview, phone) } } diff --git a/src/main/kotlin/land/leets/domain/user/domain/User.kt b/src/main/kotlin/land/leets/domain/user/domain/User.kt new file mode 100644 index 0000000..6bf6257 --- /dev/null +++ b/src/main/kotlin/land/leets/domain/user/domain/User.kt @@ -0,0 +1,34 @@ +package land.leets.domain.user.domain + +import jakarta.persistence.* +import land.leets.domain.shared.BaseTimeEntity +import java.util.UUID + +@Entity(name = "users") +class User( + @Column + var sid: String?, + + @Column(nullable = false) + val name: String, + + @Column + var phone: String?, + + @Column(nullable = false) + val email: String, + + @Column(nullable = false) + val sub: String, + + @Id + @GeneratedValue(strategy = GenerationType.UUID) + @Column(columnDefinition = "BINARY(16)") + val id: UUID? = null +) : BaseTimeEntity() { + + fun updateUserInfo(sid: String?, phone: String) { + this.sid = sid + this.phone = phone + } +} diff --git a/src/main/kotlin/land/leets/domain/user/domain/repository/UserRepository.kt b/src/main/kotlin/land/leets/domain/user/domain/repository/UserRepository.kt new file mode 100644 index 0000000..5e16e87 --- /dev/null +++ b/src/main/kotlin/land/leets/domain/user/domain/repository/UserRepository.kt @@ -0,0 +1,12 @@ +package land.leets.domain.user.domain.repository + +import land.leets.domain.user.domain.User +import org.springframework.data.jpa.repository.JpaRepository +import java.util.Optional +import java.util.UUID + +interface UserRepository : JpaRepository { + fun findBySub(sub: String): Optional + fun findByEmail(email: String): Optional + fun findByUid(uid: UUID): Optional +} diff --git a/src/main/kotlin/land/leets/domain/user/exception/UserNotFoundException.kt b/src/main/kotlin/land/leets/domain/user/exception/UserNotFoundException.kt new file mode 100644 index 0000000..2830712 --- /dev/null +++ b/src/main/kotlin/land/leets/domain/user/exception/UserNotFoundException.kt @@ -0,0 +1,6 @@ +package land.leets.domain.user.exception + +import land.leets.global.error.ErrorCode +import land.leets.global.error.exception.ServiceException + +class UserNotFoundException : ServiceException(ErrorCode.USER_NOT_FOUND) diff --git a/src/main/kotlin/land/leets/domain/user/presentation/UserController.kt b/src/main/kotlin/land/leets/domain/user/presentation/UserController.kt new file mode 100644 index 0000000..2f874f9 --- /dev/null +++ b/src/main/kotlin/land/leets/domain/user/presentation/UserController.kt @@ -0,0 +1,65 @@ +package land.leets.domain.user.presentation + +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.responses.ApiResponses +import land.leets.domain.auth.AuthDetails +import land.leets.domain.auth.AuthService +import land.leets.domain.shared.AuthRole +import land.leets.domain.user.presentation.dto.LoginRequest +import land.leets.domain.user.presentation.dto.UserDetailsResponse +import land.leets.domain.user.usecase.GetUserDetails +import land.leets.global.error.ErrorResponse +import land.leets.global.jwt.JwtProvider +import land.leets.global.jwt.dto.JwtResponse +import org.springframework.security.core.annotation.AuthenticationPrincipal +import org.springframework.web.bind.annotation.* +import java.io.IOException +import java.security.GeneralSecurityException + +@RestController +@RequestMapping("/user") +class UserController( + private val getUserDetails: GetUserDetails, + private val authService: AuthService, + private val jwtProvider: JwtProvider +) { + + @Operation(summary = "(비로그인) 유저 로그인", description = "유저 계정으로 로그인합니다.") + @ApiResponses( + value = [ + ApiResponse(responseCode = "200"), + ApiResponse(responseCode = "400", content = [Content(schema = Schema(implementation = ErrorResponse::class))]), + ApiResponse(responseCode = "403", content = [Content(schema = Schema(implementation = ErrorResponse::class))]), + ApiResponse(responseCode = "404", content = [Content(schema = Schema(implementation = ErrorResponse::class))]), + ApiResponse(responseCode = "500", content = [Content(schema = Schema(implementation = ErrorResponse::class))]) + ] + ) + @PostMapping("/login") + @Throws(GeneralSecurityException::class, IOException::class) + fun login(@RequestBody request: LoginRequest): JwtResponse { + val user = authService.getUser(request.idToken) + + val accessToken = jwtProvider.generateToken(user.id, user.email, AuthRole.ROLE_USER, false) + val refreshToken = jwtProvider.generateToken(user.id, user.email, AuthRole.ROLE_USER, true) + + return JwtResponse(accessToken, refreshToken) + } + + @Operation(summary = "(유저) 유저 정보 상세 조회", description = "유저 정보를 상세 조회합니다.") + @ApiResponses( + value = [ + ApiResponse(responseCode = "200"), + ApiResponse(responseCode = "400", content = [Content(schema = Schema(implementation = ErrorResponse::class))]), + ApiResponse(responseCode = "403", content = [Content(schema = Schema(implementation = ErrorResponse::class))]), + ApiResponse(responseCode = "404", content = [Content(schema = Schema(implementation = ErrorResponse::class))]), + ApiResponse(responseCode = "500", content = [Content(schema = Schema(implementation = ErrorResponse::class))]) + ] + ) + @GetMapping("/me") + fun getUserDetails(@AuthenticationPrincipal authDetails: AuthDetails): UserDetailsResponse { + return getUserDetails.execute(authDetails) + } +} diff --git a/src/main/kotlin/land/leets/domain/user/presentation/dto/LoginRequest.kt b/src/main/kotlin/land/leets/domain/user/presentation/dto/LoginRequest.kt new file mode 100644 index 0000000..8784220 --- /dev/null +++ b/src/main/kotlin/land/leets/domain/user/presentation/dto/LoginRequest.kt @@ -0,0 +1,5 @@ +package land.leets.domain.user.presentation.dto + +data class LoginRequest( + val idToken: String +) diff --git a/src/main/kotlin/land/leets/domain/user/presentation/dto/UserDetailsResponse.kt b/src/main/kotlin/land/leets/domain/user/presentation/dto/UserDetailsResponse.kt new file mode 100644 index 0000000..983990b --- /dev/null +++ b/src/main/kotlin/land/leets/domain/user/presentation/dto/UserDetailsResponse.kt @@ -0,0 +1,29 @@ +package land.leets.domain.user.presentation.dto + +import land.leets.domain.application.type.SubmitStatus +import land.leets.domain.user.domain.User +import java.util.UUID + +data class UserDetailsResponse( + val uid: UUID?, + val sid: String?, + val name: String, + val phone: String?, + val email: String, + val major: String?, + val submitStatus: SubmitStatus +) { + companion object { + fun of(user: User, submitStatus: SubmitStatus): UserDetailsResponse { + return UserDetailsResponse( + uid = user.id, + sid = user.sid, + name = user.name, + phone = user.phone, + email = user.email, + major = null, + submitStatus = submitStatus + ) + } + } +} diff --git a/src/main/kotlin/land/leets/domain/user/usecase/GetUserDetails.kt b/src/main/kotlin/land/leets/domain/user/usecase/GetUserDetails.kt new file mode 100644 index 0000000..7fb111c --- /dev/null +++ b/src/main/kotlin/land/leets/domain/user/usecase/GetUserDetails.kt @@ -0,0 +1,8 @@ +package land.leets.domain.user.usecase + +import land.leets.domain.auth.AuthDetails +import land.leets.domain.user.presentation.dto.UserDetailsResponse + +interface GetUserDetails { + fun execute(authDetails: AuthDetails): UserDetailsResponse +} diff --git a/src/main/kotlin/land/leets/domain/user/usecase/GetUserDetailsImpl.kt b/src/main/kotlin/land/leets/domain/user/usecase/GetUserDetailsImpl.kt new file mode 100644 index 0000000..3138808 --- /dev/null +++ b/src/main/kotlin/land/leets/domain/user/usecase/GetUserDetailsImpl.kt @@ -0,0 +1,29 @@ +package land.leets.domain.user.usecase + +import land.leets.domain.application.domain.Application +import land.leets.domain.application.domain.repository.ApplicationRepository +import land.leets.domain.application.type.SubmitStatus +import land.leets.domain.auth.AuthDetails +import land.leets.domain.user.domain.User +import land.leets.domain.user.domain.repository.UserRepository +import land.leets.domain.user.exception.UserNotFoundException +import land.leets.domain.user.presentation.dto.UserDetailsResponse +import org.springframework.data.repository.findByIdOrNull +import org.springframework.stereotype.Service +import java.util.UUID + +@Service +class GetUserDetailsImpl( + private val userRepository: UserRepository, + private val applicationRepository: ApplicationRepository +) : GetUserDetails { + + override fun execute(authDetails: AuthDetails): UserDetailsResponse { + val uid: UUID = authDetails.uid + val user: User = userRepository.findByIdOrNull(uid) ?: throw UserNotFoundException() + + val application: Application? = applicationRepository.findByUser_Uid(uid) + + return UserDetailsResponse.of(user, application?.submitStatus ?: SubmitStatus.NONE) + } +} diff --git a/src/main/kotlin/land/leets/domain/user/usecase/UpdateUser.kt b/src/main/kotlin/land/leets/domain/user/usecase/UpdateUser.kt new file mode 100644 index 0000000..2a85d29 --- /dev/null +++ b/src/main/kotlin/land/leets/domain/user/usecase/UpdateUser.kt @@ -0,0 +1,9 @@ +package land.leets.domain.user.usecase + +import land.leets.domain.application.presentation.dto.ApplicationRequest +import land.leets.domain.user.domain.User +import java.util.UUID + +interface UpdateUser { + fun execute(uid: UUID, request: ApplicationRequest): User +} diff --git a/src/main/kotlin/land/leets/domain/user/usecase/UpdateUserImpl.kt b/src/main/kotlin/land/leets/domain/user/usecase/UpdateUserImpl.kt new file mode 100644 index 0000000..1bd4a62 --- /dev/null +++ b/src/main/kotlin/land/leets/domain/user/usecase/UpdateUserImpl.kt @@ -0,0 +1,21 @@ +package land.leets.domain.user.usecase + +import land.leets.domain.application.presentation.dto.ApplicationRequest +import land.leets.domain.user.domain.User +import land.leets.domain.user.domain.repository.UserRepository +import land.leets.domain.user.exception.UserNotFoundException +import org.springframework.data.repository.findByIdOrNull +import org.springframework.stereotype.Service +import java.util.UUID + +@Service +class UpdateUserImpl( + private val userRepository: UserRepository +) : UpdateUser { + + override fun execute(uid: UUID, request: ApplicationRequest): User { + val user: User = userRepository.findByIdOrNull(uid) ?: throw UserNotFoundException() + user.updateUserInfo(request.sid, request.phone) + return userRepository.save(user) + } +} diff --git a/src/test/kotlin/land/leets/domain/admin/usecase/AdminRefreshTokenImplTest.kt b/src/test/kotlin/land/leets/domain/admin/usecase/AdminRefreshTokenImplTest.kt index 49f5bbb..7dad4d0 100644 --- a/src/test/kotlin/land/leets/domain/admin/usecase/AdminRefreshTokenImplTest.kt +++ b/src/test/kotlin/land/leets/domain/admin/usecase/AdminRefreshTokenImplTest.kt @@ -27,7 +27,7 @@ class AdminRefreshTokenImplTest : DescribeSpec({ it("새로운 액세스 토큰이 담긴 JwtResponse를 반환한다") { val claims = mockk() every { claims.get("role", String::class.java) } returns role.name - every { claims.get("uid", String::class.java) } returns uid.toString() + every { claims.get("id", String::class.java) } returns uid.toString() every { claims.subject } returns subject every { jwtProvider.validateToken(refreshToken, true) } just runs diff --git a/src/test/kotlin/land/leets/domain/application/usecase/CreateApplicationImplTest.kt b/src/test/kotlin/land/leets/domain/application/usecase/CreateApplicationImplTest.kt index bb7936f..0687692 100644 --- a/src/test/kotlin/land/leets/domain/application/usecase/CreateApplicationImplTest.kt +++ b/src/test/kotlin/land/leets/domain/application/usecase/CreateApplicationImplTest.kt @@ -49,9 +49,14 @@ class CreateApplicationImplTest : DescribeSpec({ passion = "Passion", submitStatus = SubmitStatus.SAVE ) - val user = mockk(relaxed = true) { - every { getUid() } returns uid - } + val user = User( + sid = "20202020", + name = "Test", + phone = "010-1234-5678", + email = "test@test.com", + sub = "google-oauth2|123456", + id = uid + ) it("지원서를 성공적으로 생성한다") { every { userRepository.findById(uid) } returns Optional.of(user) diff --git a/src/test/kotlin/land/leets/domain/user/usecase/GetUserDetailsImplTest.kt b/src/test/kotlin/land/leets/domain/user/usecase/GetUserDetailsImplTest.kt new file mode 100644 index 0000000..8be6cb9 --- /dev/null +++ b/src/test/kotlin/land/leets/domain/user/usecase/GetUserDetailsImplTest.kt @@ -0,0 +1,70 @@ +package land.leets.domain.user.usecase + +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import io.mockk.every +import io.mockk.mockk +import land.leets.domain.application.domain.Application +import land.leets.domain.application.domain.repository.ApplicationRepository +import land.leets.domain.application.type.SubmitStatus +import land.leets.domain.auth.AuthDetails +import land.leets.domain.shared.AuthRole +import land.leets.domain.user.domain.User +import land.leets.domain.user.domain.repository.UserRepository +import land.leets.domain.user.exception.UserNotFoundException +import java.util.Optional +import java.util.UUID + +class GetUserDetailsImplTest : DescribeSpec({ + + val userRepository = mockk() + val applicationRepository = mockk() + val getUserDetails = GetUserDetailsImpl(userRepository, applicationRepository) + + describe("GetUserDetailsImpl") { + context("유저 상세 정보를 조회할 때") { + val uid = UUID.randomUUID() + val authDetails = AuthDetails(uid, "user@test.com", AuthRole.ROLE_USER) + val user = User( + sid = "20201234", + name = "Test User", + phone = "010-1234-5678", + email = "user@test.com", + sub = "google-oauth2|123456", + id = uid + ) + + it("유저가 존재하고 지원서가 없으면 NONE 상태로 반환한다") { + every { userRepository.findById(uid) } returns Optional.of(user) + every { applicationRepository.findByUser_Uid(uid) } returns null + + val response = getUserDetails.execute(authDetails) + + response.uid shouldBe uid + response.name shouldBe "Test User" + response.submitStatus shouldBe SubmitStatus.NONE + } + + it("유저가 존재하고 지원서가 있으면 지원서 상태를 반환한다") { + val application = mockk { + every { submitStatus } returns SubmitStatus.SUBMIT + } + every { userRepository.findById(uid) } returns Optional.of(user) + every { applicationRepository.findByUser_Uid(uid) } returns application + + val response = getUserDetails.execute(authDetails) + + response.submitStatus shouldBe SubmitStatus.SUBMIT + } + + it("유저를 찾을 수 없으면 UserNotFoundException을 던진다") { + every { userRepository.findById(uid) } returns Optional.empty() + + shouldThrow { + getUserDetails.execute(authDetails) + } + } + } + } +}) diff --git a/src/test/kotlin/land/leets/domain/user/usecase/UpdateUserImplTest.kt b/src/test/kotlin/land/leets/domain/user/usecase/UpdateUserImplTest.kt new file mode 100644 index 0000000..7a4e5c8 --- /dev/null +++ b/src/test/kotlin/land/leets/domain/user/usecase/UpdateUserImplTest.kt @@ -0,0 +1,75 @@ +package land.leets.domain.user.usecase + +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import land.leets.domain.application.presentation.dto.ApplicationRequest +import land.leets.domain.application.type.Position +import land.leets.domain.application.type.SubmitStatus +import land.leets.domain.user.domain.User +import land.leets.domain.user.domain.repository.UserRepository +import land.leets.domain.user.exception.UserNotFoundException +import java.util.Optional +import java.util.UUID + +class UpdateUserImplTest : DescribeSpec({ + + val userRepository = mockk() + val updateUser = UpdateUserImpl(userRepository) + + describe("UpdateUserImpl") { + context("유저 정보를 업데이트할 때") { + val uid = UUID.randomUUID() + val request = ApplicationRequest( + name = "Test User", + sid = "20201234", + phone = "010-1234-5678", + major = "CS", + grade = "4", + project = "Project", + algorithm = "Algorithm", + portfolio = "Portfolio", + position = Position.DEV, + career = "Career", + interviewDay = "Monday", + interviewTime = "10:00", + motive = "Motive", + expectation = "Expectation", + capability = "Capability", + conflict = "Conflict", + passion = "Passion", + submitStatus = SubmitStatus.SAVE + ) + + it("유저가 존재하면 정보를 업데이트한다") { + val user = User( + sid = null, + name = "Test User", + phone = null, + email = "user@test.com", + sub = "google-oauth2|123456", + id = uid + ) + every { userRepository.findById(uid) } returns Optional.of(user) + every { userRepository.save(any()) } returnsArgument 0 + + val result = updateUser.execute(uid, request) + + verify { userRepository.save(user) } + result.sid shouldBe "20201234" + result.phone shouldBe "010-1234-5678" + } + + it("유저를 찾을 수 없으면 UserNotFoundException을 던진다") { + every { userRepository.findById(uid) } returns Optional.empty() + + shouldThrow { + updateUser.execute(uid, request) + } + } + } + } +})