From eaef7857e9756856f8b974ddd495da742be74402 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Sat, 13 Jul 2024 13:41:32 +0900 Subject: [PATCH 01/34] =?UTF-8?q?chore:=20Spring=20Security=20gradle=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index a8b8bcdc..44fb01d6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -48,11 +48,13 @@ subprojects { dependencies { implementation("org.springframework.boot:spring-boot-starter") implementation("org.springframework.boot:spring-boot-starter-data-jpa") + implementation("org.springframework.boot:spring-boot-starter-security") implementation("org.springframework.cloud:spring-cloud-starter-openfeign") + implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") - implementation("mysql:mysql-connector-java:8.0.32") + implementation("mysql:mysql-connector-j") // https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on implementation("org.bouncycastle:bcpkix-jdk15on:1.69") From e52037e13a0b79dee50cc50609f2f0cdca6ec108 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Sat, 13 Jul 2024 13:43:00 +0900 Subject: [PATCH 02/34] =?UTF-8?q?feat:=20User=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EC=A0=95=EB=B3=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - email, password, role, socialEmail 추가 --- domain/src/main/kotlin/com/wespot/user/Role.kt | 6 ++++++ domain/src/main/kotlin/com/wespot/user/Social.kt | 1 + domain/src/main/kotlin/com/wespot/user/User.kt | 3 +++ .../src/main/kotlin/com/wespot/user/UserJpaEntity.kt | 10 +++++++++- 4 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 domain/src/main/kotlin/com/wespot/user/Role.kt diff --git a/domain/src/main/kotlin/com/wespot/user/Role.kt b/domain/src/main/kotlin/com/wespot/user/Role.kt new file mode 100644 index 00000000..97f4a9bb --- /dev/null +++ b/domain/src/main/kotlin/com/wespot/user/Role.kt @@ -0,0 +1,6 @@ +package com.wespot.user + +enum class Role { + USER, + ADMIN +} diff --git a/domain/src/main/kotlin/com/wespot/user/Social.kt b/domain/src/main/kotlin/com/wespot/user/Social.kt index 627d4eb5..b066cd4c 100644 --- a/domain/src/main/kotlin/com/wespot/user/Social.kt +++ b/domain/src/main/kotlin/com/wespot/user/Social.kt @@ -3,6 +3,7 @@ package com.wespot.user data class Social( val socialType: SocialType, val socialId: Long, + val socialEmail: String?, val socialRefreshToken: String ) { } diff --git a/domain/src/main/kotlin/com/wespot/user/User.kt b/domain/src/main/kotlin/com/wespot/user/User.kt index c3680c10..7421a3a3 100644 --- a/domain/src/main/kotlin/com/wespot/user/User.kt +++ b/domain/src/main/kotlin/com/wespot/user/User.kt @@ -4,8 +4,11 @@ import java.time.LocalDateTime data class User( val id: Long, + val email: String, + val password: String, val name: String, val introduction: String, + val role: Role, val schoolId: Long, val grade: Int, val groupNumber: Int, diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/UserJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/UserJpaEntity.kt index 7269f7cf..e8abc202 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/UserJpaEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/UserJpaEntity.kt @@ -23,6 +23,12 @@ class UserJpaEntity( @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long, + @field: NotNull + val email: String, + + @field: NotNull + val password: String, + @field: NotNull val name: String, @@ -67,4 +73,6 @@ class UserJpaEntity( val withdrawAt: LocalDateTime -) +) { + +} From fa582364364b50c75b21d2c189bb121b874c6754 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Sat, 13 Jul 2024 13:44:44 +0900 Subject: [PATCH 03/34] =?UTF-8?q?feat:=20PrincipalDetail=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 인증과 권한 부여를 위해 사용자 정보를 캡슐화 --- .../auth/service/PrincipalDetailService.kt | 19 +++++++++ .../com/wespot/user/port/out/UserPort.kt | 7 ++-- .../com/wespot/auth/PrincipalDetails.kt | 41 +++++++++++++++++++ 3 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 core/src/main/kotlin/com/wespot/auth/service/PrincipalDetailService.kt create mode 100644 domain/src/main/kotlin/com/wespot/auth/PrincipalDetails.kt diff --git a/core/src/main/kotlin/com/wespot/auth/service/PrincipalDetailService.kt b/core/src/main/kotlin/com/wespot/auth/service/PrincipalDetailService.kt new file mode 100644 index 00000000..f209e90a --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/service/PrincipalDetailService.kt @@ -0,0 +1,19 @@ +package com.wespot.auth.service + +import com.wespot.auth.PrincipalDetails +import com.wespot.user.User +import com.wespot.user.port.out.UserPort +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.core.userdetails.UserDetailsService +import org.springframework.stereotype.Service +import java.util.NoSuchElementException + +@Service +class PrincipalDetailService( + private val userPort: UserPort +) : UserDetailsService { + override fun loadUserByUsername(userEmail: String): UserDetails { + val principal: User = userPort.getByEmail(userEmail) ?: throw NoSuchElementException("유저를 찾을 수 없습니다.") + return PrincipalDetails(principal) + } +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/wespot/user/port/out/UserPort.kt b/core/src/main/kotlin/com/wespot/user/port/out/UserPort.kt index 5f3ee89f..e736e0a9 100644 --- a/core/src/main/kotlin/com/wespot/user/port/out/UserPort.kt +++ b/core/src/main/kotlin/com/wespot/user/port/out/UserPort.kt @@ -3,8 +3,7 @@ package com.wespot.user.port.out import com.wespot.user.User import org.springframework.stereotype.Repository -@Repository -interface UserPort { // TODO: 자기야 이거 충돌좀 각오 해야하긴 할 것 같아.. +interface UserPort { fun findById(id: Long): User? @@ -12,8 +11,10 @@ interface UserPort { // TODO: 자기야 이거 충돌좀 각오 해야하긴 할 schoolId: Long, grade: Int, groupNumber: Int - ): List // TODO: 자기야 일단, 그냥 작업해놓을 테니까 나중에 Mapper로 바꿔줘 + ): List fun findIdsByIdIn(ids: List): List + fun getByEmail(userEmail: String): User? + } diff --git a/domain/src/main/kotlin/com/wespot/auth/PrincipalDetails.kt b/domain/src/main/kotlin/com/wespot/auth/PrincipalDetails.kt new file mode 100644 index 00000000..ffd33f3f --- /dev/null +++ b/domain/src/main/kotlin/com/wespot/auth/PrincipalDetails.kt @@ -0,0 +1,41 @@ +package com.wespot.auth + + +import com.wespot.user.User +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.userdetails.UserDetails + +class PrincipalDetails( + private val user: User +) : UserDetails { + + override fun getAuthorities(): MutableCollection { + val authorities: MutableCollection = ArrayList() + authorities.add(GrantedAuthority { user.role.name }) + return authorities + } + + override fun getPassword(): String { + return user.password + } + + override fun getUsername(): String { + return user.email + } + + override fun isAccountNonExpired(): Boolean { + return true + } + + override fun isAccountNonLocked(): Boolean { + return true + } + + override fun isCredentialsNonExpired(): Boolean { + return true + } + + override fun isEnabled(): Boolean { + return true + } +} From 8ee59502e254ec8151df4ce0e906d36e7e4882da Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 02:38:05 +0900 Subject: [PATCH 04/34] =?UTF-8?q?feat:=20=EC=8B=9C=ED=81=90=EB=A6=AC?= =?UTF-8?q?=ED=8B=B0=20=ED=95=84=ED=84=B0=20=EC=84=A4=EC=A0=95=20=EB=B0=8F?= =?UTF-8?q?=20JWT=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wespot/config/security/CustomUrlFilter.kt | 76 +++++++++++++ .../config/security/JwtAccessDeniedHandler.kt | 42 +++++++ .../security/JwtAuthenticationEntryPoint.kt | 43 ++++++++ .../security/JwtAuthenticationFilter.kt | 52 +++++++++ .../wespot/config/security/SecurityConfig.kt | 104 ++++++++++++++++++ .../auth/port/in/AuthenticationUseCase.kt | 9 ++ .../auth/service/AuthenticationService.kt | 33 ++++++ .../auth/service/jwt/JwtTokenValidator.kt | 31 ++++++ .../kotlin/com/wespot/auth/JwtTokenInfo.kt | 10 ++ 9 files changed, 400 insertions(+) create mode 100644 app/src/main/kotlin/com/wespot/config/security/CustomUrlFilter.kt create mode 100644 app/src/main/kotlin/com/wespot/config/security/JwtAccessDeniedHandler.kt create mode 100644 app/src/main/kotlin/com/wespot/config/security/JwtAuthenticationEntryPoint.kt create mode 100644 app/src/main/kotlin/com/wespot/config/security/JwtAuthenticationFilter.kt create mode 100644 app/src/main/kotlin/com/wespot/config/security/SecurityConfig.kt create mode 100644 core/src/main/kotlin/com/wespot/auth/port/in/AuthenticationUseCase.kt create mode 100644 core/src/main/kotlin/com/wespot/auth/service/AuthenticationService.kt create mode 100644 core/src/main/kotlin/com/wespot/auth/service/jwt/JwtTokenValidator.kt create mode 100644 domain/src/main/kotlin/com/wespot/auth/JwtTokenInfo.kt diff --git a/app/src/main/kotlin/com/wespot/config/security/CustomUrlFilter.kt b/app/src/main/kotlin/com/wespot/config/security/CustomUrlFilter.kt new file mode 100644 index 00000000..c69517b5 --- /dev/null +++ b/app/src/main/kotlin/com/wespot/config/security/CustomUrlFilter.kt @@ -0,0 +1,76 @@ +package com.wespot.config.security + +import com.fasterxml.jackson.databind.ObjectMapper +import jakarta.servlet.FilterChain +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ProblemDetail +import org.springframework.stereotype.Component +import org.springframework.util.AntPathMatcher +import org.springframework.web.filter.OncePerRequestFilter +import java.net.URI +import kotlin.text.Charsets.UTF_8 + +@Component +class CustomUrlFilter( + private val objectMapper: ObjectMapper +) : OncePerRequestFilter() { + + private val antPathMatcher = AntPathMatcher() + + private val validUrlPatterns = listOf( + "/health", + "/", + "/v1/auth/reissue", + "/v1/auth/admin", + "/v1/auth/login", + "/v1/auth/join", + ) + + override fun doFilterInternal( + request: HttpServletRequest, + response: HttpServletResponse, + filterChain: FilterChain + ) { + + if (!isValidUrl(request)) { + handleInvalidUrl(request, response) + return + } + filterChain.doFilter(request, response) + + } + + private fun isValidUrl(request: HttpServletRequest): Boolean { + + val requestUri = request.requestURI + + return validUrlPatterns.any { antPathMatcher.match(it, requestUri) } + + } + + private fun handleInvalidUrl( + request: HttpServletRequest, + response: HttpServletResponse + ) { + + response.contentType = MediaType.APPLICATION_JSON_VALUE + response.characterEncoding = UTF_8.name() + response.status = HttpStatus.NOT_FOUND.value() + + val body = objectMapper.writeValueAsString( + ProblemDetail.forStatusAndDetail( + HttpStatus.NOT_FOUND, + NoSuchFieldException("잘못된 URL입니다.").message!!, + ).apply { + type = URI.create("/errors/not-found") + instance = URI.create(request.requestURI) + } + ) + + response.writer.write(body) + + } +} diff --git a/app/src/main/kotlin/com/wespot/config/security/JwtAccessDeniedHandler.kt b/app/src/main/kotlin/com/wespot/config/security/JwtAccessDeniedHandler.kt new file mode 100644 index 00000000..98188cad --- /dev/null +++ b/app/src/main/kotlin/com/wespot/config/security/JwtAccessDeniedHandler.kt @@ -0,0 +1,42 @@ +package com.wespot.config.security + +import com.fasterxml.jackson.databind.ObjectMapper +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ProblemDetail +import org.springframework.security.access.AccessDeniedException +import org.springframework.security.web.access.AccessDeniedHandler +import org.springframework.stereotype.Component +import java.net.URI +import kotlin.text.Charsets.UTF_8 + +@Component +class JwtAccessDeniedHandler( + private val objectMapper: ObjectMapper +) : AccessDeniedHandler { + override fun handle( + request: HttpServletRequest, + response: HttpServletResponse, + exception: AccessDeniedException + ) { + + response.contentType = MediaType.APPLICATION_JSON_VALUE + response.characterEncoding = UTF_8.name() + response.status = HttpStatus.FORBIDDEN.value() + + val body = objectMapper.writeValueAsString( + ProblemDetail.forStatusAndDetail( + HttpStatus.UNAUTHORIZED, + AccessDeniedException("자신의 것만 가능합니다").message!!, + ).apply { + type = URI.create("/errors/forbidden") + instance = URI.create(request.requestURI) + } + ) + response.writer.write(body) + + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/wespot/config/security/JwtAuthenticationEntryPoint.kt b/app/src/main/kotlin/com/wespot/config/security/JwtAuthenticationEntryPoint.kt new file mode 100644 index 00000000..33ecf581 --- /dev/null +++ b/app/src/main/kotlin/com/wespot/config/security/JwtAuthenticationEntryPoint.kt @@ -0,0 +1,43 @@ +package com.wespot.config.security + +import com.fasterxml.jackson.databind.ObjectMapper +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ProblemDetail +import org.springframework.security.authentication.BadCredentialsException +import org.springframework.security.core.AuthenticationException +import org.springframework.security.web.AuthenticationEntryPoint +import org.springframework.stereotype.Component +import java.net.URI +import kotlin.text.Charsets.UTF_8 + +@Component +class JwtAuthenticationEntryPoint( + private val objectMapper: ObjectMapper +) : AuthenticationEntryPoint { + override fun commence( + request: HttpServletRequest, + response: HttpServletResponse, + authException: AuthenticationException? + ) { + + response.contentType = MediaType.APPLICATION_JSON_VALUE + response.characterEncoding = UTF_8.name() + response.status = HttpStatus.UNAUTHORIZED.value() + + val body = objectMapper.writeValueAsString( + ProblemDetail.forStatusAndDetail( + HttpStatus.UNAUTHORIZED, + BadCredentialsException("").message!!, + ).apply { + type = URI.create("/errors/unauthenticated") + instance = URI.create(request.requestURI) + } + ) + response.writer.write(body) + + } +} + diff --git a/app/src/main/kotlin/com/wespot/config/security/JwtAuthenticationFilter.kt b/app/src/main/kotlin/com/wespot/config/security/JwtAuthenticationFilter.kt new file mode 100644 index 00000000..40993f7a --- /dev/null +++ b/app/src/main/kotlin/com/wespot/config/security/JwtAuthenticationFilter.kt @@ -0,0 +1,52 @@ +package com.wespot.config.security + +import com.wespot.auth.JwtTokenInfo +import com.wespot.auth.port.`in`.AuthenticationUseCase +import jakarta.servlet.FilterChain +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.security.authentication.BadCredentialsException +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.stereotype.Component +import org.springframework.util.StringUtils +import org.springframework.web.filter.OncePerRequestFilter + +@Component +class JwtAuthenticationFilter( + private val authenticationUseCase: AuthenticationUseCase, + private val jwtAuthenticationEntryPoint: JwtAuthenticationEntryPoint, +) : OncePerRequestFilter() { + + override fun doFilterInternal( + request: HttpServletRequest, + response: HttpServletResponse, + filterChain: FilterChain + ) { + val token = extractToken(request) + if (token != null && StringUtils.hasText(token)) { + try { + authenticateUserByToken(token) + } catch (e: BadCredentialsException) { + jwtAuthenticationEntryPoint.commence(request, response, authException = null) + return + } + } + filterChain.doFilter(request, response) + } + + private fun authenticateUserByToken(token: String) { + try { + val authentication = authenticationUseCase.getAuthentication(token) + SecurityContextHolder.getContext().authentication = authentication + } catch (e: BadCredentialsException) { + SecurityContextHolder.clearContext() + } + } + + private fun extractToken(request: HttpServletRequest): String? { + val bearerToken = request.getHeader(JwtTokenInfo.AUTHORIZATION_HEADER) + return if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(JwtTokenInfo.BEARER_TYPE)) { + bearerToken.substring(JwtTokenInfo.BEARER_TYPE.length).trim() + } else null + } +} diff --git a/app/src/main/kotlin/com/wespot/config/security/SecurityConfig.kt b/app/src/main/kotlin/com/wespot/config/security/SecurityConfig.kt new file mode 100644 index 00000000..48850e6f --- /dev/null +++ b/app/src/main/kotlin/com/wespot/config/security/SecurityConfig.kt @@ -0,0 +1,104 @@ +package com.wespot.config.security + +import com.wespot.auth.service.PrincipalDetailService +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.http.HttpMethod +import org.springframework.security.authentication.AuthenticationManager +import org.springframework.security.authentication.ProviderManager +import org.springframework.security.authentication.dao.DaoAuthenticationProvider +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity +import org.springframework.security.config.http.SessionCreationPolicy +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder +import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.security.web.SecurityFilterChain +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter +import org.springframework.web.cors.CorsConfiguration +import org.springframework.web.cors.CorsConfigurationSource +import org.springframework.web.cors.UrlBasedCorsConfigurationSource + +@EnableWebSecurity +@Configuration +class SecurityConfig( + private val jwtAuthenticationEntryPoint: JwtAuthenticationEntryPoint, + private val jwtAccessDeniedHandler: JwtAccessDeniedHandler, + private val jwtAuthenticationFilter: JwtAuthenticationFilter, + private val principalDetailService: PrincipalDetailService, + private val customUrlFilter: CustomUrlFilter, +) { + + @Bean + fun passwordEncoder(): PasswordEncoder { + return BCryptPasswordEncoder() + } + + @Bean + fun authenticationManager(): AuthenticationManager? { + + val provider = DaoAuthenticationProvider() + provider.setPasswordEncoder(passwordEncoder()) + provider.setUserDetailsService(principalDetailService) + + return ProviderManager(provider) + + } + + @Bean + fun filterChain(http: HttpSecurity): SecurityFilterChain { + + http + .httpBasic { it.disable() } + .csrf { it.disable() } + .cors { } + .formLogin { it.disable() } + .sessionManagement { it.sessionCreationPolicy(SessionCreationPolicy.STATELESS) } + .exceptionHandling { + it.authenticationEntryPoint(jwtAuthenticationEntryPoint) + it.accessDeniedHandler(jwtAccessDeniedHandler) + + } + .authorizeHttpRequests { + it + .requestMatchers( + "/health", "/", + "/v1/auth/login", + "/v1/auth/join", + "/v1/auth/reissue", + ).permitAll() + .anyRequest().authenticated() + } + .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter::class.java) + .addFilterBefore(customUrlFilter, JwtAuthenticationFilter::class.java) + + return http.build() + + } + + @Bean + fun corsConfigurationSource(): CorsConfigurationSource { + + val configuration = CorsConfiguration().apply { + allowCredentials = true + allowedOrigins = listOf( + "https://api.lyfeteam.info", + "http://localhost:3000", + "http://localhost:8080", + ) + allowedMethods = listOf( + HttpMethod.POST.name(), + HttpMethod.GET.name(), + HttpMethod.PUT.name(), + HttpMethod.DELETE.name(), + HttpMethod.OPTIONS.name() + ) + allowedHeaders = listOf("*") + } + + val source = UrlBasedCorsConfigurationSource() + source.registerCorsConfiguration("/**", configuration) + + return source + + } +} diff --git a/core/src/main/kotlin/com/wespot/auth/port/in/AuthenticationUseCase.kt b/core/src/main/kotlin/com/wespot/auth/port/in/AuthenticationUseCase.kt new file mode 100644 index 00000000..0df617f0 --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/port/in/AuthenticationUseCase.kt @@ -0,0 +1,9 @@ +package com.wespot.auth.port.`in` + +import org.springframework.security.core.Authentication + +fun interface AuthenticationUseCase { + + fun getAuthentication(token: String): Authentication + +} diff --git a/core/src/main/kotlin/com/wespot/auth/service/AuthenticationService.kt b/core/src/main/kotlin/com/wespot/auth/service/AuthenticationService.kt new file mode 100644 index 00000000..0261a54e --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/service/AuthenticationService.kt @@ -0,0 +1,33 @@ +package com.wespot.auth.service + + +import com.wespot.auth.JwtTokenInfo.EMAIL_CLAIM +import com.wespot.auth.PrincipalDetails +import com.wespot.auth.port.`in`.AuthenticationUseCase +import com.wespot.auth.service.jwt.JwtTokenValidator +import io.jsonwebtoken.Claims +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +import org.springframework.security.core.Authentication +import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper +import org.springframework.stereotype.Component + +@Component +class AuthenticationService( + private val principalDetailService: PrincipalDetailService, + private val jwtTokenValidator: JwtTokenValidator, +) : AuthenticationUseCase { + + override fun getAuthentication(token: String): Authentication { + + val claims: Claims = jwtTokenValidator.verifyToken(token) + val email: String = claims[EMAIL_CLAIM] as String + val principalDetails = principalDetailService.loadUserByUsername(email) as PrincipalDetails + + return UsernamePasswordAuthenticationToken( + principalDetails, + principalDetails.password, + NullAuthoritiesMapper().mapAuthorities(principalDetails.authorities) + ) + } + +} diff --git a/core/src/main/kotlin/com/wespot/auth/service/jwt/JwtTokenValidator.kt b/core/src/main/kotlin/com/wespot/auth/service/jwt/JwtTokenValidator.kt new file mode 100644 index 00000000..3b53e630 --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/service/jwt/JwtTokenValidator.kt @@ -0,0 +1,31 @@ +package com.wespot.auth.service.jwt + +import io.jsonwebtoken.Claims +import io.jsonwebtoken.Jwts +import io.jsonwebtoken.security.Keys +import org.springframework.beans.factory.annotation.Value +import org.springframework.security.authentication.BadCredentialsException +import org.springframework.stereotype.Component +import java.security.Key + +@Component +class JwtTokenValidator( + @Value("\${jwt.secret}") + private val secretKey: String, +){ + private val key: Key = Keys.hmacShaKeyFor(secretKey.toByteArray()) + + fun verifyToken(token: String): Claims { + + try { + return Jwts.parserBuilder() + .setSigningKey(key) + .build() + .parseClaimsJws(token) + .body + } catch (e: Exception) { + throw BadCredentialsException("accessToken의 정보가 올바르지 않습니다.", e) + } + } + +} diff --git a/domain/src/main/kotlin/com/wespot/auth/JwtTokenInfo.kt b/domain/src/main/kotlin/com/wespot/auth/JwtTokenInfo.kt new file mode 100644 index 00000000..12c6ff07 --- /dev/null +++ b/domain/src/main/kotlin/com/wespot/auth/JwtTokenInfo.kt @@ -0,0 +1,10 @@ +package com.wespot.auth + +object JwtTokenInfo { + const val AUTHORIZATION_HEADER = "Authorization" + const val BEARER_TYPE = "Bearer" + const val EMAIL_CLAIM: String = "email" + const val ACCESS_TOKEN: String = "AccessToken" + const val REFRESH_TOKEN: String = "RefreshToken" + const val REFRESH_TOKEN_EXPIRY_DAYS = 30L +} \ No newline at end of file From bf66b7c1737ee63d9224d764f3cddbe7896fc5a4 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 02:39:47 +0900 Subject: [PATCH 05/34] =?UTF-8?q?feat:=20refreshToken=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wespot/auth/port/out/RefreshTokenPort.kt | 18 +++++++ .../kotlin/com/wespot/auth/RefreshToken.kt | 11 +++++ .../com/wespot/auth/RefreshTokenJpaEntity.kt | 37 ++++++++++++++ .../wespot/auth/RefreshTokenJpaRepository.kt | 9 ++++ .../com/wespot/auth/RefreshTokenMapper.kt | 24 +++++++++ .../auth/RefreshTokenPersistenceAdapter.kt | 49 +++++++++++++++++++ 6 files changed, 148 insertions(+) create mode 100644 core/src/main/kotlin/com/wespot/auth/port/out/RefreshTokenPort.kt create mode 100644 domain/src/main/kotlin/com/wespot/auth/RefreshToken.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenJpaEntity.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenJpaRepository.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenMapper.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenPersistenceAdapter.kt diff --git a/core/src/main/kotlin/com/wespot/auth/port/out/RefreshTokenPort.kt b/core/src/main/kotlin/com/wespot/auth/port/out/RefreshTokenPort.kt new file mode 100644 index 00000000..ac62e524 --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/port/out/RefreshTokenPort.kt @@ -0,0 +1,18 @@ +package com.wespot.auth.port.out + +import com.wespot.auth.RefreshToken +import com.wespot.user.User + +interface RefreshTokenPort { + + fun create(refreshToken: RefreshToken): RefreshToken + + fun findByUser(user: User): RefreshToken? + + fun saveOrUpdate(refreshToken: RefreshToken): RefreshToken + + fun deleteByUserId(userId: Long) + + fun findByRefreshToken(refreshToken: String): RefreshToken? + +} \ No newline at end of file diff --git a/domain/src/main/kotlin/com/wespot/auth/RefreshToken.kt b/domain/src/main/kotlin/com/wespot/auth/RefreshToken.kt new file mode 100644 index 00000000..36443224 --- /dev/null +++ b/domain/src/main/kotlin/com/wespot/auth/RefreshToken.kt @@ -0,0 +1,11 @@ +package com.wespot.auth + +import com.wespot.user.User +import java.time.LocalDateTime + +data class RefreshToken( + val id : Long, + val refreshToken: String, + val user: User, + val expiredAt: LocalDateTime? +) \ No newline at end of file diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenJpaEntity.kt new file mode 100644 index 00000000..cfc7e588 --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenJpaEntity.kt @@ -0,0 +1,37 @@ +package com.wespot.auth + +import com.wespot.user.entity.UserJpaEntity +import jakarta.persistence.* +import org.springframework.data.annotation.CreatedDate +import org.springframework.data.annotation.LastModifiedDate +import java.time.Instant +import java.time.LocalDateTime + + +@Entity +@Table(name = "refresh_token") +class RefreshTokenJpaEntity( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long = 0, + + val refreshToken: String, + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", foreignKey = ForeignKey(name = "fk_refresh_token_user_id")) + val user: UserJpaEntity, + + @CreatedDate + @LastModifiedDate + val createdAt: Instant? = null, + + @LastModifiedDate + val updatedAt: Instant? = null, + + @Column(name = "expired_at", columnDefinition = "Datetime", scale = 6) + val expiredAt: LocalDateTime? = null, +) { + +} + + diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenJpaRepository.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenJpaRepository.kt new file mode 100644 index 00000000..c0a30cdf --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenJpaRepository.kt @@ -0,0 +1,9 @@ +package com.wespot.auth + +import org.springframework.data.jpa.repository.JpaRepository + +interface RefreshTokenJpaRepository : JpaRepository { + fun deleteByUserId(userId: Long) + fun findByUserId(userId: Long): RefreshTokenJpaEntity? + fun findByRefreshToken(refreshToken: String): RefreshTokenJpaEntity? +} \ No newline at end of file diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenMapper.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenMapper.kt new file mode 100644 index 00000000..7382d45e --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenMapper.kt @@ -0,0 +1,24 @@ +package com.wespot.auth + +import com.wespot.user.mapper.UserMapper + +object RefreshTokenMapper { + + fun mapToJpaEntity(refreshToken: RefreshToken): RefreshTokenJpaEntity { + return RefreshTokenJpaEntity( + id = refreshToken.id, + refreshToken = refreshToken.refreshToken, + user = UserMapper.mapToJpaEntity(refreshToken.user), + expiredAt = refreshToken.expiredAt + ) + } + + fun mapToDomainEntity(refreshTokenJpaEntity: RefreshTokenJpaEntity): RefreshToken { + return RefreshToken( + id = refreshTokenJpaEntity.id, + refreshToken = refreshTokenJpaEntity.refreshToken, + user = UserMapper.mapToDomainEntity(refreshTokenJpaEntity.user), + expiredAt = refreshTokenJpaEntity.expiredAt + ) + } +} \ No newline at end of file diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenPersistenceAdapter.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenPersistenceAdapter.kt new file mode 100644 index 00000000..c187460e --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenPersistenceAdapter.kt @@ -0,0 +1,49 @@ +package com.wespot.auth + +import com.wespot.auth.port.out.RefreshTokenPort +import com.wespot.user.User +import org.springframework.data.repository.findByIdOrNull +import org.springframework.stereotype.Repository +import org.springframework.transaction.annotation.Transactional + +@Transactional(readOnly = true) +@Repository +class RefreshTokenPersistenceAdapter( + private val refreshTokenRepository: RefreshTokenJpaRepository +) : RefreshTokenPort { + override fun create(refreshToken: RefreshToken): RefreshToken { + return RefreshTokenMapper.mapToJpaEntity(refreshToken) + .let { refreshTokenRepository.save(it) } + .let { RefreshTokenMapper.mapToDomainEntity(it) } + } + + override fun findByUser(user: User): RefreshToken? { + return refreshTokenRepository.findByIdOrNull(user.id) + ?.let { RefreshTokenMapper.mapToDomainEntity(it) } + ?: throw NoSuchElementException("해당하는 유저의 RefreshToken이 없습니다.") + } + + override fun saveOrUpdate(refreshToken: RefreshToken): RefreshToken { + val refreshTokenJpaEntity = refreshTokenRepository.findByUserId(refreshToken.user.id) + return if (refreshTokenJpaEntity != null) { + RefreshTokenMapper.mapToJpaEntity(refreshToken) + .let { refreshTokenRepository.save(it) } + .let { RefreshTokenMapper.mapToDomainEntity(it) } + } else { + create(refreshToken) + } + } + + override fun deleteByUserId(userId: Long) { + refreshTokenRepository.deleteByUserId(userId) + } + + override fun findByRefreshToken(refreshToken: String): RefreshToken? { + val findByRefreshToken = refreshTokenRepository.findByRefreshToken(refreshToken) + if (findByRefreshToken != null) { + return RefreshTokenMapper.mapToDomainEntity(findByRefreshToken) + } + return null + } + +} \ No newline at end of file From 3bff1a28fcc5a29e43d276c454fbc626b63ca06b Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 02:41:25 +0900 Subject: [PATCH 06/34] =?UTF-8?q?feat:=20JWT=20Provider=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 1 - .../auth/service/jwt/JwtTokenProvider.kt | 58 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 core/src/main/kotlin/com/wespot/auth/service/jwt/JwtTokenProvider.kt diff --git a/build.gradle.kts b/build.gradle.kts index 44fb01d6..e7d38497 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -54,7 +54,6 @@ subprojects { implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") - implementation("mysql:mysql-connector-j") // https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on implementation("org.bouncycastle:bcpkix-jdk15on:1.69") diff --git a/core/src/main/kotlin/com/wespot/auth/service/jwt/JwtTokenProvider.kt b/core/src/main/kotlin/com/wespot/auth/service/jwt/JwtTokenProvider.kt new file mode 100644 index 00000000..1877b776 --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/service/jwt/JwtTokenProvider.kt @@ -0,0 +1,58 @@ +package com.wespot.auth.service.jwt + +import com.wespot.auth.JwtTokenInfo.ACCESS_TOKEN +import com.wespot.auth.JwtTokenInfo.EMAIL_CLAIM +import com.wespot.auth.JwtTokenInfo.REFRESH_TOKEN +import com.wespot.auth.dto.TokenResponse +import io.jsonwebtoken.Jwts +import io.jsonwebtoken.SignatureAlgorithm +import io.jsonwebtoken.security.Keys +import org.springframework.beans.factory.annotation.Value +import org.springframework.security.core.Authentication +import org.springframework.stereotype.Service +import java.security.Key +import java.util.* + + +@Service +class JwtTokenProvider( + @Value("\${jwt.secret}") + private val secretKey: String, + + @Value("\${jwt.accessTokenExpireTime}") + private val accessTokenExpireTime: Long, + + @Value("\${jwt.refreshTokenExpireTime}") + private val refreshTokenExpireTime: Long, + +) { + private val key: Key = Keys.hmacShaKeyFor(secretKey.toByteArray()) + + fun generateToken(authentication: Authentication): TokenResponse { + + val now = Date().time + val accessTokenExpiresIn = Date(now + accessTokenExpireTime) + + val accessToken = Jwts.builder() + .setSubject(ACCESS_TOKEN) + .claim(EMAIL_CLAIM, authentication.name) + .setExpiration(accessTokenExpiresIn) + .signWith(key, SignatureAlgorithm.HS256) + .compact() + + val refreshToken = Jwts.builder() + .setSubject(REFRESH_TOKEN) + .claim(EMAIL_CLAIM, authentication.name) + .setExpiration(Date(now + refreshTokenExpireTime)) + .signWith(key, SignatureAlgorithm.HS256) + .compact() + + return TokenResponse( + accessToken = accessToken, + refreshToken = refreshToken + ) + + } + +} + From da78e476e81acfbecdfc8e60f2bcbb054d4e57b1 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 11:49:02 +0900 Subject: [PATCH 07/34] =?UTF-8?q?refactor:=20BaseEntity=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt index ba571d1f..24533700 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt @@ -15,10 +15,11 @@ class BaseEntity( @CreatedDate @field: NotNull - @Column(updatable = false) - val createdAt: LocalDateTime, + @Column(updatable = false, nullable = false) + val createdAt: LocalDateTime = LocalDateTime.now(), @LastModifiedDate + @Column(nullable = false) val updatedAt: LocalDateTime? = null ) From 6846bd570dd3986541eb07276e2f002c845f8e69 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 11:51:16 +0900 Subject: [PATCH 08/34] =?UTF-8?q?refactor:=20School=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EB=A6=AC=ED=8E=99=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/com/wespot/school/EstType.kt | 4 ---- .../main/kotlin/com/wespot/school/School.kt | 23 +++++++++++++++++-- .../com/wespot/school/SchoolCategory.kt | 6 ----- .../kotlin/com/wespot/school/SchoolType.kt | 4 +++- .../com/wespot/school/SchoolJpaEntity.kt | 8 ++++++- 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/domain/src/main/kotlin/com/wespot/school/EstType.kt b/domain/src/main/kotlin/com/wespot/school/EstType.kt index c5e6f31f..e69de29b 100644 --- a/domain/src/main/kotlin/com/wespot/school/EstType.kt +++ b/domain/src/main/kotlin/com/wespot/school/EstType.kt @@ -1,4 +0,0 @@ -package com.wespot.school - -enum class EstType { // TODO : 이 부분은 같이 이야기하면서 구체화 해나가 보시죠! -} diff --git a/domain/src/main/kotlin/com/wespot/school/School.kt b/domain/src/main/kotlin/com/wespot/school/School.kt index f4f7486a..32c79cfd 100644 --- a/domain/src/main/kotlin/com/wespot/school/School.kt +++ b/domain/src/main/kotlin/com/wespot/school/School.kt @@ -1,12 +1,31 @@ package com.wespot.school +import com.wespot.user.User + data class School( val id: Long, + val user: User, val name: String, - val category: SchoolCategory, val schoolType: SchoolType, - val estType: EstType, val region: String, val address: String, ) { + + companion object { + fun create( + user: User, + name: String, + schoolType: SchoolType, + region: String, + address: String + ) = + School( + id = 0, + user = user, + name = name, + schoolType = schoolType, + region = region, + address = address + ) + } } diff --git a/domain/src/main/kotlin/com/wespot/school/SchoolCategory.kt b/domain/src/main/kotlin/com/wespot/school/SchoolCategory.kt index 214ec4c2..e69de29b 100644 --- a/domain/src/main/kotlin/com/wespot/school/SchoolCategory.kt +++ b/domain/src/main/kotlin/com/wespot/school/SchoolCategory.kt @@ -1,6 +0,0 @@ -package com.wespot.school - -enum class SchoolCategory { - MIDDLE, - HIGH, -} diff --git a/domain/src/main/kotlin/com/wespot/school/SchoolType.kt b/domain/src/main/kotlin/com/wespot/school/SchoolType.kt index 1111971e..8318dade 100644 --- a/domain/src/main/kotlin/com/wespot/school/SchoolType.kt +++ b/domain/src/main/kotlin/com/wespot/school/SchoolType.kt @@ -1,4 +1,6 @@ package com.wespot.school -enum class SchoolType { // TODO : 이 부분은 같이 이야기하면서 구체화 해나가 보시죠! +enum class SchoolType { + MIDDLE, + HIGH } diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolJpaEntity.kt index ee9f263f..6884b4a4 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolJpaEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolJpaEntity.kt @@ -1,5 +1,6 @@ package com.wespot.school +import com.wespot.user.entity.UserJpaEntity import jakarta.persistence.* import org.jetbrains.annotations.NotNull @@ -11,11 +12,16 @@ class SchoolJpaEntity( @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long, + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "users_id", foreignKey = ForeignKey(name = "fk_school_users_id")) + val user: UserJpaEntity, + @field:NotNull val name: String, @field:NotNull - val category: SchoolCategory, + @Enumerated(EnumType.STRING) + val schoolType: SchoolType, @field:NotNull val region: String, From 92f29c8312d19b93b7f7fa67768be1f7ef4b781e Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 11:51:55 +0900 Subject: [PATCH 09/34] =?UTF-8?q?feat:=20School=20Repositroy,=20mapper=20?= =?UTF-8?q?=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/wespot/school/port/out/SchoolPort.kt | 7 +++++ .../kotlin/com/wespot/school/SchoolMapper.kt | 26 +++++++++++++++++++ .../wespot/school/SchoolPersistentAdapter.kt | 16 ++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 core/src/main/kotlin/com/wespot/school/port/out/SchoolPort.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolMapper.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolPersistentAdapter.kt diff --git a/core/src/main/kotlin/com/wespot/school/port/out/SchoolPort.kt b/core/src/main/kotlin/com/wespot/school/port/out/SchoolPort.kt new file mode 100644 index 00000000..9a7ea101 --- /dev/null +++ b/core/src/main/kotlin/com/wespot/school/port/out/SchoolPort.kt @@ -0,0 +1,7 @@ +package com.wespot.school.port.out + +import com.wespot.school.School + +interface SchoolPort { + fun save(school: School): School +} \ No newline at end of file diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolMapper.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolMapper.kt new file mode 100644 index 00000000..5ec4f6cb --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolMapper.kt @@ -0,0 +1,26 @@ +package com.wespot.school + +import com.wespot.user.mapper.UserMapper + +object SchoolMapper { + + fun mapToDomainEntity(school: SchoolJpaEntity): School = + School( + id = school.id, + user = UserMapper.mapToDomainEntity(school.user), + name = school.name, + schoolType = school.schoolType, + region = school.region, + address = school.address, + ) + + fun mapToJpaEntity(school: School): SchoolJpaEntity = + SchoolJpaEntity( + id = school.id, + user = UserMapper.mapToJpaEntity(school.user), + name = school.name, + schoolType = school.schoolType, + region = school.region, + address = school.address, + ) +} \ No newline at end of file diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolPersistentAdapter.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolPersistentAdapter.kt new file mode 100644 index 00000000..1dd3e654 --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolPersistentAdapter.kt @@ -0,0 +1,16 @@ +package com.wespot.school + +import com.wespot.school.port.out.SchoolPort +import org.springframework.stereotype.Repository + +@Repository +class SchoolPersistentAdapter( + private val schoolJpaRepository: SchoolJpaRepository +): SchoolPort { + + override fun save(school: School): School { + return schoolJpaRepository.save(SchoolMapper.mapToJpaEntity(school)) + .let { SchoolMapper.mapToDomainEntity(it) } + } + +} From 66f64894883a8bd80244dd79bcf5dee32b7da463 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 11:52:28 +0900 Subject: [PATCH 10/34] =?UTF-8?q?feat:=20Profile=20Repositroy,=20mapper=20?= =?UTF-8?q?=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/wespot/user/port/out/ProfilePort.kt | 8 +++++++ .../main/kotlin/com/wespot/user/Profile.kt | 15 ++++++++++++ .../wespot/user/entity/ProfileJpaEntity.kt | 24 +++++++++++++++++++ .../com/wespot/user/mapper/ProfileMapper.kt | 23 ++++++++++++++++++ .../user/repository/ProfileJpaRepository.kt | 7 ++++++ 5 files changed, 77 insertions(+) create mode 100644 core/src/main/kotlin/com/wespot/user/port/out/ProfilePort.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/ProfileJpaEntity.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/ProfileMapper.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/ProfileJpaRepository.kt diff --git a/core/src/main/kotlin/com/wespot/user/port/out/ProfilePort.kt b/core/src/main/kotlin/com/wespot/user/port/out/ProfilePort.kt new file mode 100644 index 00000000..f03ed90d --- /dev/null +++ b/core/src/main/kotlin/com/wespot/user/port/out/ProfilePort.kt @@ -0,0 +1,8 @@ +package com.wespot.user.port.out + +import com.wespot.user.Profile + +interface ProfilePort { + + fun save(profile: Profile): Profile +} \ No newline at end of file diff --git a/domain/src/main/kotlin/com/wespot/user/Profile.kt b/domain/src/main/kotlin/com/wespot/user/Profile.kt index 8976b114..07cc276d 100644 --- a/domain/src/main/kotlin/com/wespot/user/Profile.kt +++ b/domain/src/main/kotlin/com/wespot/user/Profile.kt @@ -2,7 +2,22 @@ package com.wespot.user data class Profile( val id: Long, + val user: User, val backgroundColor: String, val iconUrl: String, ) { + + companion object { + fun create( + user: User, + backgroundColor: String, + iconUrl: String + ) = + Profile( + id = 0, + user = user, + backgroundColor = backgroundColor, + iconUrl = iconUrl + ) + } } diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/ProfileJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/ProfileJpaEntity.kt new file mode 100644 index 00000000..fe330969 --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/ProfileJpaEntity.kt @@ -0,0 +1,24 @@ +package com.wespot.user.entity + +import jakarta.persistence.* +import org.jetbrains.annotations.NotNull + +@Entity +@Table(name = "fcm") +class ProfileJpaEntity( + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long, + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "users_id", foreignKey = ForeignKey(name = "fk_profile_users_id")) + val user: UserJpaEntity, + + @field: NotNull + val backgroundColor: String, + + @field: NotNull + val iconUrl: String + +) diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/ProfileMapper.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/ProfileMapper.kt new file mode 100644 index 00000000..6bd234aa --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/ProfileMapper.kt @@ -0,0 +1,23 @@ +package com.wespot.user.mapper + +import com.wespot.user.Profile +import com.wespot.user.entity.ProfileJpaEntity + +object ProfileMapper { + + fun mapToDomainEntity(profile: ProfileJpaEntity): Profile = + Profile( + id = profile.id, + user = UserMapper.mapToDomainEntity(profile.user), + backgroundColor = profile.backgroundColor, + iconUrl = profile.iconUrl + ) + + fun mapToJpaEntity(profile: Profile): ProfileJpaEntity = + ProfileJpaEntity( + id = profile.id, + user = UserMapper.mapToJpaEntity(profile.user), + backgroundColor = profile.backgroundColor, + iconUrl = profile.iconUrl + ) +} \ No newline at end of file diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/ProfileJpaRepository.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/ProfileJpaRepository.kt new file mode 100644 index 00000000..da768356 --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/ProfileJpaRepository.kt @@ -0,0 +1,7 @@ +package com.wespot.user.repository + +import com.wespot.user.entity.ProfileJpaEntity +import org.springframework.data.jpa.repository.JpaRepository + +interface ProfileJpaRepository: JpaRepository { +} \ No newline at end of file From 1bc7c8e422e5cdc2ba86420cbeade40cbb485e96 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 12:24:19 +0900 Subject: [PATCH 11/34] =?UTF-8?q?refactor:=20Setting,=20FCM=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- domain/src/main/kotlin/com/wespot/user/FCM.kt | 5 +++-- .../main/kotlin/com/wespot/user/Setting.kt | 3 +-- .../com/wespot/user/SettingJpaEntity.kt | 21 ------------------- .../wespot/user/{ => entity}/FCMJpaEntity.kt | 10 ++++++--- .../wespot/user/entity/SettingJpaEntity.kt | 12 +++++++++++ 5 files changed, 23 insertions(+), 28 deletions(-) rename infrastructure/mysql/src/main/kotlin/com/wespot/user/{ => entity}/FCMJpaEntity.kt (66%) create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/SettingJpaEntity.kt diff --git a/domain/src/main/kotlin/com/wespot/user/FCM.kt b/domain/src/main/kotlin/com/wespot/user/FCM.kt index 85fc00d3..5db3229d 100644 --- a/domain/src/main/kotlin/com/wespot/user/FCM.kt +++ b/domain/src/main/kotlin/com/wespot/user/FCM.kt @@ -4,7 +4,8 @@ import java.time.LocalDateTime data class FCM( val id: Long, - val fcmToken: String, - val createdAt: LocalDateTime, + val user: User, + val fcmToken: String?, + val createdAt: LocalDateTime?, ) { } diff --git a/domain/src/main/kotlin/com/wespot/user/Setting.kt b/domain/src/main/kotlin/com/wespot/user/Setting.kt index 1305e8d3..c9c63d5c 100644 --- a/domain/src/main/kotlin/com/wespot/user/Setting.kt +++ b/domain/src/main/kotlin/com/wespot/user/Setting.kt @@ -1,7 +1,6 @@ package com.wespot.user data class Setting( - val id: Long, - val isEnableNotification: Boolean, + val isEnableNotification: Boolean = false ) { } diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/SettingJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/SettingJpaEntity.kt index 7c90c246..e69de29b 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/SettingJpaEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/SettingJpaEntity.kt @@ -1,21 +0,0 @@ -package com.wespot.user - -import jakarta.persistence.Entity -import jakarta.persistence.GeneratedValue -import jakarta.persistence.GenerationType -import jakarta.persistence.Id -import jakarta.persistence.Table -import org.jetbrains.annotations.NotNull - -@Entity -@Table(name = "setting") -class SettingJpaEntity( - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - val id: Long, - - @field: NotNull - val isEnableNotification: Boolean - -) diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/FCMJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/FCMJpaEntity.kt similarity index 66% rename from infrastructure/mysql/src/main/kotlin/com/wespot/user/FCMJpaEntity.kt rename to infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/FCMJpaEntity.kt index 20eae714..692a1d8c 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/FCMJpaEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/FCMJpaEntity.kt @@ -1,4 +1,4 @@ -package com.wespot.user +package com.wespot.user.entity import com.wespot.common.BaseEntity import jakarta.persistence.Embedded @@ -17,11 +17,15 @@ class FCMJpaEntity( @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long, + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "users_id", foreignKey = ForeignKey(name = "fk_fcm_users_id")) + val user: UserJpaEntity, + @field: NotNull - val fcmToken: String, + val fcmToken: String?, @Embedded @field: NotNull - val baseEntity: BaseEntity + val baseEntity: BaseEntity? ) diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/SettingJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/SettingJpaEntity.kt new file mode 100644 index 00000000..8b4b5a1e --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/SettingJpaEntity.kt @@ -0,0 +1,12 @@ +package com.wespot.user.entity + +import jakarta.persistence.* +import org.jetbrains.annotations.NotNull + +@Embeddable +class SettingJpaEntity( + + @field: NotNull + val isEnableNotification: Boolean + +) From 412af65bf42876c1cd057ab25e8203b770f235ca Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 12:25:26 +0900 Subject: [PATCH 12/34] =?UTF-8?q?feat:=20UserConsent=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wespot/user/port/out/UserConsentPort.kt | 8 ++++++ .../kotlin/com/wespot/user/ConsentType.kt | 5 ++++ .../kotlin/com/wespot/user/UserConsent.kt | 27 +++++++++++++++++++ .../adapter/UserConsentPersistentAdapter.kt | 19 +++++++++++++ .../user/entity/UserConsentJpaEntity.kt | 25 +++++++++++++++++ .../wespot/user/mapper/UserConsentMapper.kt | 26 ++++++++++++++++++ .../repository/UserConsentJpaRepository.kt | 7 +++++ 7 files changed, 117 insertions(+) create mode 100644 core/src/main/kotlin/com/wespot/user/port/out/UserConsentPort.kt create mode 100644 domain/src/main/kotlin/com/wespot/user/ConsentType.kt create mode 100644 domain/src/main/kotlin/com/wespot/user/UserConsent.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserConsentPersistentAdapter.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserConsentJpaEntity.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserConsentMapper.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/UserConsentJpaRepository.kt diff --git a/core/src/main/kotlin/com/wespot/user/port/out/UserConsentPort.kt b/core/src/main/kotlin/com/wespot/user/port/out/UserConsentPort.kt new file mode 100644 index 00000000..029e7f61 --- /dev/null +++ b/core/src/main/kotlin/com/wespot/user/port/out/UserConsentPort.kt @@ -0,0 +1,8 @@ +package com.wespot.user.port.out + +import com.wespot.user.UserConsent + +interface UserConsentPort { + + fun save(userConsent: UserConsent): UserConsent +} \ No newline at end of file diff --git a/domain/src/main/kotlin/com/wespot/user/ConsentType.kt b/domain/src/main/kotlin/com/wespot/user/ConsentType.kt new file mode 100644 index 00000000..f697233f --- /dev/null +++ b/domain/src/main/kotlin/com/wespot/user/ConsentType.kt @@ -0,0 +1,5 @@ +package com.wespot.user + +enum class ConsentType { + MARKETING, // 마케팅 +} diff --git a/domain/src/main/kotlin/com/wespot/user/UserConsent.kt b/domain/src/main/kotlin/com/wespot/user/UserConsent.kt new file mode 100644 index 00000000..5fdc0225 --- /dev/null +++ b/domain/src/main/kotlin/com/wespot/user/UserConsent.kt @@ -0,0 +1,27 @@ +package com.wespot.user + +import java.time.LocalDateTime + +data class UserConsent( + val id: Long, + val user: User, + val consentType: ConsentType?, + val consentValue: Boolean?, + val consentedAt: LocalDateTime? +) { + companion object { + fun create( + user: User, + consentType: ConsentType, + consentValue: Boolean, + consentedAt: LocalDateTime + ) = + UserConsent( + id = 0, + user = user, + consentType = consentType, + consentValue = consentValue, + consentedAt = consentedAt + ) + } +} diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserConsentPersistentAdapter.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserConsentPersistentAdapter.kt new file mode 100644 index 00000000..92ce6bc4 --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserConsentPersistentAdapter.kt @@ -0,0 +1,19 @@ +package com.wespot.user.adapter + +import com.wespot.user.UserConsent +import com.wespot.user.mapper.UserConsentMapper +import com.wespot.user.port.out.UserConsentPort +import com.wespot.user.repository.UserConsentJpaRepository +import org.springframework.stereotype.Repository + +@Repository +class UserConsentPersistentAdapter( + private val userConsentJpaRepository: UserConsentJpaRepository +) : UserConsentPort { + + override fun save(userConsent: UserConsent): UserConsent { + return userConsentJpaRepository.save(UserConsentMapper.mapToJpaEntity(userConsent)) + .let { UserConsentMapper.mapToDomainEntity(it) } + } + +} diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserConsentJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserConsentJpaEntity.kt new file mode 100644 index 00000000..d2fbddb0 --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserConsentJpaEntity.kt @@ -0,0 +1,25 @@ +package com.wespot.user.entity + +import com.wespot.user.ConsentType +import jakarta.persistence.* +import java.time.LocalDateTime + +@Entity +@Table(name = "user_consent") +class UserConsentJpaEntity ( + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long, + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "users_id", foreignKey = ForeignKey(name = "fk_user_consent_users_id")) + val user: UserJpaEntity, + + @Enumerated(EnumType.STRING) + val consentType: ConsentType?, + + val consentValue : Boolean?, + + val consentedAt: LocalDateTime? +) \ No newline at end of file diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserConsentMapper.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserConsentMapper.kt new file mode 100644 index 00000000..96f85e07 --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserConsentMapper.kt @@ -0,0 +1,26 @@ +package com.wespot.user.mapper + +import com.wespot.user.UserConsent +import com.wespot.user.entity.UserConsentJpaEntity + +object UserConsentMapper { + + fun mapToDomainEntity(userConsentJpaEntity: UserConsentJpaEntity): UserConsent = + UserConsent( + id = userConsentJpaEntity.id, + user = UserMapper.mapToDomainEntity(userConsentJpaEntity.user), + consentType = userConsentJpaEntity.consentType, + consentValue = userConsentJpaEntity.consentValue, + consentedAt = userConsentJpaEntity.consentedAt, + ) + + + fun mapToJpaEntity(userConsent: UserConsent): UserConsentJpaEntity = + UserConsentJpaEntity( + id = userConsent.id, + user = UserMapper.mapToJpaEntity(userConsent.user), + consentType = userConsent.consentType, + consentValue = userConsent.consentValue, + consentedAt = userConsent.consentedAt, + ) +} \ No newline at end of file diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/UserConsentJpaRepository.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/UserConsentJpaRepository.kt new file mode 100644 index 00000000..465e6e0d --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/UserConsentJpaRepository.kt @@ -0,0 +1,7 @@ +package com.wespot.user.repository + +import com.wespot.user.entity.UserConsentJpaEntity +import org.springframework.data.jpa.repository.JpaRepository + +interface UserConsentJpaRepository: JpaRepository { +} \ No newline at end of file From 6efb8501f8185bee9eb080700f3d7f7e5e9e51d8 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 12:27:31 +0900 Subject: [PATCH 13/34] =?UTF-8?q?refactor:=20Social=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/kotlin/com/wespot/user/Social.kt | 19 ++++++++++++++++-- .../com/wespot/user/entity/SocialJpaEntity.kt | 20 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/SocialJpaEntity.kt diff --git a/domain/src/main/kotlin/com/wespot/user/Social.kt b/domain/src/main/kotlin/com/wespot/user/Social.kt index b066cd4c..96d76f2a 100644 --- a/domain/src/main/kotlin/com/wespot/user/Social.kt +++ b/domain/src/main/kotlin/com/wespot/user/Social.kt @@ -2,8 +2,23 @@ package com.wespot.user data class Social( val socialType: SocialType, - val socialId: Long, + val socialId: String, val socialEmail: String?, - val socialRefreshToken: String + val socialRefreshToken: String? ) { + + companion object{ + fun create( + email : String, + socialEmail: String, + socialRefreshToken: String + ): Social { + return Social( + socialType = SocialType.valueOf(email.split("@")[1]), + socialId = email.split("@")[0], + socialEmail = socialEmail, + socialRefreshToken = socialRefreshToken + ) + } + } } diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/SocialJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/SocialJpaEntity.kt new file mode 100644 index 00000000..235d1dc6 --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/SocialJpaEntity.kt @@ -0,0 +1,20 @@ +package com.wespot.user.entity + +import com.wespot.user.SocialType +import jakarta.persistence.Embeddable +import org.jetbrains.annotations.NotNull + +@Embeddable +class SocialJpaEntity( + + @field: NotNull + val socialId: String, + + @field: NotNull + val socialType: SocialType, + + val socialEmail: String?, + + val socialRefreshToken: String? + +) \ No newline at end of file From 8f610857d6a25255e99021015f40acd56de97f76 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 12:28:38 +0900 Subject: [PATCH 14/34] =?UTF-8?q?refactor:=20User=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20Role=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/wespot/user/port/out/UserPort.kt | 6 ++ .../src/main/kotlin/com/wespot/user/Role.kt | 1 + .../src/main/kotlin/com/wespot/user/User.kt | 40 +++++++++- .../kotlin/com/wespot/user/UserJpaEntity.kt | 78 ------------------- .../user/adapter/ProfilePersistentAdapter.kt | 19 +++++ .../user/adapter/UserPersistenceAdapter.kt | 30 +++++++ .../com/wespot/user/entity/UserJpaEntity.kt | 50 ++++++++++++ .../com/wespot/user/mapper/UserMapper.kt | 57 ++++++++++++++ .../user/repository/UserJpaRepository.kt | 10 +++ 9 files changed, 210 insertions(+), 81 deletions(-) delete mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/UserJpaEntity.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/ProfilePersistentAdapter.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserJpaEntity.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserMapper.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/UserJpaRepository.kt diff --git a/core/src/main/kotlin/com/wespot/user/port/out/UserPort.kt b/core/src/main/kotlin/com/wespot/user/port/out/UserPort.kt index e736e0a9..7cb07544 100644 --- a/core/src/main/kotlin/com/wespot/user/port/out/UserPort.kt +++ b/core/src/main/kotlin/com/wespot/user/port/out/UserPort.kt @@ -17,4 +17,10 @@ interface UserPort { fun getByEmail(userEmail: String): User? + fun findByEmail(userEmail: String): User? + + fun save(user: User): User + + fun findById(userId: Long): User? + } diff --git a/domain/src/main/kotlin/com/wespot/user/Role.kt b/domain/src/main/kotlin/com/wespot/user/Role.kt index 97f4a9bb..f02e013a 100644 --- a/domain/src/main/kotlin/com/wespot/user/Role.kt +++ b/domain/src/main/kotlin/com/wespot/user/Role.kt @@ -1,6 +1,7 @@ package com.wespot.user enum class Role { + GUEST, USER, ADMIN } diff --git a/domain/src/main/kotlin/com/wespot/user/User.kt b/domain/src/main/kotlin/com/wespot/user/User.kt index 7421a3a3..0dffab00 100644 --- a/domain/src/main/kotlin/com/wespot/user/User.kt +++ b/domain/src/main/kotlin/com/wespot/user/User.kt @@ -1,5 +1,6 @@ package com.wespot.user +import com.wespot.school.School import java.time.LocalDateTime data class User( @@ -13,11 +14,44 @@ data class User( val grade: Int, val groupNumber: Int, val setting: Setting, - val profile: Profile, - val fcm: FCM, val social: Social, val createdAt: LocalDateTime, val updatedAt: LocalDateTime?, - val withdrawAt: LocalDateTime, + val withdrawAt: LocalDateTime?, ) { + + fun withdraw(user: User) = + User( + id = id, + email = email, + password = password, + role = Role.GUEST, + grade = grade, + groupNumber = groupNumber, + setting = setting, + social = social, + createdAt = createdAt, + updatedAt = LocalDateTime.now(), + withdrawAt = LocalDateTime.now(), + ) + + companion object { + fun create( + email: String, + password: String, + grade: Int, + groupNumber: Int, + social: Social + ) = + User( + id = 0, + email = email, + password = password, + role = Role.USER, + grade = grade, + groupNumber = groupNumber, + setting = Setting(), + social = social, + ) + } } diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/UserJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/UserJpaEntity.kt deleted file mode 100644 index e8abc202..00000000 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/UserJpaEntity.kt +++ /dev/null @@ -1,78 +0,0 @@ -package com.wespot.user - -import com.wespot.common.BaseEntity -import jakarta.persistence.CascadeType -import jakarta.persistence.Embedded -import jakarta.persistence.Entity -import jakarta.persistence.FetchType -import jakarta.persistence.ForeignKey -import jakarta.persistence.GeneratedValue -import jakarta.persistence.GenerationType -import jakarta.persistence.Id -import jakarta.persistence.JoinColumn -import jakarta.persistence.OneToOne -import jakarta.persistence.Table -import org.jetbrains.annotations.NotNull -import java.time.LocalDateTime - -@Entity -@Table(name = "users") -class UserJpaEntity( - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - val id: Long, - - @field: NotNull - val email: String, - - @field: NotNull - val password: String, - - @field: NotNull - val name: String, - - @field: NotNull - val introduction: String, - - @field: NotNull - val schoolId: Long, - - @field: NotNull - val grade: Int, - - @field: NotNull - val groupNumber: Int, - - @OneToOne(fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST]) - @JoinColumn( - name = "setting_id", foreignKey = ForeignKey(name = "fk_users_setting_id") - ) - @field: NotNull - val setting: SettingJpaEntity, - - @OneToOne(fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST]) - @JoinColumn( - name = "profile_id", foreignKey = ForeignKey(name = "fk_users_profile_id") - ) - @field: NotNull - val profile: ProfileJpaEntity, - - @OneToOne(fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST]) - @JoinColumn( - name = "fcm_id", foreignKey = ForeignKey(name = "fk_users_fcm_id") - ) - val fcm: FCMJpaEntity, - - @Embedded - val social: SocialJpaEntity, - - @Embedded - @field: NotNull - val baseEntity: BaseEntity, - - val withdrawAt: LocalDateTime - -) { - -} diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/ProfilePersistentAdapter.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/ProfilePersistentAdapter.kt new file mode 100644 index 00000000..30355c0d --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/ProfilePersistentAdapter.kt @@ -0,0 +1,19 @@ +package com.wespot.user.adapter + +import com.wespot.user.Profile +import com.wespot.user.mapper.ProfileMapper +import com.wespot.user.port.out.ProfilePort +import com.wespot.user.repository.ProfileJpaRepository +import org.springframework.stereotype.Repository + +@Repository +class ProfilePersistentAdapter( + private val profileJpaRepository: ProfileJpaRepository +): ProfilePort { + + override fun save(profile: Profile): Profile { + return profileJpaRepository.save(ProfileMapper.mapToJpaEntity(profile)) + .let { ProfileMapper.mapToDomainEntity(it) } + } + +} diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt new file mode 100644 index 00000000..f448afa5 --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt @@ -0,0 +1,30 @@ +package com.wespot.user.adapter + +import com.wespot.user.User +import com.wespot.user.repository.UserJpaRepository +import com.wespot.user.mapper.UserMapper +import com.wespot.user.port.out.UserPort +import org.springframework.stereotype.Repository + +@Repository +class UserPersistenceAdapter( + private val userJpaRepository: UserJpaRepository, +) : UserPort { + + override fun findByEmail(userEmail: String): User? { + return userJpaRepository.findByEmail(userEmail) + ?.let { UserMapper.mapToDomainEntity(it) } + } + + override fun save(user: User): User { + return userJpaRepository.save(UserMapper.mapToJpaEntity(user)) + .let { UserMapper.mapToDomainEntity(it) } + } + + override fun findById(userId: Long): User? { + return userJpaRepository.findById(userId) + .orElseThrow { NoSuchElementException("유저를 찾을 수 없습니다.") } + .let { UserMapper.mapToDomainEntity(it) } + } + +} \ No newline at end of file diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserJpaEntity.kt new file mode 100644 index 00000000..cd31fabc --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserJpaEntity.kt @@ -0,0 +1,50 @@ +package com.wespot.user + +import com.wespot.common.BaseEntity +import jakarta.persistence.* +import org.jetbrains.annotations.NotNull +import java.time.LocalDateTime + +@Entity +@Table(name = "users") +class UserJpaEntity( + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long, + + @field: NotNull + val email: String, + + @field: NotNull + val password: String, + + @field: NotNull + val schoolId: Long, + + @field: NotNull + val grade: Int, + + @field: NotNull + val groupNumber: Int, + + @Embedded + @field: NotNull + val setting: SettingJpaEntity, + + @Embedded + val social: SocialJpaEntity, + + @Enumerated(EnumType.STRING) + val role: Role, + + val withdrawAt: LocalDateTime?, + + @Embedded + @field: NotNull + val baseEntity: BaseEntity, + + +) { + +} diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserMapper.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserMapper.kt new file mode 100644 index 00000000..f82efa97 --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserMapper.kt @@ -0,0 +1,57 @@ +package com.wespot.user.mapper + +import com.wespot.common.BaseEntity +import com.wespot.school.School +import com.wespot.school.SchoolJpaEntity +import com.wespot.user.* +import com.wespot.user.entity.* + +object UserMapper { + + fun mapToDomainEntity(user: UserJpaEntity): User = + User( + id = user.id, + email = user.email, + password = user.password, + setting = Setting( + isEnableNotification = user.setting.isEnableNotification, + ), + grade = user.grade, + groupNumber = user.groupNumber, + role = user.role, + social = Social( + socialType = user.social.socialType, + socialId = user.social.socialId, + socialEmail = user.social.socialEmail, + socialRefreshToken = user.social.socialRefreshToken, + ), + createdAt = user.baseEntity.createdAt, + updatedAt = user.baseEntity.updatedAt, + withdrawAt = user.withdrawAt, + ) + + + fun mapToJpaEntity(user: User): UserJpaEntity = + UserJpaEntity( + id = user.id, + email = user.email, + password = user.password, + setting = SettingJpaEntity( + isEnableNotification = user.setting.isEnableNotification, + ), + grade = user.grade, + groupNumber = user.groupNumber, + role = user.role, + social = SocialJpaEntity( + socialType = user.social.socialType, + socialId = user.social.socialId, + socialEmail = user.social.socialEmail, + socialRefreshToken = user.social.socialRefreshToken, + ), + withdrawAt = user.withdrawAt, + baseEntity = BaseEntity( + createdAt = user.createdAt, + updatedAt = user.updatedAt, + ), + ) +} \ No newline at end of file diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/UserJpaRepository.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/UserJpaRepository.kt new file mode 100644 index 00000000..1aed31b1 --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/UserJpaRepository.kt @@ -0,0 +1,10 @@ +package com.wespot.user.repository + +import com.wespot.user.entity.UserJpaEntity +import org.springframework.data.jpa.repository.JpaRepository + +interface UserJpaRepository : JpaRepository { + + fun findByEmail(email: String): UserJpaEntity? + +} \ No newline at end of file From 8cd802b3c0ffb926849fdd30127e00a98a444850 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 12:31:18 +0900 Subject: [PATCH 15/34] =?UTF-8?q?feat:=20Auth=20Dto=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/main/kotlin/com/wespot/auth/dto/AuthData.kt | 7 +++++++ .../com/wespot/auth/dto/OAuthIdAndRefreshToken.kt | 6 ------ .../kotlin/com/wespot/auth/dto/ProfileRequest.kt | 6 ++++++ .../main/kotlin/com/wespot/auth/dto/SchoolRequest.kt | 10 ++++++++++ .../main/kotlin/com/wespot/auth/dto/SignInRequest.kt | 12 ++++++++++++ .../kotlin/com/wespot/auth/dto/SignInResponse.kt | 6 ++++++ .../main/kotlin/com/wespot/auth/dto/SignUpRequest.kt | 10 ++++++++++ .../kotlin/com/wespot/auth/dto/SignUpResponse.kt | 5 +++++ .../kotlin/com/wespot/auth/dto/SocialResponse.kt | 7 +++++++ .../main/kotlin/com/wespot/auth/dto/TokenResponse.kt | 6 ++++++ .../kotlin/com/wespot/auth/dto/UserConsentRequest.kt | 8 ++++++++ .../wespot/auth/service/PrincipalDetailService.kt | 4 +++- .../com/wespot/auth/service/SocialAuthService.kt | 8 ++++++-- .../wespot/auth/service/SocialAuthServiceFactory.kt | 1 - .../com/wespot/auth/service/apple/AppleService.kt | 11 ++++++----- .../com/wespot/auth/service/jwt/JwtTokenProvider.kt | 2 +- .../com/wespot/auth/service/kakao/KakaoService.kt | 10 ++++++---- infrastructure/mysql/build.gradle.kts | 6 ++++++ 18 files changed, 105 insertions(+), 20 deletions(-) create mode 100644 core/src/main/kotlin/com/wespot/auth/dto/AuthData.kt delete mode 100644 core/src/main/kotlin/com/wespot/auth/dto/OAuthIdAndRefreshToken.kt create mode 100644 core/src/main/kotlin/com/wespot/auth/dto/ProfileRequest.kt create mode 100644 core/src/main/kotlin/com/wespot/auth/dto/SchoolRequest.kt create mode 100644 core/src/main/kotlin/com/wespot/auth/dto/SignInRequest.kt create mode 100644 core/src/main/kotlin/com/wespot/auth/dto/SignInResponse.kt create mode 100644 core/src/main/kotlin/com/wespot/auth/dto/SignUpRequest.kt create mode 100644 core/src/main/kotlin/com/wespot/auth/dto/SignUpResponse.kt create mode 100644 core/src/main/kotlin/com/wespot/auth/dto/SocialResponse.kt create mode 100644 core/src/main/kotlin/com/wespot/auth/dto/TokenResponse.kt create mode 100644 core/src/main/kotlin/com/wespot/auth/dto/UserConsentRequest.kt diff --git a/core/src/main/kotlin/com/wespot/auth/dto/AuthData.kt b/core/src/main/kotlin/com/wespot/auth/dto/AuthData.kt new file mode 100644 index 00000000..39dd1767 --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/dto/AuthData.kt @@ -0,0 +1,7 @@ +package com.wespot.auth.dto + +data class AuthData( + val email: String, + val socialRefreshToken: String, + val socialEmail: String, +) \ No newline at end of file diff --git a/core/src/main/kotlin/com/wespot/auth/dto/OAuthIdAndRefreshToken.kt b/core/src/main/kotlin/com/wespot/auth/dto/OAuthIdAndRefreshToken.kt deleted file mode 100644 index 1f4fc25a..00000000 --- a/core/src/main/kotlin/com/wespot/auth/dto/OAuthIdAndRefreshToken.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.wespot.auth.dto - -data class OAuthIdAndRefreshToken( - val oAuthId: String, - val refreshToken: String -) diff --git a/core/src/main/kotlin/com/wespot/auth/dto/ProfileRequest.kt b/core/src/main/kotlin/com/wespot/auth/dto/ProfileRequest.kt new file mode 100644 index 00000000..1b8eb34f --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/dto/ProfileRequest.kt @@ -0,0 +1,6 @@ +package com.wespot.auth.dto + +data class ProfileRequest( + val backgroundColor: String, + val iconUrl: String, +) diff --git a/core/src/main/kotlin/com/wespot/auth/dto/SchoolRequest.kt b/core/src/main/kotlin/com/wespot/auth/dto/SchoolRequest.kt new file mode 100644 index 00000000..ad2f8ced --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/dto/SchoolRequest.kt @@ -0,0 +1,10 @@ +package com.wespot.auth.dto + +import com.wespot.school.SchoolType + +data class SchoolRequest( + val name: String, + val schoolType: SchoolType, + val region: String, + val address: String, +) diff --git a/core/src/main/kotlin/com/wespot/auth/dto/SignInRequest.kt b/core/src/main/kotlin/com/wespot/auth/dto/SignInRequest.kt new file mode 100644 index 00000000..cd9eb5e5 --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/dto/SignInRequest.kt @@ -0,0 +1,12 @@ +package com.wespot.auth.dto + +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken + +data class SignInRequest( + val email: String, + val password: String +){ + fun toAuthentication(): UsernamePasswordAuthenticationToken { + return UsernamePasswordAuthenticationToken(email, password) + } +} diff --git a/core/src/main/kotlin/com/wespot/auth/dto/SignInResponse.kt b/core/src/main/kotlin/com/wespot/auth/dto/SignInResponse.kt new file mode 100644 index 00000000..4bf23ce3 --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/dto/SignInResponse.kt @@ -0,0 +1,6 @@ +package com.wespot.auth.dto + +data class SignInResponse ( + val accessToken: String, + val refreshToken: String +) \ No newline at end of file diff --git a/core/src/main/kotlin/com/wespot/auth/dto/SignUpRequest.kt b/core/src/main/kotlin/com/wespot/auth/dto/SignUpRequest.kt new file mode 100644 index 00000000..c727afd2 --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/dto/SignUpRequest.kt @@ -0,0 +1,10 @@ +package com.wespot.auth.dto + +data class SignUpRequest( + val singUpToken: String, + val profile: ProfileRequest, + val userConsent: UserConsentRequest, + val school: SchoolRequest, + val grade: Int, + val groupNumber: Int, +) \ No newline at end of file diff --git a/core/src/main/kotlin/com/wespot/auth/dto/SignUpResponse.kt b/core/src/main/kotlin/com/wespot/auth/dto/SignUpResponse.kt new file mode 100644 index 00000000..8b7690ab --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/dto/SignUpResponse.kt @@ -0,0 +1,5 @@ +package com.wespot.auth.dto + +data class SignUpResponse( + val signUpToken: String +) \ No newline at end of file diff --git a/core/src/main/kotlin/com/wespot/auth/dto/SocialResponse.kt b/core/src/main/kotlin/com/wespot/auth/dto/SocialResponse.kt new file mode 100644 index 00000000..4ae396f5 --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/dto/SocialResponse.kt @@ -0,0 +1,7 @@ +package com.wespot.auth.dto + +data class SocialResponse( + val socialId: String, + val socialEmail: String, + val socialRefreshToken: String +) diff --git a/core/src/main/kotlin/com/wespot/auth/dto/TokenResponse.kt b/core/src/main/kotlin/com/wespot/auth/dto/TokenResponse.kt new file mode 100644 index 00000000..11023841 --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/dto/TokenResponse.kt @@ -0,0 +1,6 @@ +package com.wespot.auth.dto + +data class TokenResponse( + val accessToken: String, + val refreshToken: String +) \ No newline at end of file diff --git a/core/src/main/kotlin/com/wespot/auth/dto/UserConsentRequest.kt b/core/src/main/kotlin/com/wespot/auth/dto/UserConsentRequest.kt new file mode 100644 index 00000000..242b63d2 --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/dto/UserConsentRequest.kt @@ -0,0 +1,8 @@ +package com.wespot.auth.dto + +import com.wespot.user.ConsentType + +data class UserConsentRequest( + val consentType: ConsentType, + val consentValue: Boolean +) diff --git a/core/src/main/kotlin/com/wespot/auth/service/PrincipalDetailService.kt b/core/src/main/kotlin/com/wespot/auth/service/PrincipalDetailService.kt index f209e90a..368c5c6a 100644 --- a/core/src/main/kotlin/com/wespot/auth/service/PrincipalDetailService.kt +++ b/core/src/main/kotlin/com/wespot/auth/service/PrincipalDetailService.kt @@ -13,7 +13,9 @@ class PrincipalDetailService( private val userPort: UserPort ) : UserDetailsService { override fun loadUserByUsername(userEmail: String): UserDetails { - val principal: User = userPort.getByEmail(userEmail) ?: throw NoSuchElementException("유저를 찾을 수 없습니다.") + + val principal: User = userPort.findByEmail(userEmail) ?: throw NoSuchElementException("유저를 찾을 수 없습니다.") + return PrincipalDetails(principal) } } \ No newline at end of file diff --git a/core/src/main/kotlin/com/wespot/auth/service/SocialAuthService.kt b/core/src/main/kotlin/com/wespot/auth/service/SocialAuthService.kt index 8e2cc6ad..b00975d3 100644 --- a/core/src/main/kotlin/com/wespot/auth/service/SocialAuthService.kt +++ b/core/src/main/kotlin/com/wespot/auth/service/SocialAuthService.kt @@ -1,11 +1,15 @@ package com.wespot.auth.service import com.wespot.auth.dto.AuthLoginRequest -import com.wespot.auth.dto.OAuthIdAndRefreshToken +import com.wespot.auth.dto.SocialResponse import com.wespot.user.SocialType interface SocialAuthService { - fun fetchAuthToken(authLoginRequest: AuthLoginRequest): OAuthIdAndRefreshToken + + fun fetchAuthToken(authLoginRequest: AuthLoginRequest): SocialResponse + fun isSupport(socialType: SocialType): Boolean + fun revoke(socialId: String, socialRefreshToken: String?): Boolean + } diff --git a/core/src/main/kotlin/com/wespot/auth/service/SocialAuthServiceFactory.kt b/core/src/main/kotlin/com/wespot/auth/service/SocialAuthServiceFactory.kt index 40547c07..705c66f5 100644 --- a/core/src/main/kotlin/com/wespot/auth/service/SocialAuthServiceFactory.kt +++ b/core/src/main/kotlin/com/wespot/auth/service/SocialAuthServiceFactory.kt @@ -1,7 +1,6 @@ package com.wespot.auth.service import com.wespot.user.SocialType -import org.springframework.stereotype.Component import org.springframework.stereotype.Service @Service diff --git a/core/src/main/kotlin/com/wespot/auth/service/apple/AppleService.kt b/core/src/main/kotlin/com/wespot/auth/service/apple/AppleService.kt index dabff5d1..d01cca05 100644 --- a/core/src/main/kotlin/com/wespot/auth/service/apple/AppleService.kt +++ b/core/src/main/kotlin/com/wespot/auth/service/apple/AppleService.kt @@ -1,7 +1,7 @@ package com.wespot.auth.service.apple import com.wespot.auth.dto.AuthLoginRequest -import com.wespot.auth.dto.OAuthIdAndRefreshToken +import com.wespot.auth.dto.SocialResponse import com.wespot.auth.dto.apple.AppleRevokeRequest import com.wespot.auth.dto.apple.AppleTokenResult import com.wespot.auth.service.SocialAuthService @@ -27,15 +27,16 @@ class AppleService( private const val TOKEN_TYPE_HINT = "refresh_token" } - override fun fetchAuthToken(authLoginRequest: AuthLoginRequest): OAuthIdAndRefreshToken { + override fun fetchAuthToken(authLoginRequest: AuthLoginRequest): SocialResponse { val appleId = getAppleId(authLoginRequest.identityToken ?: throw IllegalArgumentException("Apple ID token이 없습니다.")) val appleTokenResult = generateAuthToken(authLoginRequest.authorizationCode ?: throw IllegalArgumentException("Authorization code가 없습니다.")) - return OAuthIdAndRefreshToken( - oAuthId = appleId, - refreshToken = appleTokenResult.refreshToken ?: NOT_SUPPORTED + return SocialResponse( + socialId = appleId, + socialRefreshToken = appleTokenResult.refreshToken ?: NOT_SUPPORTED, + socialEmail = NOT_SUPPORTED ) } diff --git a/core/src/main/kotlin/com/wespot/auth/service/jwt/JwtTokenProvider.kt b/core/src/main/kotlin/com/wespot/auth/service/jwt/JwtTokenProvider.kt index 1877b776..a7c57253 100644 --- a/core/src/main/kotlin/com/wespot/auth/service/jwt/JwtTokenProvider.kt +++ b/core/src/main/kotlin/com/wespot/auth/service/jwt/JwtTokenProvider.kt @@ -53,6 +53,6 @@ class JwtTokenProvider( ) } - + } diff --git a/core/src/main/kotlin/com/wespot/auth/service/kakao/KakaoService.kt b/core/src/main/kotlin/com/wespot/auth/service/kakao/KakaoService.kt index ee84d89b..15fdc638 100644 --- a/core/src/main/kotlin/com/wespot/auth/service/kakao/KakaoService.kt +++ b/core/src/main/kotlin/com/wespot/auth/service/kakao/KakaoService.kt @@ -1,7 +1,7 @@ package com.wespot.auth.service.kakao import com.wespot.auth.dto.AuthLoginRequest -import com.wespot.auth.dto.OAuthIdAndRefreshToken +import com.wespot.auth.dto.SocialResponse import com.wespot.auth.service.SocialAuthService import com.wespot.user.SocialType import org.springframework.beans.factory.annotation.Value @@ -18,12 +18,14 @@ class KakaoService( private const val KAKAO_PREFIX = "KakaoAK " } - override fun fetchAuthToken(authLoginRequest: AuthLoginRequest): OAuthIdAndRefreshToken { + override fun fetchAuthToken(authLoginRequest: AuthLoginRequest): SocialResponse { val kakaoId = getKakaoId(authLoginRequest.identityToken ?: throw IllegalArgumentException("Kakao ID가 입력되지 않았습니다.")) - return OAuthIdAndRefreshToken( - oAuthId = kakaoId, refreshToken = NOT_SUPPORTED + return SocialResponse( + socialId = kakaoId, + socialRefreshToken = NOT_SUPPORTED, + socialEmail = NOT_SUPPORTED ) } diff --git a/infrastructure/mysql/build.gradle.kts b/infrastructure/mysql/build.gradle.kts index c3004bbf..91b6a7f9 100644 --- a/infrastructure/mysql/build.gradle.kts +++ b/infrastructure/mysql/build.gradle.kts @@ -1,10 +1,16 @@ import org.springframework.boot.gradle.tasks.bundling.BootJar dependencies { + + implementation("com.mysql:mysql-connector-j") runtimeOnly("com.mysql:mysql-connector-j") implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.data:spring-data-commons") + // https://mvnrepository.com/artifact/org.mapstruct/mapstruct + implementation("org.mapstruct:mapstruct:1.5.3.Final") + annotationProcessor("org.mapstruct:mapstruct-processor:1.5.3.Final") + implementation(project(":common")) implementation(project(":domain")) implementation(project(":core")) From 9c8c9ac79d1ccba68f0abb41bf439c417f19934a Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 18:40:31 +0900 Subject: [PATCH 16/34] =?UTF-8?q?refactor:=20School=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 유저와 연결 끊도록 설정 --- .../main/kotlin/com/wespot/school/port/out/SchoolPort.kt | 6 +++++- domain/src/main/kotlin/com/wespot/school/School.kt | 6 +----- domain/src/main/kotlin/com/wespot/user/User.kt | 7 ++++++- .../src/main/kotlin/com/wespot/school/SchoolJpaEntity.kt | 5 ----- .../src/main/kotlin/com/wespot/school/SchoolMapper.kt | 3 --- .../kotlin/com/wespot/school/SchoolPersistentAdapter.kt | 7 +++++++ .../com/wespot/user/adapter/UserPersistenceAdapter.kt | 3 +++ .../main/kotlin/com/wespot/user/entity/ProfileJpaEntity.kt | 2 +- .../main/kotlin/com/wespot/user/entity/UserJpaEntity.kt | 6 ++++-- .../src/main/kotlin/com/wespot/user/mapper/UserMapper.kt | 2 ++ 10 files changed, 29 insertions(+), 18 deletions(-) diff --git a/core/src/main/kotlin/com/wespot/school/port/out/SchoolPort.kt b/core/src/main/kotlin/com/wespot/school/port/out/SchoolPort.kt index 9a7ea101..f02f064b 100644 --- a/core/src/main/kotlin/com/wespot/school/port/out/SchoolPort.kt +++ b/core/src/main/kotlin/com/wespot/school/port/out/SchoolPort.kt @@ -3,5 +3,9 @@ package com.wespot.school.port.out import com.wespot.school.School interface SchoolPort { + fun save(school: School): School -} \ No newline at end of file + + fun findById(id: Long): School? + +} diff --git a/domain/src/main/kotlin/com/wespot/school/School.kt b/domain/src/main/kotlin/com/wespot/school/School.kt index 32c79cfd..4a0309ce 100644 --- a/domain/src/main/kotlin/com/wespot/school/School.kt +++ b/domain/src/main/kotlin/com/wespot/school/School.kt @@ -1,10 +1,8 @@ package com.wespot.school -import com.wespot.user.User data class School( val id: Long, - val user: User, val name: String, val schoolType: SchoolType, val region: String, @@ -13,15 +11,13 @@ data class School( companion object { fun create( - user: User, name: String, schoolType: SchoolType, region: String, address: String ) = School( - id = 0, - user = user, + id = 0L, name = name, schoolType = schoolType, region = region, diff --git a/domain/src/main/kotlin/com/wespot/user/User.kt b/domain/src/main/kotlin/com/wespot/user/User.kt index 0dffab00..0f986ae1 100644 --- a/domain/src/main/kotlin/com/wespot/user/User.kt +++ b/domain/src/main/kotlin/com/wespot/user/User.kt @@ -26,6 +26,7 @@ data class User( email = email, password = password, role = Role.GUEST, + schoolId = schoolId, grade = grade, groupNumber = groupNumber, setting = setting, @@ -39,19 +40,23 @@ data class User( fun create( email: String, password: String, + schoolId: Long, grade: Int, groupNumber: Int, social: Social ) = User( - id = 0, + id = 0L, email = email, password = password, role = Role.USER, + schoolId = schoolId, grade = grade, groupNumber = groupNumber, setting = Setting(), social = social, + createdAt = LocalDateTime.now(), + updatedAt = LocalDateTime.now(), ) } } diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolJpaEntity.kt index 6884b4a4..1e25a06c 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolJpaEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolJpaEntity.kt @@ -1,6 +1,5 @@ package com.wespot.school -import com.wespot.user.entity.UserJpaEntity import jakarta.persistence.* import org.jetbrains.annotations.NotNull @@ -12,10 +11,6 @@ class SchoolJpaEntity( @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long, - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "users_id", foreignKey = ForeignKey(name = "fk_school_users_id")) - val user: UserJpaEntity, - @field:NotNull val name: String, diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolMapper.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolMapper.kt index 5ec4f6cb..20ab0c38 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolMapper.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolMapper.kt @@ -1,13 +1,11 @@ package com.wespot.school -import com.wespot.user.mapper.UserMapper object SchoolMapper { fun mapToDomainEntity(school: SchoolJpaEntity): School = School( id = school.id, - user = UserMapper.mapToDomainEntity(school.user), name = school.name, schoolType = school.schoolType, region = school.region, @@ -17,7 +15,6 @@ object SchoolMapper { fun mapToJpaEntity(school: School): SchoolJpaEntity = SchoolJpaEntity( id = school.id, - user = UserMapper.mapToJpaEntity(school.user), name = school.name, schoolType = school.schoolType, region = school.region, diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolPersistentAdapter.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolPersistentAdapter.kt index 1dd3e654..a11e3481 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolPersistentAdapter.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolPersistentAdapter.kt @@ -1,6 +1,7 @@ package com.wespot.school import com.wespot.school.port.out.SchoolPort +import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Repository @Repository @@ -13,4 +14,10 @@ class SchoolPersistentAdapter( .let { SchoolMapper.mapToDomainEntity(it) } } + override fun findById(id: Long): School? { + return schoolJpaRepository.findByIdOrNull(id) + ?.let { SchoolMapper.mapToDomainEntity(it) } + ?: throw NoSuchElementException("학교 정보를 찾을 수 없습니다.") + } + } diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt index f448afa5..8ba3beb6 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt @@ -4,8 +4,11 @@ import com.wespot.user.User import com.wespot.user.repository.UserJpaRepository import com.wespot.user.mapper.UserMapper import com.wespot.user.port.out.UserPort +import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.stereotype.Repository +import org.springframework.transaction.annotation.Transactional +@Transactional(readOnly = true) @Repository class UserPersistenceAdapter( private val userJpaRepository: UserJpaRepository, diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/ProfileJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/ProfileJpaEntity.kt index fe330969..576cf710 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/ProfileJpaEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/ProfileJpaEntity.kt @@ -4,7 +4,7 @@ import jakarta.persistence.* import org.jetbrains.annotations.NotNull @Entity -@Table(name = "fcm") +@Table(name = "profile") class ProfileJpaEntity( @Id diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserJpaEntity.kt index cd31fabc..d40bb1c7 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserJpaEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserJpaEntity.kt @@ -1,6 +1,8 @@ -package com.wespot.user +package com.wespot.user.entity import com.wespot.common.BaseEntity +import com.wespot.school.SchoolJpaEntity +import com.wespot.user.Role import jakarta.persistence.* import org.jetbrains.annotations.NotNull import java.time.LocalDateTime @@ -18,7 +20,7 @@ class UserJpaEntity( @field: NotNull val password: String, - + @field: NotNull val schoolId: Long, diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserMapper.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserMapper.kt index f82efa97..db684450 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserMapper.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserMapper.kt @@ -16,6 +16,7 @@ object UserMapper { setting = Setting( isEnableNotification = user.setting.isEnableNotification, ), + schoolId = user.schoolId, grade = user.grade, groupNumber = user.groupNumber, role = user.role, @@ -39,6 +40,7 @@ object UserMapper { setting = SettingJpaEntity( isEnableNotification = user.setting.isEnableNotification, ), + schoolId = user.schoolId, grade = user.grade, groupNumber = user.groupNumber, role = user.role, From 35659a65caf4932b2e694e3d24cd4df035299174 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 18:48:52 +0900 Subject: [PATCH 17/34] =?UTF-8?q?refactor:=20RefreshToken=20create,=20upda?= =?UTF-8?q?te=20=EC=84=A4=EC=A0=95=20=EB=B0=8F=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/service/RefreshTokenService.kt | 40 ++++++++++++++++++ .../kotlin/com/wespot/auth/RefreshToken.kt | 41 ++++++++++++++++++- .../com/wespot/auth/RefreshTokenJpaEntity.kt | 24 +++++------ .../wespot/auth/RefreshTokenJpaRepository.kt | 8 +++- .../com/wespot/auth/RefreshTokenMapper.kt | 24 +++++++---- .../auth/RefreshTokenPersistenceAdapter.kt | 30 +++++++------- .../kotlin/com/wespot/common/BaseEntity.kt | 7 ++-- 7 files changed, 131 insertions(+), 43 deletions(-) create mode 100644 core/src/main/kotlin/com/wespot/auth/service/RefreshTokenService.kt diff --git a/core/src/main/kotlin/com/wespot/auth/service/RefreshTokenService.kt b/core/src/main/kotlin/com/wespot/auth/service/RefreshTokenService.kt new file mode 100644 index 00000000..9e35e042 --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/service/RefreshTokenService.kt @@ -0,0 +1,40 @@ +package com.wespot.auth.service + +import com.wespot.auth.JwtTokenInfo.REFRESH_TOKEN_EXPIRY_DAYS +import com.wespot.auth.RefreshToken +import com.wespot.auth.port.out.RefreshTokenPort +import com.wespot.user.User +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.time.LocalDateTime + +@Service +class RefreshTokenService( + private val refreshTokenPort: RefreshTokenPort +) { + @Transactional + fun saveOrUpdateRefreshToken(token: String, user: User) { + val findRefreshToken = refreshTokenPort.findByUserId(user.id) + val refreshToken: RefreshToken + + if (findRefreshToken != null) { + refreshToken = RefreshToken.update( + id = findRefreshToken.id, + refreshToken = token, + user = findRefreshToken.user, + createdAt = findRefreshToken.createdAt ?: LocalDateTime.now(), + updatedAt = LocalDateTime.now(), + expiredAt = LocalDateTime.now().plusDays(REFRESH_TOKEN_EXPIRY_DAYS) + ) + } else { + refreshToken = RefreshToken.create( + refreshToken = token, + user = user, + createdAt = LocalDateTime.now(), + updatedAt = LocalDateTime.now(), + expiredAt = LocalDateTime.now().plusDays(REFRESH_TOKEN_EXPIRY_DAYS) + ) + } + refreshTokenPort.saveOrUpdate(refreshToken) + } +} diff --git a/domain/src/main/kotlin/com/wespot/auth/RefreshToken.kt b/domain/src/main/kotlin/com/wespot/auth/RefreshToken.kt index 36443224..d971fb98 100644 --- a/domain/src/main/kotlin/com/wespot/auth/RefreshToken.kt +++ b/domain/src/main/kotlin/com/wespot/auth/RefreshToken.kt @@ -7,5 +7,42 @@ data class RefreshToken( val id : Long, val refreshToken: String, val user: User, - val expiredAt: LocalDateTime? -) \ No newline at end of file + val createdAt: LocalDateTime?, + val updatedAt: LocalDateTime?, + val expiredAt: LocalDateTime +){ + companion object { + fun create( + refreshToken: String, + user: User, + createdAt: LocalDateTime, + updatedAt: LocalDateTime, + expiredAt: LocalDateTime + ) = + RefreshToken( + id = 0L, + refreshToken = refreshToken, + user = user, + createdAt = createdAt, + updatedAt = updatedAt, + expiredAt = expiredAt + ) + + fun update( + id: Long, + refreshToken: String, + user: User, + createdAt: LocalDateTime, + updatedAt: LocalDateTime, + expiredAt: LocalDateTime + ) = + RefreshToken( + id = id, + refreshToken = refreshToken, + user = user, + createdAt = createdAt, + updatedAt = updatedAt, + expiredAt = expiredAt + ) + } +} \ No newline at end of file diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenJpaEntity.kt index cfc7e588..1554130d 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenJpaEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenJpaEntity.kt @@ -1,10 +1,8 @@ package com.wespot.auth +import com.wespot.common.BaseEntity import com.wespot.user.entity.UserJpaEntity import jakarta.persistence.* -import org.springframework.data.annotation.CreatedDate -import org.springframework.data.annotation.LastModifiedDate -import java.time.Instant import java.time.LocalDateTime @@ -15,23 +13,23 @@ class RefreshTokenJpaEntity( @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long = 0, - val refreshToken: String, + var refreshToken: String, @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "user_id", foreignKey = ForeignKey(name = "fk_refresh_token_user_id")) + @JoinColumn(name = "users_id", foreignKey = ForeignKey(name = "fk_refresh_token_user_id")) val user: UserJpaEntity, - @CreatedDate - @LastModifiedDate - val createdAt: Instant? = null, + @Embedded + val baseEntity: BaseEntity, - @LastModifiedDate - val updatedAt: Instant? = null, - - @Column(name = "expired_at", columnDefinition = "Datetime", scale = 6) - val expiredAt: LocalDateTime? = null, + @field:Column(name = "expired_at", columnDefinition = "Datetime", scale = 6) + var expiredAt: LocalDateTime, ) { + fun update(refreshToken: String) { + this.refreshToken = refreshToken + this.expiredAt= LocalDateTime.now().plusDays(30) + } } diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenJpaRepository.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenJpaRepository.kt index c0a30cdf..8dedb2b8 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenJpaRepository.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenJpaRepository.kt @@ -3,7 +3,13 @@ package com.wespot.auth import org.springframework.data.jpa.repository.JpaRepository interface RefreshTokenJpaRepository : JpaRepository { + + fun save(refreshToken: RefreshTokenJpaEntity): RefreshTokenJpaEntity + fun deleteByUserId(userId: Long) + fun findByUserId(userId: Long): RefreshTokenJpaEntity? + fun findByRefreshToken(refreshToken: String): RefreshTokenJpaEntity? -} \ No newline at end of file + +} diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenMapper.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenMapper.kt index 7382d45e..dc51ec46 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenMapper.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenMapper.kt @@ -1,24 +1,32 @@ package com.wespot.auth +import com.wespot.common.BaseEntity import com.wespot.user.mapper.UserMapper object RefreshTokenMapper { + fun mapToDomainEntity(refreshTokenJpaEntity: RefreshTokenJpaEntity): RefreshToken { + return RefreshToken( + id = refreshTokenJpaEntity.id, + refreshToken = refreshTokenJpaEntity.refreshToken, + user = UserMapper.mapToDomainEntity(refreshTokenJpaEntity.user), + createdAt = refreshTokenJpaEntity.baseEntity.createdAt, + updatedAt = refreshTokenJpaEntity.baseEntity.updatedAt, + expiredAt = refreshTokenJpaEntity.expiredAt + ) + } + fun mapToJpaEntity(refreshToken: RefreshToken): RefreshTokenJpaEntity { return RefreshTokenJpaEntity( id = refreshToken.id, refreshToken = refreshToken.refreshToken, user = UserMapper.mapToJpaEntity(refreshToken.user), + baseEntity = BaseEntity( + createdAt = refreshToken.createdAt, + updatedAt = refreshToken.updatedAt, + ), expiredAt = refreshToken.expiredAt ) } - fun mapToDomainEntity(refreshTokenJpaEntity: RefreshTokenJpaEntity): RefreshToken { - return RefreshToken( - id = refreshTokenJpaEntity.id, - refreshToken = refreshTokenJpaEntity.refreshToken, - user = UserMapper.mapToDomainEntity(refreshTokenJpaEntity.user), - expiredAt = refreshTokenJpaEntity.expiredAt - ) - } } \ No newline at end of file diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenPersistenceAdapter.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenPersistenceAdapter.kt index c187460e..6aef30b7 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenPersistenceAdapter.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenPersistenceAdapter.kt @@ -1,45 +1,45 @@ package com.wespot.auth import com.wespot.auth.port.out.RefreshTokenPort -import com.wespot.user.User -import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Repository import org.springframework.transaction.annotation.Transactional -@Transactional(readOnly = true) @Repository class RefreshTokenPersistenceAdapter( - private val refreshTokenRepository: RefreshTokenJpaRepository + private val refreshTokenJpaRepository: RefreshTokenJpaRepository ) : RefreshTokenPort { - override fun create(refreshToken: RefreshToken): RefreshToken { + + + @Transactional + override fun save(refreshToken: RefreshToken): RefreshToken { return RefreshTokenMapper.mapToJpaEntity(refreshToken) - .let { refreshTokenRepository.save(it) } + .let { refreshTokenJpaRepository.save(it) } .let { RefreshTokenMapper.mapToDomainEntity(it) } } - override fun findByUser(user: User): RefreshToken? { - return refreshTokenRepository.findByIdOrNull(user.id) + override fun findByUserId(userId: Long): RefreshToken? { + return refreshTokenJpaRepository.findByUserId(userId) ?.let { RefreshTokenMapper.mapToDomainEntity(it) } - ?: throw NoSuchElementException("해당하는 유저의 RefreshToken이 없습니다.") } + @Transactional override fun saveOrUpdate(refreshToken: RefreshToken): RefreshToken { - val refreshTokenJpaEntity = refreshTokenRepository.findByUserId(refreshToken.user.id) + val refreshTokenJpaEntity = refreshTokenJpaRepository.findByUserId(refreshToken.user.id) return if (refreshTokenJpaEntity != null) { - RefreshTokenMapper.mapToJpaEntity(refreshToken) - .let { refreshTokenRepository.save(it) } + refreshTokenJpaEntity.update(refreshToken.refreshToken) + refreshTokenJpaRepository.save(refreshTokenJpaEntity) .let { RefreshTokenMapper.mapToDomainEntity(it) } } else { - create(refreshToken) + save(refreshToken) } } override fun deleteByUserId(userId: Long) { - refreshTokenRepository.deleteByUserId(userId) + refreshTokenJpaRepository.deleteByUserId(userId) } override fun findByRefreshToken(refreshToken: String): RefreshToken? { - val findByRefreshToken = refreshTokenRepository.findByRefreshToken(refreshToken) + val findByRefreshToken = refreshTokenJpaRepository.findByRefreshToken(refreshToken) if (findByRefreshToken != null) { return RefreshTokenMapper.mapToDomainEntity(findByRefreshToken) } diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt index 24533700..bc4e2c30 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt @@ -3,7 +3,6 @@ package com.wespot.common import jakarta.persistence.Column import jakarta.persistence.Embeddable import jakarta.persistence.EntityListeners -import org.jetbrains.annotations.NotNull import org.springframework.data.annotation.CreatedDate import org.springframework.data.annotation.LastModifiedDate import org.springframework.data.jpa.domain.support.AuditingEntityListener @@ -14,12 +13,12 @@ import java.time.LocalDateTime class BaseEntity( @CreatedDate - @field: NotNull - @Column(updatable = false, nullable = false) + @field:NotNull + @field:Column(nullable = false, updatable = false) val createdAt: LocalDateTime = LocalDateTime.now(), @LastModifiedDate - @Column(nullable = false) + @field:Column(nullable = false) val updatedAt: LocalDateTime? = null ) From e8056ed18442756efc1ed5b08949fa2697afbdd3 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 18:52:05 +0900 Subject: [PATCH 18/34] =?UTF-8?q?feat:=20Redis=20=EB=AA=A8=EB=93=88=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80,=20=EC=84=A4=EC=A0=95=20=EB=B0=8F=20AuthDate?= =?UTF-8?q?=20=EC=A0=80=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 3 +++ .../kotlin/com/wespot/auth/dto/AuthData.kt | 13 +++++---- infrastructure/redis/build.gradle.kts | 19 +++++++++++++ .../kotlin/com/wespot/RedisAuthDataAdapter.kt | 22 +++++++++++++++ .../kotlin/com/wespot/config/RedisConfig.kt | 27 +++++++++++++++++++ settings.gradle.kts | 1 + 6 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 infrastructure/redis/build.gradle.kts create mode 100644 infrastructure/redis/src/main/kotlin/com/wespot/RedisAuthDataAdapter.kt create mode 100644 infrastructure/redis/src/main/kotlin/com/wespot/config/RedisConfig.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8f523545..358dc5ac 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -9,6 +9,9 @@ dependencies { implementation(project(":domain")) implementation(project(":core")) implementation(project(":infrastructure:mysql")) + implementation(project(":infrastructure:redis")) testImplementation("io.rest-assured:rest-assured") + + } diff --git a/core/src/main/kotlin/com/wespot/auth/dto/AuthData.kt b/core/src/main/kotlin/com/wespot/auth/dto/AuthData.kt index 39dd1767..ef749c91 100644 --- a/core/src/main/kotlin/com/wespot/auth/dto/AuthData.kt +++ b/core/src/main/kotlin/com/wespot/auth/dto/AuthData.kt @@ -1,7 +1,10 @@ package com.wespot.auth.dto -data class AuthData( - val email: String, - val socialRefreshToken: String, - val socialEmail: String, -) \ No newline at end of file +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty + +data class AuthData @JsonCreator constructor( + @JsonProperty("email") val email: String, + @JsonProperty("socialRefreshToken") val socialRefreshToken: String, + @JsonProperty("socialEmail") val socialEmail: String +) diff --git a/infrastructure/redis/build.gradle.kts b/infrastructure/redis/build.gradle.kts new file mode 100644 index 00000000..3feeb939 --- /dev/null +++ b/infrastructure/redis/build.gradle.kts @@ -0,0 +1,19 @@ +import org.springframework.boot.gradle.tasks.bundling.BootJar + +dependencies { + + // redis + implementation("org.springframework.boot:spring-boot-starter-data-redis") + + implementation(project(":common")) + implementation(project(":domain")) + implementation(project(":core")) +} + +tasks.named("jar") { + enabled = true +} + +tasks.named("bootJar") { + enabled = false +} \ No newline at end of file diff --git a/infrastructure/redis/src/main/kotlin/com/wespot/RedisAuthDataAdapter.kt b/infrastructure/redis/src/main/kotlin/com/wespot/RedisAuthDataAdapter.kt new file mode 100644 index 00000000..d5482b7c --- /dev/null +++ b/infrastructure/redis/src/main/kotlin/com/wespot/RedisAuthDataAdapter.kt @@ -0,0 +1,22 @@ +package com.wespot + + +import com.wespot.auth.dto.AuthData +import com.wespot.auth.port.out.AuthDataPort +import org.springframework.data.redis.core.RedisTemplate +import org.springframework.stereotype.Component +import java.util.concurrent.TimeUnit + +@Component +class RedisAuthDataAdapter( + private val redisTemplate: RedisTemplate +) : AuthDataPort { + + override fun saveAuthData(token: String, authData: AuthData) { + redisTemplate.opsForValue().set(token, authData, 25, TimeUnit.MINUTES) + } + + override fun getAuthData(token: String): AuthData? { + return redisTemplate.opsForValue().get(token) as? AuthData + } +} \ No newline at end of file diff --git a/infrastructure/redis/src/main/kotlin/com/wespot/config/RedisConfig.kt b/infrastructure/redis/src/main/kotlin/com/wespot/config/RedisConfig.kt new file mode 100644 index 00000000..634b01b2 --- /dev/null +++ b/infrastructure/redis/src/main/kotlin/com/wespot/config/RedisConfig.kt @@ -0,0 +1,27 @@ +package com.wespot.config + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory +import org.springframework.data.redis.core.RedisTemplate +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer +import org.springframework.data.redis.serializer.StringRedisSerializer + +@Configuration +class RedisConfig { + + @Bean + fun redisConnectionFactory(): LettuceConnectionFactory { + return LettuceConnectionFactory() + } + + @Bean + fun redisTemplate(): RedisTemplate { + val template = RedisTemplate() + template.connectionFactory = redisConnectionFactory() + template.keySerializer = StringRedisSerializer() + template.valueSerializer = GenericJackson2JsonRedisSerializer() + return template + } + +} diff --git a/settings.gradle.kts b/settings.gradle.kts index eece8f5f..0addc935 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,6 +3,7 @@ include( "domain", "core", "infrastructure:mysql", + "infrastructure:redis", "app", "common", ) From e17f0415bdf24430c9c0ea78bf109827fce9dd2e Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 18:53:32 +0900 Subject: [PATCH 19/34] =?UTF-8?q?refactor:=20DTO=20=ED=8F=B4=EB=8D=94=20?= =?UTF-8?q?=EA=B2=BD=EB=A1=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wespot/auth/dto/{ => request}/AuthLoginRequest.kt | 2 +- .../wespot/auth/dto/{ => request}/ProfileRequest.kt | 2 +- .../wespot/auth/dto/request/RefreshTokenRequest.kt | 5 +++++ .../wespot/auth/dto/{ => request}/SchoolRequest.kt | 2 +- .../wespot/auth/dto/{ => request}/SignInRequest.kt | 2 +- .../wespot/auth/dto/{ => request}/SignUpRequest.kt | 6 +++--- .../auth/dto/{ => request}/UserConsentRequest.kt | 2 +- .../wespot/auth/dto/{ => response}/SignInResponse.kt | 2 +- .../wespot/auth/dto/{ => response}/SignUpResponse.kt | 2 +- .../wespot/auth/dto/{ => response}/SocialResponse.kt | 2 +- .../wespot/auth/dto/{ => response}/TokenResponse.kt | 2 +- .../kotlin/com/wespot/auth/port/out/AuthDataPort.kt | 11 +++++++++++ .../com/wespot/auth/port/out/RefreshTokenPort.kt | 4 ++-- .../com/wespot/auth/service/SocialAuthService.kt | 4 ++-- .../com/wespot/auth/service/apple/AppleService.kt | 4 ++-- .../com/wespot/auth/service/jwt/JwtTokenProvider.kt | 2 +- .../com/wespot/auth/service/kakao/KakaoService.kt | 4 ++-- 17 files changed, 37 insertions(+), 21 deletions(-) rename core/src/main/kotlin/com/wespot/auth/dto/{ => request}/AuthLoginRequest.kt (84%) rename core/src/main/kotlin/com/wespot/auth/dto/{ => request}/ProfileRequest.kt (70%) create mode 100644 core/src/main/kotlin/com/wespot/auth/dto/request/RefreshTokenRequest.kt rename core/src/main/kotlin/com/wespot/auth/dto/{ => request}/SchoolRequest.kt (82%) rename core/src/main/kotlin/com/wespot/auth/dto/{ => request}/SignInRequest.kt (89%) rename core/src/main/kotlin/com/wespot/auth/dto/{ => request}/SignUpRequest.kt (62%) rename core/src/main/kotlin/com/wespot/auth/dto/{ => request}/UserConsentRequest.kt (78%) rename core/src/main/kotlin/com/wespot/auth/dto/{ => response}/SignInResponse.kt (70%) rename core/src/main/kotlin/com/wespot/auth/dto/{ => response}/SignUpResponse.kt (60%) rename core/src/main/kotlin/com/wespot/auth/dto/{ => response}/SocialResponse.kt (76%) rename core/src/main/kotlin/com/wespot/auth/dto/{ => response}/TokenResponse.kt (69%) create mode 100644 core/src/main/kotlin/com/wespot/auth/port/out/AuthDataPort.kt diff --git a/core/src/main/kotlin/com/wespot/auth/dto/AuthLoginRequest.kt b/core/src/main/kotlin/com/wespot/auth/dto/request/AuthLoginRequest.kt similarity index 84% rename from core/src/main/kotlin/com/wespot/auth/dto/AuthLoginRequest.kt rename to core/src/main/kotlin/com/wespot/auth/dto/request/AuthLoginRequest.kt index c011610c..3237f669 100644 --- a/core/src/main/kotlin/com/wespot/auth/dto/AuthLoginRequest.kt +++ b/core/src/main/kotlin/com/wespot/auth/dto/request/AuthLoginRequest.kt @@ -1,4 +1,4 @@ -package com.wespot.auth.dto +package com.wespot.auth.dto.request import com.wespot.user.SocialType diff --git a/core/src/main/kotlin/com/wespot/auth/dto/ProfileRequest.kt b/core/src/main/kotlin/com/wespot/auth/dto/request/ProfileRequest.kt similarity index 70% rename from core/src/main/kotlin/com/wespot/auth/dto/ProfileRequest.kt rename to core/src/main/kotlin/com/wespot/auth/dto/request/ProfileRequest.kt index 1b8eb34f..f0f4e287 100644 --- a/core/src/main/kotlin/com/wespot/auth/dto/ProfileRequest.kt +++ b/core/src/main/kotlin/com/wespot/auth/dto/request/ProfileRequest.kt @@ -1,4 +1,4 @@ -package com.wespot.auth.dto +package com.wespot.auth.dto.request data class ProfileRequest( val backgroundColor: String, diff --git a/core/src/main/kotlin/com/wespot/auth/dto/request/RefreshTokenRequest.kt b/core/src/main/kotlin/com/wespot/auth/dto/request/RefreshTokenRequest.kt new file mode 100644 index 00000000..82a8e79c --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/dto/request/RefreshTokenRequest.kt @@ -0,0 +1,5 @@ +package com.wespot.auth.dto.request + +data class RefreshTokenRequest( + val refreshToken: String +) diff --git a/core/src/main/kotlin/com/wespot/auth/dto/SchoolRequest.kt b/core/src/main/kotlin/com/wespot/auth/dto/request/SchoolRequest.kt similarity index 82% rename from core/src/main/kotlin/com/wespot/auth/dto/SchoolRequest.kt rename to core/src/main/kotlin/com/wespot/auth/dto/request/SchoolRequest.kt index ad2f8ced..df1ffc93 100644 --- a/core/src/main/kotlin/com/wespot/auth/dto/SchoolRequest.kt +++ b/core/src/main/kotlin/com/wespot/auth/dto/request/SchoolRequest.kt @@ -1,4 +1,4 @@ -package com.wespot.auth.dto +package com.wespot.auth.dto.request import com.wespot.school.SchoolType diff --git a/core/src/main/kotlin/com/wespot/auth/dto/SignInRequest.kt b/core/src/main/kotlin/com/wespot/auth/dto/request/SignInRequest.kt similarity index 89% rename from core/src/main/kotlin/com/wespot/auth/dto/SignInRequest.kt rename to core/src/main/kotlin/com/wespot/auth/dto/request/SignInRequest.kt index cd9eb5e5..db260413 100644 --- a/core/src/main/kotlin/com/wespot/auth/dto/SignInRequest.kt +++ b/core/src/main/kotlin/com/wespot/auth/dto/request/SignInRequest.kt @@ -1,4 +1,4 @@ -package com.wespot.auth.dto +package com.wespot.auth.dto.request import org.springframework.security.authentication.UsernamePasswordAuthenticationToken diff --git a/core/src/main/kotlin/com/wespot/auth/dto/SignUpRequest.kt b/core/src/main/kotlin/com/wespot/auth/dto/request/SignUpRequest.kt similarity index 62% rename from core/src/main/kotlin/com/wespot/auth/dto/SignUpRequest.kt rename to core/src/main/kotlin/com/wespot/auth/dto/request/SignUpRequest.kt index c727afd2..0aa7fc91 100644 --- a/core/src/main/kotlin/com/wespot/auth/dto/SignUpRequest.kt +++ b/core/src/main/kotlin/com/wespot/auth/dto/request/SignUpRequest.kt @@ -1,10 +1,10 @@ -package com.wespot.auth.dto +package com.wespot.auth.dto.request data class SignUpRequest( - val singUpToken: String, + val signUpToken: String, val profile: ProfileRequest, val userConsent: UserConsentRequest, - val school: SchoolRequest, + val schoolId: Long, val grade: Int, val groupNumber: Int, ) \ No newline at end of file diff --git a/core/src/main/kotlin/com/wespot/auth/dto/UserConsentRequest.kt b/core/src/main/kotlin/com/wespot/auth/dto/request/UserConsentRequest.kt similarity index 78% rename from core/src/main/kotlin/com/wespot/auth/dto/UserConsentRequest.kt rename to core/src/main/kotlin/com/wespot/auth/dto/request/UserConsentRequest.kt index 242b63d2..747e1e6b 100644 --- a/core/src/main/kotlin/com/wespot/auth/dto/UserConsentRequest.kt +++ b/core/src/main/kotlin/com/wespot/auth/dto/request/UserConsentRequest.kt @@ -1,4 +1,4 @@ -package com.wespot.auth.dto +package com.wespot.auth.dto.request import com.wespot.user.ConsentType diff --git a/core/src/main/kotlin/com/wespot/auth/dto/SignInResponse.kt b/core/src/main/kotlin/com/wespot/auth/dto/response/SignInResponse.kt similarity index 70% rename from core/src/main/kotlin/com/wespot/auth/dto/SignInResponse.kt rename to core/src/main/kotlin/com/wespot/auth/dto/response/SignInResponse.kt index 4bf23ce3..5df1803c 100644 --- a/core/src/main/kotlin/com/wespot/auth/dto/SignInResponse.kt +++ b/core/src/main/kotlin/com/wespot/auth/dto/response/SignInResponse.kt @@ -1,4 +1,4 @@ -package com.wespot.auth.dto +package com.wespot.auth.dto.response data class SignInResponse ( val accessToken: String, diff --git a/core/src/main/kotlin/com/wespot/auth/dto/SignUpResponse.kt b/core/src/main/kotlin/com/wespot/auth/dto/response/SignUpResponse.kt similarity index 60% rename from core/src/main/kotlin/com/wespot/auth/dto/SignUpResponse.kt rename to core/src/main/kotlin/com/wespot/auth/dto/response/SignUpResponse.kt index 8b7690ab..753d4291 100644 --- a/core/src/main/kotlin/com/wespot/auth/dto/SignUpResponse.kt +++ b/core/src/main/kotlin/com/wespot/auth/dto/response/SignUpResponse.kt @@ -1,4 +1,4 @@ -package com.wespot.auth.dto +package com.wespot.auth.dto.response data class SignUpResponse( val signUpToken: String diff --git a/core/src/main/kotlin/com/wespot/auth/dto/SocialResponse.kt b/core/src/main/kotlin/com/wespot/auth/dto/response/SocialResponse.kt similarity index 76% rename from core/src/main/kotlin/com/wespot/auth/dto/SocialResponse.kt rename to core/src/main/kotlin/com/wespot/auth/dto/response/SocialResponse.kt index 4ae396f5..21ee0baf 100644 --- a/core/src/main/kotlin/com/wespot/auth/dto/SocialResponse.kt +++ b/core/src/main/kotlin/com/wespot/auth/dto/response/SocialResponse.kt @@ -1,4 +1,4 @@ -package com.wespot.auth.dto +package com.wespot.auth.dto.response data class SocialResponse( val socialId: String, diff --git a/core/src/main/kotlin/com/wespot/auth/dto/TokenResponse.kt b/core/src/main/kotlin/com/wespot/auth/dto/response/TokenResponse.kt similarity index 69% rename from core/src/main/kotlin/com/wespot/auth/dto/TokenResponse.kt rename to core/src/main/kotlin/com/wespot/auth/dto/response/TokenResponse.kt index 11023841..34c287f5 100644 --- a/core/src/main/kotlin/com/wespot/auth/dto/TokenResponse.kt +++ b/core/src/main/kotlin/com/wespot/auth/dto/response/TokenResponse.kt @@ -1,4 +1,4 @@ -package com.wespot.auth.dto +package com.wespot.auth.dto.response data class TokenResponse( val accessToken: String, diff --git a/core/src/main/kotlin/com/wespot/auth/port/out/AuthDataPort.kt b/core/src/main/kotlin/com/wespot/auth/port/out/AuthDataPort.kt new file mode 100644 index 00000000..d5879ba3 --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/port/out/AuthDataPort.kt @@ -0,0 +1,11 @@ +package com.wespot.auth.port.out + +import com.wespot.auth.dto.AuthData + +interface AuthDataPort { + + fun saveAuthData(token: String, authData: AuthData) + + fun getAuthData(token: String): AuthData? + +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/wespot/auth/port/out/RefreshTokenPort.kt b/core/src/main/kotlin/com/wespot/auth/port/out/RefreshTokenPort.kt index ac62e524..397e2b9e 100644 --- a/core/src/main/kotlin/com/wespot/auth/port/out/RefreshTokenPort.kt +++ b/core/src/main/kotlin/com/wespot/auth/port/out/RefreshTokenPort.kt @@ -5,9 +5,9 @@ import com.wespot.user.User interface RefreshTokenPort { - fun create(refreshToken: RefreshToken): RefreshToken + fun save(refreshToken: RefreshToken): RefreshToken - fun findByUser(user: User): RefreshToken? + fun findByUserId(userId: Long): RefreshToken? fun saveOrUpdate(refreshToken: RefreshToken): RefreshToken diff --git a/core/src/main/kotlin/com/wespot/auth/service/SocialAuthService.kt b/core/src/main/kotlin/com/wespot/auth/service/SocialAuthService.kt index b00975d3..2370c63b 100644 --- a/core/src/main/kotlin/com/wespot/auth/service/SocialAuthService.kt +++ b/core/src/main/kotlin/com/wespot/auth/service/SocialAuthService.kt @@ -1,7 +1,7 @@ package com.wespot.auth.service -import com.wespot.auth.dto.AuthLoginRequest -import com.wespot.auth.dto.SocialResponse +import com.wespot.auth.dto.request.AuthLoginRequest +import com.wespot.auth.dto.response.SocialResponse import com.wespot.user.SocialType interface SocialAuthService { diff --git a/core/src/main/kotlin/com/wespot/auth/service/apple/AppleService.kt b/core/src/main/kotlin/com/wespot/auth/service/apple/AppleService.kt index d01cca05..e7dde085 100644 --- a/core/src/main/kotlin/com/wespot/auth/service/apple/AppleService.kt +++ b/core/src/main/kotlin/com/wespot/auth/service/apple/AppleService.kt @@ -1,7 +1,7 @@ package com.wespot.auth.service.apple -import com.wespot.auth.dto.AuthLoginRequest -import com.wespot.auth.dto.SocialResponse +import com.wespot.auth.dto.request.AuthLoginRequest +import com.wespot.auth.dto.response.SocialResponse import com.wespot.auth.dto.apple.AppleRevokeRequest import com.wespot.auth.dto.apple.AppleTokenResult import com.wespot.auth.service.SocialAuthService diff --git a/core/src/main/kotlin/com/wespot/auth/service/jwt/JwtTokenProvider.kt b/core/src/main/kotlin/com/wespot/auth/service/jwt/JwtTokenProvider.kt index a7c57253..133aa363 100644 --- a/core/src/main/kotlin/com/wespot/auth/service/jwt/JwtTokenProvider.kt +++ b/core/src/main/kotlin/com/wespot/auth/service/jwt/JwtTokenProvider.kt @@ -3,7 +3,7 @@ package com.wespot.auth.service.jwt import com.wespot.auth.JwtTokenInfo.ACCESS_TOKEN import com.wespot.auth.JwtTokenInfo.EMAIL_CLAIM import com.wespot.auth.JwtTokenInfo.REFRESH_TOKEN -import com.wespot.auth.dto.TokenResponse +import com.wespot.auth.dto.response.TokenResponse import io.jsonwebtoken.Jwts import io.jsonwebtoken.SignatureAlgorithm import io.jsonwebtoken.security.Keys diff --git a/core/src/main/kotlin/com/wespot/auth/service/kakao/KakaoService.kt b/core/src/main/kotlin/com/wespot/auth/service/kakao/KakaoService.kt index 15fdc638..e0f2fb1a 100644 --- a/core/src/main/kotlin/com/wespot/auth/service/kakao/KakaoService.kt +++ b/core/src/main/kotlin/com/wespot/auth/service/kakao/KakaoService.kt @@ -1,7 +1,7 @@ package com.wespot.auth.service.kakao -import com.wespot.auth.dto.AuthLoginRequest -import com.wespot.auth.dto.SocialResponse +import com.wespot.auth.dto.request.AuthLoginRequest +import com.wespot.auth.dto.response.SocialResponse import com.wespot.auth.service.SocialAuthService import com.wespot.user.SocialType import org.springframework.beans.factory.annotation.Value From adab3e58394f66b484292adebb7c7baeae9a99f1 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 18:53:48 +0900 Subject: [PATCH 20/34] =?UTF-8?q?feat:=20SecurityUtils=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/wespot/auth/service/SecurityUtils.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 core/src/main/kotlin/com/wespot/auth/service/SecurityUtils.kt diff --git a/core/src/main/kotlin/com/wespot/auth/service/SecurityUtils.kt b/core/src/main/kotlin/com/wespot/auth/service/SecurityUtils.kt new file mode 100644 index 00000000..6bf045f5 --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/service/SecurityUtils.kt @@ -0,0 +1,22 @@ +package com.wespot.auth.service + + +import com.wespot.auth.PrincipalDetails +import com.wespot.user.User +import com.wespot.user.port.out.UserPort +import org.springframework.security.core.context.SecurityContextHolder + +object SecurityUtils +{ + fun getLoginUserId(userPort : UserPort) : Long{ + val principal = SecurityContextHolder.getContext().authentication.principal as PrincipalDetails + return userPort.findByEmail(principal.username)?.id + ?: throw NoSuchElementException("해당 계정이 존재하지 않습니다.") + } + + fun getLoginUser(userPort : UserPort) : User { + val principal = SecurityContextHolder.getContext().authentication.principal as PrincipalDetails + return userPort.findByEmail(principal.username) + ?: throw NoSuchElementException("해당 계정이 존재하지 않습니다.") + } +} \ No newline at end of file From bb46e8db1ce271131f1776d815ad6784ec355587 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 18:54:09 +0900 Subject: [PATCH 21/34] =?UTF-8?q?feat:=20AuthService=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/wespot/auth/service/AuthService.kt | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 core/src/main/kotlin/com/wespot/auth/service/AuthService.kt diff --git a/core/src/main/kotlin/com/wespot/auth/service/AuthService.kt b/core/src/main/kotlin/com/wespot/auth/service/AuthService.kt new file mode 100644 index 00000000..95034099 --- /dev/null +++ b/core/src/main/kotlin/com/wespot/auth/service/AuthService.kt @@ -0,0 +1,211 @@ +package com.wespot.auth.service + +import com.wespot.auth.dto.* +import com.wespot.auth.dto.request.AuthLoginRequest +import com.wespot.auth.dto.request.RefreshTokenRequest +import com.wespot.auth.dto.request.SignInRequest +import com.wespot.auth.dto.request.SignUpRequest +import com.wespot.auth.dto.response.SignUpResponse +import com.wespot.auth.dto.response.SocialResponse +import com.wespot.auth.dto.response.TokenResponse +import com.wespot.auth.port.out.AuthDataPort +import com.wespot.auth.port.out.RefreshTokenPort +import com.wespot.auth.service.jwt.JwtTokenProvider +import com.wespot.school.port.out.SchoolPort +import com.wespot.user.* +import com.wespot.user.port.out.ProfilePort +import com.wespot.user.port.out.UserConsentPort +import com.wespot.user.port.out.UserPort +import org.springframework.beans.factory.annotation.Value +import org.springframework.security.authentication.AuthenticationManager +import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.time.LocalDateTime +import java.util.* + +@Service +@Transactional +class AuthService( + private val userPort: UserPort, + private val refreshTokenPort: RefreshTokenPort, + private val userConsentPort: UserConsentPort, + private val profilePort: ProfilePort, + private val schoolPort: SchoolPort, + private val authDataPort: AuthDataPort, + private val jwtTokenProvider: JwtTokenProvider, + private val socialAuthServiceFactory: SocialAuthServiceFactory, + private val authenticationService: AuthenticationService, + private val authenticationManager: AuthenticationManager, + private val passwordEncoder: PasswordEncoder, + private val refreshTokenService: RefreshTokenService, + + @Value("\${jwt.secret}") + private val secretKey: String +) { + + + fun socialAccess(authLoginRequest: AuthLoginRequest): Any { + + val socialResponse = fetchSocialEmail(authLoginRequest) + val socialEmail = formatSocialEmail(socialResponse.socialId, authLoginRequest.socialType) + + val authData = AuthData( + email = socialEmail, + socialRefreshToken = socialResponse.socialRefreshToken, + socialEmail = socialResponse.socialEmail, + ) + val user = userPort.findByEmail(socialEmail) + ?: return SignUpResponse(createSignUpToken(authDate = authData)) + + return signIn(createSignInRequest(user)) + + } + + + fun signIn(signInRequest: SignInRequest): TokenResponse { + + val authentication = authenticateUser(signInRequest) + val generateToken = jwtTokenProvider.generateToken(authentication) + val user = getUserByEmail(authentication.name) + + refreshTokenService.saveOrUpdateRefreshToken(generateToken.refreshToken, user) + + return TokenResponse( + accessToken = generateToken.accessToken, + refreshToken = generateToken.refreshToken + ) + + } + + + fun signUp(signUpRequest: SignUpRequest): TokenResponse { + + val signUpToken = checkSignUpToken(signUpRequest.signUpToken) + + val user = createUser(signUpToken, signUpRequest) + val savedUser = userPort.save(user) + + saveRelatedEntities(savedUser, signUpRequest) + + return signIn(createSignInRequest(savedUser)) + + } + + private fun createUser( + signUpToken: AuthData, + signUpRequest: SignUpRequest + ): User { + + val school = (schoolPort.findById(signUpRequest.schoolId) + ?: throw NoSuchElementException("해당 학교가 존재하지 않습니다.")) + + val social = Social.create( + email = signUpToken.email, + socialEmail = signUpToken.socialEmail, + socialRefreshToken = signUpToken.socialRefreshToken + ) + + return User.create( + email = signUpToken.email, + password = passwordEncoder.encode(signUpToken.email + secretKey), + schoolId = school.id, + grade = signUpRequest.grade, + groupNumber = signUpRequest.groupNumber, + social = social + ) + + } + + fun saveRelatedEntities( + user: User, + signUpRequest: SignUpRequest + ) { + + val userConsent = UserConsent.create( + user = user, + consentType = signUpRequest.userConsent.consentType, + consentValue = signUpRequest.userConsent.consentValue, + consentedAt = LocalDateTime.now() + ) + + val profile = Profile.create( + user = user, + backgroundColor = signUpRequest.profile.backgroundColor, + iconUrl = signUpRequest.profile.iconUrl + ) + + userConsentPort.save(userConsent) + profilePort.save(profile) + } + + fun reIssueToken(refreshTokenRequest: RefreshTokenRequest): TokenResponse { + + val authentication = authenticationService.getAuthentication(token = refreshTokenRequest.refreshToken) + val generateToken = jwtTokenProvider.generateToken(authentication = authentication) + val user = getUserByEmail(authentication.name) + + refreshTokenService.saveOrUpdateRefreshToken(generateToken.refreshToken, user) + + return TokenResponse( + accessToken = generateToken.accessToken, + refreshToken = generateToken.refreshToken + ) + + } + + fun revoke() { + + val loginUserId = getLoginUserId() + val revokeUser = userPort.findById(loginUserId) + ?: throw NoSuchElementException("해당 계정이 존재하지 않습니다.") + + socialAuthServiceFactory.getService(revokeUser.social.socialType) + .revoke(revokeUser.social.socialId, revokeUser.social.socialRefreshToken) + + refreshTokenPort.deleteByUserId(loginUserId) + userPort.save(revokeUser.withdraw(revokeUser)) + + } + + private fun fetchSocialEmail(authLoginRequest: AuthLoginRequest): SocialResponse { + return socialAuthServiceFactory.getService(authLoginRequest.socialType) + .fetchAuthToken(authLoginRequest) + } + + + private fun getUserByEmail(email: String): User { + return userPort.findByEmail(email) + ?: throw NoSuchElementException("유저를 찾을 수 없습니다.") + } + + private fun authenticateUser(signInRequest: SignInRequest) = + authenticationManager.authenticate(signInRequest.toAuthentication()) + + private fun createSignInRequest(user: User) = SignInRequest( + email = user.email, + password = "${user.email}$secretKey" + ) + + private fun formatSocialEmail(socialId: String, socialType: SocialType): String { + return "$socialId@${socialType.name}" + } + + + private fun createSignUpToken(authDate: AuthData): String { + + val token = UUID.randomUUID().toString() + authDataPort.saveAuthData(token, authDate) + + return token + } + + fun checkSignUpToken(token: String): AuthData { + return authDataPort.getAuthData(token) ?: throw NoSuchElementException("회원가입 토큰이 만료되었습니다.") + } + + fun getLoginUserId(): Long { + return SecurityUtils.getLoginUserId(userPort) + } + +} From 30c01b2296f2968dd6ffec425d80d8f338bec081 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Tue, 16 Jul 2024 18:55:08 +0900 Subject: [PATCH 22/34] =?UTF-8?q?feat:=20Auth=20Controller=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20url=20=EC=84=A4=EC=A0=95=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/wespot/auth/AuthController.kt | 71 +++++++++++++++++++ .../wespot/config/security/CustomUrlFilter.kt | 8 +-- .../wespot/config/security/SecurityConfig.kt | 6 +- .../user/adapter/UserPersistenceAdapter.kt | 1 - 4 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 app/src/main/kotlin/com/wespot/auth/AuthController.kt diff --git a/app/src/main/kotlin/com/wespot/auth/AuthController.kt b/app/src/main/kotlin/com/wespot/auth/AuthController.kt new file mode 100644 index 00000000..32db0433 --- /dev/null +++ b/app/src/main/kotlin/com/wespot/auth/AuthController.kt @@ -0,0 +1,71 @@ +package com.wespot.auth + +import com.wespot.auth.dto.request.AuthLoginRequest +import com.wespot.auth.dto.request.RefreshTokenRequest +import com.wespot.auth.dto.request.SignUpRequest +import com.wespot.auth.dto.response.SignUpResponse +import com.wespot.auth.dto.response.TokenResponse +import com.wespot.auth.service.AuthService +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +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 + +@RestController +@RequestMapping("/api/v1/auth") +class AuthController( + private val authService: AuthService +) { + + @PostMapping("/login") + fun signIn( + @RequestBody request: AuthLoginRequest + ): Any { + + val response = authService.socialAccess(request) + + return if (response is SignUpResponse) { + ResponseEntity.status(HttpStatus.ACCEPTED).body(response) + } else { + ResponseEntity.ok() + .body(response) + } + + } + + @PostMapping("/signup") + fun signUp( + @RequestBody request: SignUpRequest + ): ResponseEntity { + + val signUp = authService.signUp(request) + + return ResponseEntity.ok() + .body(signUp) + + } + + @PostMapping("/reissue") + fun reissue( + @RequestBody request: RefreshTokenRequest + ): ResponseEntity { + + val response = authService.reIssueToken(request) + + return ResponseEntity.ok() + .body(response) + + } + + @PostMapping("/revoke") + fun revoke(): ResponseEntity { + + authService.revoke() + + return ResponseEntity.noContent().build() + + } + +} diff --git a/app/src/main/kotlin/com/wespot/config/security/CustomUrlFilter.kt b/app/src/main/kotlin/com/wespot/config/security/CustomUrlFilter.kt index c69517b5..2a514dc4 100644 --- a/app/src/main/kotlin/com/wespot/config/security/CustomUrlFilter.kt +++ b/app/src/main/kotlin/com/wespot/config/security/CustomUrlFilter.kt @@ -23,10 +23,10 @@ class CustomUrlFilter( private val validUrlPatterns = listOf( "/health", "/", - "/v1/auth/reissue", - "/v1/auth/admin", - "/v1/auth/login", - "/v1/auth/join", + "/api/v1/auth/reissue", + "/api/v1/auth/login", + "/api/v1/auth/signup", + "/api/v1/auth/revoke", ) override fun doFilterInternal( diff --git a/app/src/main/kotlin/com/wespot/config/security/SecurityConfig.kt b/app/src/main/kotlin/com/wespot/config/security/SecurityConfig.kt index 48850e6f..e7db38f7 100644 --- a/app/src/main/kotlin/com/wespot/config/security/SecurityConfig.kt +++ b/app/src/main/kotlin/com/wespot/config/security/SecurityConfig.kt @@ -62,9 +62,9 @@ class SecurityConfig( it .requestMatchers( "/health", "/", - "/v1/auth/login", - "/v1/auth/join", - "/v1/auth/reissue", + "/api/v1/auth/login", + "/api/v1/auth/signup", + "/api/v1/auth/reissue", ).permitAll() .anyRequest().authenticated() } diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt index 8ba3beb6..5616676c 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt @@ -4,7 +4,6 @@ import com.wespot.user.User import com.wespot.user.repository.UserJpaRepository import com.wespot.user.mapper.UserMapper import com.wespot.user.port.out.UserPort -import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.stereotype.Repository import org.springframework.transaction.annotation.Transactional From dbc670fd61b775af594378515043994c62f36c9d Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Wed, 17 Jul 2024 00:00:22 +0900 Subject: [PATCH 23/34] =?UTF-8?q?refactor:=20rebase=20=ED=9B=84=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/SocialAuthServiceFactoryTest.kt | 0 .../com/wespot/user/fixture/UserFixture.kt | 25 ++++--- .../wespot/vote/service/VoteServiceTest.kt | 6 +- .../wespot/auth/dto/request/SignUpRequest.kt | 2 + .../com/wespot/auth/service/AuthService.kt | 20 ++++-- .../com/wespot/user/port/in/UserUseCase.kt | 2 - .../com/wespot/user/port/out/UserPort.kt | 6 +- .../wespot/vote/dto/response/UserResponse.kt | 4 +- .../kotlin/com/wespot/auth/RefreshToken.kt | 2 +- .../main/kotlin/com/wespot/school/EstType.kt | 0 .../com/wespot/school/SchoolCategory.kt | 0 domain/src/main/kotlin/com/wespot/user/FCM.kt | 1 - .../main/kotlin/com/wespot/user/Profile.kt | 3 - .../src/main/kotlin/com/wespot/user/User.kt | 65 +++++++++++++++++-- .../kotlin/com/wespot/user/UserConsent.kt | 3 - .../kotlin/com/wespot/common/BaseEntity.kt | 1 + .../com/wespot/school/SchoolJpaRepository.kt | 1 + .../main/kotlin/com/wespot/user/FCMMapper.kt | 23 ------- .../com/wespot/user/ProfileJpaEntity.kt | 24 ------- .../kotlin/com/wespot/user/ProfileMapper.kt | 19 ------ .../com/wespot/user/SettingJpaEntity.kt | 0 .../kotlin/com/wespot/user/SocialJpaEntity.kt | 17 ----- .../com/wespot/user/UserJpaRepository.kt | 18 ----- .../main/kotlin/com/wespot/user/UserMapper.kt | 40 ------------ .../com/wespot/user/UserPersistenceAdapter.kt | 38 ----------- .../user/adapter/UserPersistenceAdapter.kt | 20 +++++- .../com/wespot/user/entity/FCMJpaEntity.kt | 8 +-- .../wespot/user/entity/ProfileJpaEntity.kt | 4 -- .../user/entity/UserConsentJpaEntity.kt | 4 -- .../com/wespot/user/entity/UserJpaEntity.kt | 19 ++++++ .../com/wespot/user/mapper/FCMMapper.kt | 22 +++++++ .../com/wespot/user/mapper/ProfileMapper.kt | 10 ++- .../wespot/user/{ => mapper}/SettingMapper.kt | 7 +- .../wespot/user/{ => mapper}/SocialMapper.kt | 7 +- .../wespot/user/mapper/UserConsentMapper.kt | 2 - .../com/wespot/user/mapper/UserMapper.kt | 56 +++++++--------- .../user/repository/UserJpaRepository.kt | 10 +++ 37 files changed, 214 insertions(+), 275 deletions(-) rename {core => app}/src/test/kotlin/com/wespot/auth/service/SocialAuthServiceFactoryTest.kt (100%) delete mode 100644 domain/src/main/kotlin/com/wespot/school/EstType.kt delete mode 100644 domain/src/main/kotlin/com/wespot/school/SchoolCategory.kt delete mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/FCMMapper.kt delete mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/ProfileJpaEntity.kt delete mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/ProfileMapper.kt delete mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/SettingJpaEntity.kt delete mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/SocialJpaEntity.kt delete mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/UserJpaRepository.kt delete mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/UserMapper.kt delete mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/UserPersistenceAdapter.kt create mode 100644 infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/FCMMapper.kt rename infrastructure/mysql/src/main/kotlin/com/wespot/user/{ => mapper}/SettingMapper.kt (76%) rename infrastructure/mysql/src/main/kotlin/com/wespot/user/{ => mapper}/SocialMapper.kt (71%) diff --git a/core/src/test/kotlin/com/wespot/auth/service/SocialAuthServiceFactoryTest.kt b/app/src/test/kotlin/com/wespot/auth/service/SocialAuthServiceFactoryTest.kt similarity index 100% rename from core/src/test/kotlin/com/wespot/auth/service/SocialAuthServiceFactoryTest.kt rename to app/src/test/kotlin/com/wespot/auth/service/SocialAuthServiceFactoryTest.kt diff --git a/app/src/test/kotlin/com/wespot/user/fixture/UserFixture.kt b/app/src/test/kotlin/com/wespot/user/fixture/UserFixture.kt index 5bbc0543..f06920b8 100644 --- a/app/src/test/kotlin/com/wespot/user/fixture/UserFixture.kt +++ b/app/src/test/kotlin/com/wespot/user/fixture/UserFixture.kt @@ -1,11 +1,6 @@ package com.wespot.user.fixture -import com.wespot.user.FCM -import com.wespot.user.Profile -import com.wespot.user.Setting -import com.wespot.user.Social -import com.wespot.user.SocialType -import com.wespot.user.User +import com.wespot.user.* import java.time.LocalDateTime object UserFixture { @@ -14,15 +9,29 @@ object UserFixture { id: Long, ) = User( id = id, + email = "TestEmail@Kakako", + password = "TestPassword", + role = Role.USER, name = "TestUser", introduction = "hello", schoolId = 1L, grade = 1, groupNumber = 1, - setting = Setting(0, false), + setting = Setting(), profile = Profile(0, "black", "image.png"), fcm = FCM(0, "token", LocalDateTime.now()), - social = Social(SocialType.KAKAO, 1L, "refreshToken"), + social = Social( + socialType = SocialType.KAKAO, + socialId = "1123123", + socialEmail = null, + socialRefreshToken = "refreshToken" + ), + userConsent = UserConsent( + id = 0, + consentType = ConsentType.MARKETING, + consentValue = true, + consentedAt = LocalDateTime.now() + ), createdAt = LocalDateTime.now(), updatedAt = null, withdrawAt = LocalDateTime.now(), diff --git a/app/src/test/kotlin/com/wespot/vote/service/VoteServiceTest.kt b/app/src/test/kotlin/com/wespot/vote/service/VoteServiceTest.kt index 878a5869..b769f1ef 100644 --- a/app/src/test/kotlin/com/wespot/vote/service/VoteServiceTest.kt +++ b/app/src/test/kotlin/com/wespot/vote/service/VoteServiceTest.kt @@ -1,10 +1,10 @@ package com.wespot.vote.service import com.wespot.DatabaseCleanup -import com.wespot.user.UserJpaEntity -import com.wespot.user.UserJpaRepository -import com.wespot.user.UserMapper +import com.wespot.user.entity.UserJpaEntity import com.wespot.user.fixture.UserFixture +import com.wespot.user.mapper.UserMapper +import com.wespot.user.repository.UserJpaRepository import com.wespot.vote.BallotJpaRepository import com.wespot.vote.VoteJpaRepository import com.wespot.vote.VoteMapper diff --git a/core/src/main/kotlin/com/wespot/auth/dto/request/SignUpRequest.kt b/core/src/main/kotlin/com/wespot/auth/dto/request/SignUpRequest.kt index 0aa7fc91..48672a98 100644 --- a/core/src/main/kotlin/com/wespot/auth/dto/request/SignUpRequest.kt +++ b/core/src/main/kotlin/com/wespot/auth/dto/request/SignUpRequest.kt @@ -2,6 +2,8 @@ package com.wespot.auth.dto.request data class SignUpRequest( val signUpToken: String, + val name: String, + val introduction: String, val profile: ProfileRequest, val userConsent: UserConsentRequest, val schoolId: Long, diff --git a/core/src/main/kotlin/com/wespot/auth/service/AuthService.kt b/core/src/main/kotlin/com/wespot/auth/service/AuthService.kt index 95034099..7fa6c9ff 100644 --- a/core/src/main/kotlin/com/wespot/auth/service/AuthService.kt +++ b/core/src/main/kotlin/com/wespot/auth/service/AuthService.kt @@ -110,6 +110,8 @@ class AuthService( email = signUpToken.email, password = passwordEncoder.encode(signUpToken.email + secretKey), schoolId = school.id, + name = signUpRequest.name, + introduction = signUpRequest.introduction, grade = signUpRequest.grade, groupNumber = signUpRequest.groupNumber, social = social @@ -123,20 +125,28 @@ class AuthService( ) { val userConsent = UserConsent.create( - user = user, consentType = signUpRequest.userConsent.consentType, consentValue = signUpRequest.userConsent.consentValue, consentedAt = LocalDateTime.now() ) val profile = Profile.create( - user = user, backgroundColor = signUpRequest.profile.backgroundColor, iconUrl = signUpRequest.profile.iconUrl ) - userConsentPort.save(userConsent) - profilePort.save(profile) + val savedUserConsent = userConsentPort.save(userConsent) + val savedProfile = profilePort.save(profile) + + val updatedUser = User.update( + user = user, + userConsent = savedUserConsent, + profile = savedProfile, + fcm = null, + setting = null + ) + userPort.save(updatedUser) + } fun reIssueToken(refreshTokenRequest: RefreshTokenRequest): TokenResponse { @@ -164,7 +174,7 @@ class AuthService( .revoke(revokeUser.social.socialId, revokeUser.social.socialRefreshToken) refreshTokenPort.deleteByUserId(loginUserId) - userPort.save(revokeUser.withdraw(revokeUser)) + userPort.save(revokeUser.withdraw()) } diff --git a/core/src/main/kotlin/com/wespot/user/port/in/UserUseCase.kt b/core/src/main/kotlin/com/wespot/user/port/in/UserUseCase.kt index 7c396bbe..49b5c092 100644 --- a/core/src/main/kotlin/com/wespot/user/port/in/UserUseCase.kt +++ b/core/src/main/kotlin/com/wespot/user/port/in/UserUseCase.kt @@ -1,7 +1,5 @@ package com.wespot.user.port.`in` -import org.springframework.stereotype.Service -@Service interface UserUseCase { } diff --git a/core/src/main/kotlin/com/wespot/user/port/out/UserPort.kt b/core/src/main/kotlin/com/wespot/user/port/out/UserPort.kt index 7cb07544..1e188c9d 100644 --- a/core/src/main/kotlin/com/wespot/user/port/out/UserPort.kt +++ b/core/src/main/kotlin/com/wespot/user/port/out/UserPort.kt @@ -1,11 +1,10 @@ package com.wespot.user.port.out import com.wespot.user.User -import org.springframework.stereotype.Repository interface UserPort { - fun findById(id: Long): User? + fun findById(userId: Long): User? fun findAllBySchoolIdAndGradeAndGroupNumber( schoolId: Long, @@ -15,12 +14,9 @@ interface UserPort { fun findIdsByIdIn(ids: List): List - fun getByEmail(userEmail: String): User? - fun findByEmail(userEmail: String): User? fun save(user: User): User - fun findById(userId: Long): User? } diff --git a/core/src/main/kotlin/com/wespot/vote/dto/response/UserResponse.kt b/core/src/main/kotlin/com/wespot/vote/dto/response/UserResponse.kt index 6d62637b..b5bee880 100644 --- a/core/src/main/kotlin/com/wespot/vote/dto/response/UserResponse.kt +++ b/core/src/main/kotlin/com/wespot/vote/dto/response/UserResponse.kt @@ -5,7 +5,7 @@ import com.wespot.user.User data class UserResponse( val id: Long, val name: String, - val profile: ProfileResponse + val profile: ProfileResponse? ) { companion object { @@ -14,7 +14,7 @@ data class UserResponse( return UserResponse( id = user.id, name = user.name, - profile = ProfileResponse.from(user.profile) + profile = null ) } diff --git a/domain/src/main/kotlin/com/wespot/auth/RefreshToken.kt b/domain/src/main/kotlin/com/wespot/auth/RefreshToken.kt index d971fb98..e13fde0f 100644 --- a/domain/src/main/kotlin/com/wespot/auth/RefreshToken.kt +++ b/domain/src/main/kotlin/com/wespot/auth/RefreshToken.kt @@ -7,7 +7,7 @@ data class RefreshToken( val id : Long, val refreshToken: String, val user: User, - val createdAt: LocalDateTime?, + val createdAt: LocalDateTime, val updatedAt: LocalDateTime?, val expiredAt: LocalDateTime ){ diff --git a/domain/src/main/kotlin/com/wespot/school/EstType.kt b/domain/src/main/kotlin/com/wespot/school/EstType.kt deleted file mode 100644 index e69de29b..00000000 diff --git a/domain/src/main/kotlin/com/wespot/school/SchoolCategory.kt b/domain/src/main/kotlin/com/wespot/school/SchoolCategory.kt deleted file mode 100644 index e69de29b..00000000 diff --git a/domain/src/main/kotlin/com/wespot/user/FCM.kt b/domain/src/main/kotlin/com/wespot/user/FCM.kt index 5db3229d..a6252954 100644 --- a/domain/src/main/kotlin/com/wespot/user/FCM.kt +++ b/domain/src/main/kotlin/com/wespot/user/FCM.kt @@ -4,7 +4,6 @@ import java.time.LocalDateTime data class FCM( val id: Long, - val user: User, val fcmToken: String?, val createdAt: LocalDateTime?, ) { diff --git a/domain/src/main/kotlin/com/wespot/user/Profile.kt b/domain/src/main/kotlin/com/wespot/user/Profile.kt index 07cc276d..8e474b29 100644 --- a/domain/src/main/kotlin/com/wespot/user/Profile.kt +++ b/domain/src/main/kotlin/com/wespot/user/Profile.kt @@ -2,20 +2,17 @@ package com.wespot.user data class Profile( val id: Long, - val user: User, val backgroundColor: String, val iconUrl: String, ) { companion object { fun create( - user: User, backgroundColor: String, iconUrl: String ) = Profile( id = 0, - user = user, backgroundColor = backgroundColor, iconUrl = iconUrl ) diff --git a/domain/src/main/kotlin/com/wespot/user/User.kt b/domain/src/main/kotlin/com/wespot/user/User.kt index 0f986ae1..171f37ea 100644 --- a/domain/src/main/kotlin/com/wespot/user/User.kt +++ b/domain/src/main/kotlin/com/wespot/user/User.kt @@ -1,6 +1,5 @@ package com.wespot.user -import com.wespot.school.School import java.time.LocalDateTime data class User( @@ -13,24 +12,37 @@ data class User( val schoolId: Long, val grade: Int, val groupNumber: Int, + val profile: Profile, + val fcm: FCM?, val setting: Setting, val social: Social, + val userConsent: UserConsent, val createdAt: LocalDateTime, val updatedAt: LocalDateTime?, val withdrawAt: LocalDateTime?, ) { - fun withdraw(user: User) = + fun withdraw() = User( id = id, - email = email, - password = password, + email = "", + password = "", + name = "", + introduction = "", role = Role.GUEST, schoolId = schoolId, grade = grade, groupNumber = groupNumber, + profile = profile, + fcm = fcm, setting = setting, - social = social, + social = Social( + socialEmail = "", + socialId = "", + socialType = social.socialType, + socialRefreshToken = "" + ), + userConsent = userConsent, createdAt = createdAt, updatedAt = LocalDateTime.now(), withdrawAt = LocalDateTime.now(), @@ -40,6 +52,8 @@ data class User( fun create( email: String, password: String, + name: String, + introduction: String, schoolId: Long, grade: Int, groupNumber: Int, @@ -49,14 +63,55 @@ data class User( id = 0L, email = email, password = password, + name = name, + introduction = introduction, role = Role.USER, schoolId = schoolId, grade = grade, groupNumber = groupNumber, + profile = Profile.create( + backgroundColor = "", + iconUrl = "", + ), + fcm = null, setting = Setting(), social = social, + userConsent = UserConsent.create( + consentType = ConsentType.MARKETING, + consentedAt = LocalDateTime.now(), + consentValue = false + ), createdAt = LocalDateTime.now(), updatedAt = LocalDateTime.now(), + withdrawAt = null ) + + fun update( + user: User, + profile: Profile?, + fcm: FCM?, + setting: Setting?, + userConsent: UserConsent? + )= + User( + id = user.id, + email = user.email, + password = user.password, + name = user.name, + introduction = user.introduction, + role = user.role, + schoolId = user.schoolId, + grade = user.grade, + groupNumber = user.groupNumber, + profile = profile?: user.profile, + fcm = fcm?: user.fcm, + setting = setting?: user.setting, + social = user.social, + userConsent = userConsent?: user.userConsent, + createdAt = user.createdAt, + updatedAt = LocalDateTime.now(), + withdrawAt = user.withdrawAt + ) + } } diff --git a/domain/src/main/kotlin/com/wespot/user/UserConsent.kt b/domain/src/main/kotlin/com/wespot/user/UserConsent.kt index 5fdc0225..e4503f43 100644 --- a/domain/src/main/kotlin/com/wespot/user/UserConsent.kt +++ b/domain/src/main/kotlin/com/wespot/user/UserConsent.kt @@ -4,21 +4,18 @@ import java.time.LocalDateTime data class UserConsent( val id: Long, - val user: User, val consentType: ConsentType?, val consentValue: Boolean?, val consentedAt: LocalDateTime? ) { companion object { fun create( - user: User, consentType: ConsentType, consentValue: Boolean, consentedAt: LocalDateTime ) = UserConsent( id = 0, - user = user, consentType = consentType, consentValue = consentValue, consentedAt = consentedAt diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt index bc4e2c30..5829f93e 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt @@ -3,6 +3,7 @@ package com.wespot.common import jakarta.persistence.Column import jakarta.persistence.Embeddable import jakarta.persistence.EntityListeners +import org.jetbrains.annotations.NotNull import org.springframework.data.annotation.CreatedDate import org.springframework.data.annotation.LastModifiedDate import org.springframework.data.jpa.domain.support.AuditingEntityListener diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolJpaRepository.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolJpaRepository.kt index 82e1637e..953ee9d3 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolJpaRepository.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/school/SchoolJpaRepository.kt @@ -3,4 +3,5 @@ package com.wespot.school import org.springframework.data.jpa.repository.JpaRepository interface SchoolJpaRepository : JpaRepository { + } diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/FCMMapper.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/FCMMapper.kt deleted file mode 100644 index 06e5ddaa..00000000 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/FCMMapper.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.wespot.user - -import com.wespot.common.BaseEntity - -object FCMMapper { - fun mapToDomainEntity(fcmJpaEntity: FCMJpaEntity): FCM = - FCM( - id = fcmJpaEntity.id, - fcmToken = fcmJpaEntity.fcmToken, - createdAt = fcmJpaEntity.baseEntity.createdAt - ) - - fun mapToJpaEntity(fcm: FCM): FCMJpaEntity = - FCMJpaEntity( - id = fcm.id, - fcmToken = fcm.fcmToken, - baseEntity = BaseEntity( - createdAt = fcm.createdAt, - updatedAt = null - ) // TODO : Domain 객체에 CreatedAt만 존재해서 조금 애매하네요.. 이 부분은 어떻게 해야할까요? - ) - -} diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/ProfileJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/ProfileJpaEntity.kt deleted file mode 100644 index 0a2b0f2f..00000000 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/ProfileJpaEntity.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.wespot.user - -import jakarta.persistence.Entity -import jakarta.persistence.GeneratedValue -import jakarta.persistence.GenerationType -import jakarta.persistence.Id -import jakarta.persistence.Table -import org.jetbrains.annotations.NotNull - -@Entity -@Table(name = "profile") -class ProfileJpaEntity( - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - val id: Long, - - @field: NotNull - val backgroundColor: String, - - @field: NotNull - val iconUrl: String - -) diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/ProfileMapper.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/ProfileMapper.kt deleted file mode 100644 index 08cd81d6..00000000 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/ProfileMapper.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.wespot.user - -object ProfileMapper { - - fun mapToDomainEntity(profileJpaEntity: ProfileJpaEntity): Profile = - Profile( - id = profileJpaEntity.id, - backgroundColor = profileJpaEntity.backgroundColor, - iconUrl = profileJpaEntity.iconUrl - ) - - fun mapToJpaEntity(profile: Profile): ProfileJpaEntity = - ProfileJpaEntity( - id = profile.id, - backgroundColor = profile.backgroundColor, - iconUrl = profile.iconUrl, - ) - -} diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/SettingJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/SettingJpaEntity.kt deleted file mode 100644 index e69de29b..00000000 diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/SocialJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/SocialJpaEntity.kt deleted file mode 100644 index 2db33fb0..00000000 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/SocialJpaEntity.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.wespot.user - -import jakarta.persistence.Embeddable -import org.jetbrains.annotations.NotNull - -@Embeddable -class SocialJpaEntity( - - @field: NotNull - val socialId: Long, - - @field: NotNull - val socialType: SocialType, - - val socialRefreshToken: String - -) diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/UserJpaRepository.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/UserJpaRepository.kt deleted file mode 100644 index 8e56d66c..00000000 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/UserJpaRepository.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.wespot.user - -import org.springframework.data.jpa.repository.JpaRepository -import org.springframework.data.jpa.repository.Query -import org.springframework.data.repository.query.Param - -interface UserJpaRepository : JpaRepository { - - fun findAllBySchoolIdAndGradeAndGroupNumber( - schoolId: Long, - grade: Int, - groupNumber: Int - ): List - - @Query("SELECT u.id FROM UserJpaEntity u WHERE u.id IN :ids") - fun findIdsByIdIn(@Param("ids") ids: List): List - -} diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/UserMapper.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/UserMapper.kt deleted file mode 100644 index 9810cab4..00000000 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/UserMapper.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.wespot.user - -import com.wespot.common.BaseEntity - -object UserMapper { - - fun mapToDomainEntity(userJpaEntity: UserJpaEntity): User = - User( - id = userJpaEntity.id, - name = userJpaEntity.name, - introduction = userJpaEntity.introduction, - schoolId = userJpaEntity.schoolId, - grade = userJpaEntity.grade, - groupNumber = userJpaEntity.groupNumber, - setting = SettingMapper.mapToDomainEntity(userJpaEntity.setting), - profile = ProfileMapper.mapToDomainEntity(userJpaEntity.profile), - fcm = FCMMapper.mapToDomainEntity(userJpaEntity.fcm), - social = SocialMapper.mapToDomainEntity(userJpaEntity.social), - createdAt = userJpaEntity.baseEntity.createdAt, - updatedAt = userJpaEntity.baseEntity.updatedAt, - withdrawAt = userJpaEntity.withdrawAt - ) - - fun mapToJpaEntity(user: User): UserJpaEntity = - UserJpaEntity( - id = user.id, - name = user.name, - introduction = user.introduction, - schoolId = user.schoolId, - grade = user.grade, - setting = SettingMapper.mapToJpaEntity(user.setting), - profile = ProfileMapper.mapToJpaEntity(user.profile), - fcm = FCMMapper.mapToJpaEntity(user.fcm), - social = SocialMapper.mapToJpaEntity(user.social), - groupNumber = user.groupNumber, - withdrawAt = user.withdrawAt, - baseEntity = BaseEntity(user.createdAt, user.updatedAt), - ) - -} diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/UserPersistenceAdapter.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/UserPersistenceAdapter.kt deleted file mode 100644 index 789a1488..00000000 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/UserPersistenceAdapter.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.wespot.user - -import com.wespot.user.port.out.UserPort -import org.springframework.stereotype.Repository -import kotlin.jvm.optionals.getOrNull - -@Repository -class UserPersistenceAdapter( - private val userJpaRepository: UserJpaRepository -) : UserPort { - - override fun findById(id: Long): User? { - return userJpaRepository.findById(id) - .getOrNull() - ?.let { userJpaEntity -> - UserMapper.mapToDomainEntity(userJpaEntity) - } - } - - override fun findAllBySchoolIdAndGradeAndGroupNumber( - schoolId: Long, - grade: Int, - groupNumber: Int - ): List { - return userJpaRepository.findAllBySchoolIdAndGradeAndGroupNumber( - schoolId, - grade, - groupNumber - ).stream() - .map { userJpaEntity -> UserMapper.mapToDomainEntity(userJpaEntity) } - .toList() - } - - override fun findIdsByIdIn(ids: List): List { - return userJpaRepository.findIdsByIdIn(ids) - } - -} diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt index 5616676c..495edc1e 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt @@ -29,4 +29,22 @@ class UserPersistenceAdapter( .let { UserMapper.mapToDomainEntity(it) } } -} \ No newline at end of file + override fun findAllBySchoolIdAndGradeAndGroupNumber( + schoolId: Long, + grade: Int, + groupNumber: Int + ): List { + return userJpaRepository.findAllBySchoolIdAndGradeAndGroupNumber( + schoolId, + grade, + groupNumber + ).stream() + .map { userJpaEntity -> UserMapper.mapToDomainEntity(userJpaEntity) } + .toList() + } + + override fun findIdsByIdIn(ids: List): List { + return userJpaRepository.findIdsByIdIn(ids) + } + +} diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/FCMJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/FCMJpaEntity.kt index 692a1d8c..49d02168 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/FCMJpaEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/FCMJpaEntity.kt @@ -8,6 +8,7 @@ import jakarta.persistence.GenerationType import jakarta.persistence.Id import jakarta.persistence.Table import org.jetbrains.annotations.NotNull +import java.time.LocalDateTime @Entity @Table(name = "fcm") @@ -17,15 +18,10 @@ class FCMJpaEntity( @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long, - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "users_id", foreignKey = ForeignKey(name = "fk_fcm_users_id")) - val user: UserJpaEntity, - @field: NotNull val fcmToken: String?, - @Embedded @field: NotNull - val baseEntity: BaseEntity? + val createdAt: LocalDateTime? ) diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/ProfileJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/ProfileJpaEntity.kt index 576cf710..b91fd1a3 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/ProfileJpaEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/ProfileJpaEntity.kt @@ -11,10 +11,6 @@ class ProfileJpaEntity( @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long, - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "users_id", foreignKey = ForeignKey(name = "fk_profile_users_id")) - val user: UserJpaEntity, - @field: NotNull val backgroundColor: String, diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserConsentJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserConsentJpaEntity.kt index d2fbddb0..1ff2ff09 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserConsentJpaEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserConsentJpaEntity.kt @@ -12,10 +12,6 @@ class UserConsentJpaEntity ( @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long, - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "users_id", foreignKey = ForeignKey(name = "fk_user_consent_users_id")) - val user: UserJpaEntity, - @Enumerated(EnumType.STRING) val consentType: ConsentType?, diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserJpaEntity.kt index d40bb1c7..903934ec 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserJpaEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserJpaEntity.kt @@ -21,9 +21,28 @@ class UserJpaEntity( @field: NotNull val password: String, + @field: NotNull + val name: String, + + @field: NotNull + val introduction: String, + @field: NotNull val schoolId: Long, + @field: NotNull + @OneToOne(fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST]) + @JoinColumn(name = "profile_id", foreignKey = ForeignKey(name = "fk_users_profile_id")) + val profile: ProfileJpaEntity, + + @OneToOne(fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST]) + @JoinColumn(name = "fcm_id", foreignKey = ForeignKey(name = "fk_users_fcm_id")) + val fcm: FCMJpaEntity, + + @OneToOne(fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST]) + @JoinColumn(name = "user_consent_id", foreignKey = ForeignKey(name = "fk_users_user_consent_id")) + val userConsent: UserConsentJpaEntity, + @field: NotNull val grade: Int, diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/FCMMapper.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/FCMMapper.kt new file mode 100644 index 00000000..01bff816 --- /dev/null +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/FCMMapper.kt @@ -0,0 +1,22 @@ +package com.wespot.user.mapper + +import com.wespot.common.BaseEntity +import com.wespot.user.FCM +import com.wespot.user.entity.FCMJpaEntity + +object FCMMapper { + fun mapToDomainEntity(fcmJpaEntity: FCMJpaEntity): FCM = + FCM( + id = fcmJpaEntity.id, + fcmToken = fcmJpaEntity.fcmToken, + createdAt = fcmJpaEntity.createdAt + ) + + fun mapToJpaEntity(fcm: FCM?): FCMJpaEntity = + FCMJpaEntity( + id = fcm?.id ?: 0L, + fcmToken = fcm?.fcmToken, + createdAt = fcm?.createdAt, + ) + +} diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/ProfileMapper.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/ProfileMapper.kt index 6bd234aa..7be8feda 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/ProfileMapper.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/ProfileMapper.kt @@ -5,18 +5,16 @@ import com.wespot.user.entity.ProfileJpaEntity object ProfileMapper { - fun mapToDomainEntity(profile: ProfileJpaEntity): Profile = + fun mapToDomainEntity(profileJpaEntity: ProfileJpaEntity): Profile = Profile( - id = profile.id, - user = UserMapper.mapToDomainEntity(profile.user), - backgroundColor = profile.backgroundColor, - iconUrl = profile.iconUrl + id = profileJpaEntity.id, + backgroundColor = profileJpaEntity.backgroundColor, + iconUrl = profileJpaEntity.iconUrl ) fun mapToJpaEntity(profile: Profile): ProfileJpaEntity = ProfileJpaEntity( id = profile.id, - user = UserMapper.mapToJpaEntity(profile.user), backgroundColor = profile.backgroundColor, iconUrl = profile.iconUrl ) diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/SettingMapper.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/SettingMapper.kt similarity index 76% rename from infrastructure/mysql/src/main/kotlin/com/wespot/user/SettingMapper.kt rename to infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/SettingMapper.kt index 3dffd933..a4d23c17 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/SettingMapper.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/SettingMapper.kt @@ -1,16 +1,17 @@ -package com.wespot.user +package com.wespot.user.mapper + +import com.wespot.user.Setting +import com.wespot.user.entity.SettingJpaEntity object SettingMapper { fun mapToDomainEntity(settingJpaEntity: SettingJpaEntity): Setting = Setting( - id = settingJpaEntity.id, isEnableNotification = settingJpaEntity.isEnableNotification ) fun mapToJpaEntity(setting: Setting): SettingJpaEntity = SettingJpaEntity( - id = setting.id, isEnableNotification = setting.isEnableNotification ) diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/SocialMapper.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/SocialMapper.kt similarity index 71% rename from infrastructure/mysql/src/main/kotlin/com/wespot/user/SocialMapper.kt rename to infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/SocialMapper.kt index 29775149..fdc8fbe9 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/SocialMapper.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/SocialMapper.kt @@ -1,4 +1,7 @@ -package com.wespot.user +package com.wespot.user.mapper + +import com.wespot.user.Social +import com.wespot.user.entity.SocialJpaEntity object SocialMapper { @@ -6,6 +9,7 @@ object SocialMapper { Social( socialId = socialJpaEntity.socialId, socialType = socialJpaEntity.socialType, + socialEmail = socialJpaEntity.socialEmail, socialRefreshToken = socialJpaEntity.socialRefreshToken ) @@ -13,6 +17,7 @@ object SocialMapper { SocialJpaEntity( socialId = social.socialId, socialType = social.socialType, + socialEmail = social.socialEmail, socialRefreshToken = social.socialRefreshToken ) diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserConsentMapper.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserConsentMapper.kt index 96f85e07..fedc55e5 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserConsentMapper.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserConsentMapper.kt @@ -8,7 +8,6 @@ object UserConsentMapper { fun mapToDomainEntity(userConsentJpaEntity: UserConsentJpaEntity): UserConsent = UserConsent( id = userConsentJpaEntity.id, - user = UserMapper.mapToDomainEntity(userConsentJpaEntity.user), consentType = userConsentJpaEntity.consentType, consentValue = userConsentJpaEntity.consentValue, consentedAt = userConsentJpaEntity.consentedAt, @@ -18,7 +17,6 @@ object UserConsentMapper { fun mapToJpaEntity(userConsent: UserConsent): UserConsentJpaEntity = UserConsentJpaEntity( id = userConsent.id, - user = UserMapper.mapToJpaEntity(userConsent.user), consentType = userConsent.consentType, consentValue = userConsent.consentValue, consentedAt = userConsent.consentedAt, diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserMapper.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserMapper.kt index db684450..50e9f7ff 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserMapper.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/mapper/UserMapper.kt @@ -1,34 +1,30 @@ package com.wespot.user.mapper import com.wespot.common.BaseEntity -import com.wespot.school.School -import com.wespot.school.SchoolJpaEntity import com.wespot.user.* import com.wespot.user.entity.* object UserMapper { - fun mapToDomainEntity(user: UserJpaEntity): User = + fun mapToDomainEntity(userJpaEntity: UserJpaEntity): User = User( - id = user.id, - email = user.email, - password = user.password, - setting = Setting( - isEnableNotification = user.setting.isEnableNotification, - ), - schoolId = user.schoolId, - grade = user.grade, - groupNumber = user.groupNumber, - role = user.role, - social = Social( - socialType = user.social.socialType, - socialId = user.social.socialId, - socialEmail = user.social.socialEmail, - socialRefreshToken = user.social.socialRefreshToken, - ), - createdAt = user.baseEntity.createdAt, - updatedAt = user.baseEntity.updatedAt, - withdrawAt = user.withdrawAt, + id = userJpaEntity.id, + email = userJpaEntity.email, + password = userJpaEntity.password, + name = userJpaEntity.name, + introduction = userJpaEntity.introduction, + schoolId = userJpaEntity.schoolId, + grade = userJpaEntity.grade, + groupNumber = userJpaEntity.groupNumber, + role = userJpaEntity.role, + setting = SettingMapper.mapToDomainEntity(userJpaEntity.setting), + profile = ProfileMapper.mapToDomainEntity(userJpaEntity.profile), + fcm = FCMMapper.mapToDomainEntity(userJpaEntity.fcm), + social = SocialMapper.mapToDomainEntity(userJpaEntity.social), + userConsent = UserConsentMapper.mapToDomainEntity(userJpaEntity.userConsent), + createdAt = userJpaEntity.baseEntity.createdAt, + updatedAt = userJpaEntity.baseEntity.updatedAt, + withdrawAt = userJpaEntity.withdrawAt, ) @@ -37,19 +33,17 @@ object UserMapper { id = user.id, email = user.email, password = user.password, - setting = SettingJpaEntity( - isEnableNotification = user.setting.isEnableNotification, - ), + name = user.name, + introduction = user.introduction, schoolId = user.schoolId, grade = user.grade, groupNumber = user.groupNumber, role = user.role, - social = SocialJpaEntity( - socialType = user.social.socialType, - socialId = user.social.socialId, - socialEmail = user.social.socialEmail, - socialRefreshToken = user.social.socialRefreshToken, - ), + setting = SettingMapper.mapToJpaEntity(user.setting), + profile = ProfileMapper.mapToJpaEntity(user.profile), + fcm = FCMMapper.mapToJpaEntity(user.fcm), + social = SocialMapper.mapToJpaEntity(user.social), + userConsent = UserConsentMapper.mapToJpaEntity(user.userConsent), withdrawAt = user.withdrawAt, baseEntity = BaseEntity( createdAt = user.createdAt, diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/UserJpaRepository.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/UserJpaRepository.kt index 1aed31b1..6faee102 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/UserJpaRepository.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/UserJpaRepository.kt @@ -2,9 +2,19 @@ package com.wespot.user.repository import com.wespot.user.entity.UserJpaEntity import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.query.Param interface UserJpaRepository : JpaRepository { fun findByEmail(email: String): UserJpaEntity? + fun findAllBySchoolIdAndGradeAndGroupNumber( + schoolId: Long, + grade: Int, + groupNumber: Int + ): List + + @Query("SELECT u.id FROM UserJpaEntity u WHERE u.id IN :ids") + fun findIdsByIdIn(@Param("ids") ids: List): List } \ No newline at end of file From b8f61d4be15bcee3cd5e9d0e535ced1ae91879a6 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Wed, 17 Jul 2024 01:02:38 +0900 Subject: [PATCH 24/34] =?UTF-8?q?test:=20service=20Test=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 6 ++ .../auth/fixture/RefreshTokenFixture.kt | 22 ++++++ .../wespot/auth/service/AuthServiceTest.kt | 66 ++++++++++++++++ .../auth/service/AuthenticationServiceTest.kt | 41 ++++++++++ .../service/PrincipalDetailServiceTest.kt | 32 ++++++++ .../auth/service/RefreshTokenServiceTest.kt | 77 +++++++++++++++++++ 6 files changed, 244 insertions(+) create mode 100644 app/src/test/kotlin/com/wespot/auth/fixture/RefreshTokenFixture.kt create mode 100644 app/src/test/kotlin/com/wespot/auth/service/AuthServiceTest.kt create mode 100644 app/src/test/kotlin/com/wespot/auth/service/AuthenticationServiceTest.kt create mode 100644 app/src/test/kotlin/com/wespot/auth/service/PrincipalDetailServiceTest.kt create mode 100644 app/src/test/kotlin/com/wespot/auth/service/RefreshTokenServiceTest.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 358dc5ac..ac0e13d8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -11,6 +11,12 @@ dependencies { implementation(project(":infrastructure:mysql")) implementation(project(":infrastructure:redis")) + + // https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api + testImplementation("io.jsonwebtoken:jjwt-api:0.11.2") + testImplementation("io.jsonwebtoken:jjwt-impl:0.11.2") + testImplementation("io.jsonwebtoken:jjwt-jackson:0.11.2") + testImplementation("io.rest-assured:rest-assured") diff --git a/app/src/test/kotlin/com/wespot/auth/fixture/RefreshTokenFixture.kt b/app/src/test/kotlin/com/wespot/auth/fixture/RefreshTokenFixture.kt new file mode 100644 index 00000000..941bf898 --- /dev/null +++ b/app/src/test/kotlin/com/wespot/auth/fixture/RefreshTokenFixture.kt @@ -0,0 +1,22 @@ +package com.wespot.auth.fixture + +import com.wespot.auth.RefreshToken +import com.wespot.user.* +import com.wespot.user.fixture.UserFixture +import java.time.LocalDateTime + +object RefreshTokenFixture { + + fun createWithIdAndRefreshToken( + id: Long, + refreshToken: RefreshToken + ) = RefreshToken( + id = id, + refreshToken = refreshToken.refreshToken, + user = refreshToken.user, + createdAt = refreshToken.createdAt, + updatedAt = refreshToken.updatedAt, + expiredAt = refreshToken.expiredAt + ) + +} diff --git a/app/src/test/kotlin/com/wespot/auth/service/AuthServiceTest.kt b/app/src/test/kotlin/com/wespot/auth/service/AuthServiceTest.kt new file mode 100644 index 00000000..0574f286 --- /dev/null +++ b/app/src/test/kotlin/com/wespot/auth/service/AuthServiceTest.kt @@ -0,0 +1,66 @@ +package com.wespot.auth.service + +import com.wespot.auth.dto.* +import com.wespot.auth.dto.request.* +import com.wespot.auth.dto.response.SignUpResponse +import com.wespot.auth.dto.response.SocialResponse +import com.wespot.auth.dto.response.TokenResponse +import com.wespot.auth.port.out.AuthDataPort +import com.wespot.auth.port.out.RefreshTokenPort +import com.wespot.auth.service.jwt.JwtTokenProvider +import com.wespot.auth.service.kakao.KakaoService +import com.wespot.school.School +import com.wespot.school.SchoolType +import com.wespot.school.port.out.SchoolPort +import com.wespot.user.* +import com.wespot.user.port.out.ProfilePort +import com.wespot.user.port.out.UserConsentPort +import com.wespot.user.port.out.UserPort +import io.jsonwebtoken.Claims +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.matchers.shouldBe +import io.mockk.* +import org.springframework.security.authentication.AuthenticationManager +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +import org.springframework.security.core.Authentication +import org.springframework.security.crypto.password.PasswordEncoder +import java.time.LocalDateTime + +class AuthServiceTest : BehaviorSpec({ + + val userPort = mockk() + val refreshTokenPort = mockk() + val userConsentPort = mockk() + val profilePort = mockk() + val schoolPort = mockk() + val authDataPort = mockk() + val jwtTokenProvider = mockk() + val socialAuthServiceFactory = mockk() + val authenticationService = mockk() + val authenticationManager = mockk() + val passwordEncoder = mockk() + val refreshTokenService = mockk() + + val secretKey = "testSecretKey" + + val authService = AuthService( + userPort, + refreshTokenPort, + userConsentPort, + profilePort, + schoolPort, + authDataPort, + jwtTokenProvider, + socialAuthServiceFactory, + authenticationService, + authenticationManager, + passwordEncoder, + refreshTokenService, + secretKey + ) + + given("AuthService 테스트") { + // TODO : 나중에 작성해서 PR 올리겠습니다! + + } +}) diff --git a/app/src/test/kotlin/com/wespot/auth/service/AuthenticationServiceTest.kt b/app/src/test/kotlin/com/wespot/auth/service/AuthenticationServiceTest.kt new file mode 100644 index 00000000..32a0b13a --- /dev/null +++ b/app/src/test/kotlin/com/wespot/auth/service/AuthenticationServiceTest.kt @@ -0,0 +1,41 @@ +package com.wespot.auth.service + +import com.wespot.auth.JwtTokenInfo.EMAIL_CLAIM +import com.wespot.auth.PrincipalDetails +import com.wespot.auth.service.jwt.JwtTokenValidator +import com.wespot.user.fixture.UserFixture +import io.jsonwebtoken.Claims +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.matchers.shouldBe +import io.mockk.every +import io.mockk.mockk +import org.springframework.security.core.Authentication + +class AuthenticationServiceTest : BehaviorSpec({ + val principalDetailService = mockk() + val jwtTokenValidator = mockk() + val authenticationService = AuthenticationService(principalDetailService, jwtTokenValidator) + + given("authenticationService 테스트") { + + val user = UserFixture.createWithId(1) + val token = "token" + + val claims = mockk() + val principalDetails = PrincipalDetails(user = user) + + `when`("토큰이 유효할 때") { + + every { claims[EMAIL_CLAIM] } returns user.email + every { jwtTokenValidator.verifyToken(token) } returns claims + every { principalDetailService.loadUserByUsername(user.email) } returns principalDetails + + then("Authentication 객체를 반환해야 한다") { + val authentication: Authentication = authenticationService.getAuthentication(token) + + authentication.name shouldBe principalDetails.username + authentication.credentials shouldBe principalDetails.password + } + } + } +}) diff --git a/app/src/test/kotlin/com/wespot/auth/service/PrincipalDetailServiceTest.kt b/app/src/test/kotlin/com/wespot/auth/service/PrincipalDetailServiceTest.kt new file mode 100644 index 00000000..fb891518 --- /dev/null +++ b/app/src/test/kotlin/com/wespot/auth/service/PrincipalDetailServiceTest.kt @@ -0,0 +1,32 @@ +package com.wespot.auth.service + +import com.wespot.user.fixture.UserFixture +import com.wespot.user.port.out.UserPort +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.matchers.shouldBe +import io.mockk.every +import io.mockk.mockk + +class PrincipalDetailServiceTest: BehaviorSpec({ + val userPort = mockk() + val principalDetailService = PrincipalDetailService(userPort) + + given("principalDetailService 테스트") { + + val user = UserFixture.createWithId(1) + + `when`("유저 아이디로 유저 정보를 가져올 때") { + every { userPort.findByEmail(user.email) } returns user + + val userDetails = principalDetailService.loadUserByUsername(user.email) + + then("userDetails 정보를 감싼 유저 정보를 가져와야 한다") { + + userDetails.username shouldBe user.email + userDetails.password shouldBe user.password + + } + } + } + +}) diff --git a/app/src/test/kotlin/com/wespot/auth/service/RefreshTokenServiceTest.kt b/app/src/test/kotlin/com/wespot/auth/service/RefreshTokenServiceTest.kt new file mode 100644 index 00000000..571c9d3b --- /dev/null +++ b/app/src/test/kotlin/com/wespot/auth/service/RefreshTokenServiceTest.kt @@ -0,0 +1,77 @@ +package com.wespot.auth.service + +import com.wespot.auth.JwtTokenInfo.REFRESH_TOKEN_EXPIRY_DAYS +import com.wespot.auth.RefreshToken +import com.wespot.auth.fixture.RefreshTokenFixture +import com.wespot.auth.port.out.RefreshTokenPort +import com.wespot.user.fixture.UserFixture +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.matchers.shouldBe +import io.mockk.* +import java.time.LocalDateTime + +class RefreshTokenServiceTest : BehaviorSpec({ + val refreshTokenPort = mockk() + val refreshTokenService = RefreshTokenService(refreshTokenPort) + + given("refreshTokenService 테스트") { + + val token = "newRefreshToken" + val user = UserFixture.createWithId(1) + + val existingToken = RefreshToken.create( + refreshToken = "oldToken", + user = user, + createdAt = LocalDateTime.now().minusDays(1), + updatedAt = LocalDateTime.now().minusDays(1), + expiredAt = LocalDateTime.now().minusDays(1) + ) + + val updatedToken = RefreshToken.update( + id = existingToken.id, + refreshToken = token, + user = existingToken.user, + createdAt = existingToken.createdAt ?: LocalDateTime.now(), + updatedAt = LocalDateTime.now(), + expiredAt = LocalDateTime.now().plusDays(REFRESH_TOKEN_EXPIRY_DAYS) + ) + + val existingRefreshToken = RefreshTokenFixture.createWithIdAndRefreshToken(1, existingToken) + val updatedRefreshToken = RefreshTokenFixture.createWithIdAndRefreshToken(1, updatedToken) + + + `when`("기존 리프레시 토큰이 있을 때") { + + every { refreshTokenPort.findByUserId(user.id) } returns existingToken + every { refreshTokenPort.saveOrUpdate(any()) } returns updatedRefreshToken + + then("리프레시 토큰이 업데이트되어야 한다") { + refreshTokenService.saveOrUpdateRefreshToken(token, user) + val saveOrUpdateToken = refreshTokenPort.saveOrUpdate(updatedToken) + + saveOrUpdateToken.refreshToken shouldBe updatedToken.refreshToken + saveOrUpdateToken.expiredAt shouldBe updatedToken.expiredAt + + } + } + + `when`("기존 리프레시 토큰이 없을 때") { + every { refreshTokenPort.findByUserId(user.id) } returns null + every { refreshTokenPort.saveOrUpdate(any()) } returns existingRefreshToken + + then("새로운 리프레시 토큰이 생성되어야 한다") { + refreshTokenService.saveOrUpdateRefreshToken(token, user) + + val newToken = RefreshToken.create( + refreshToken = token, + user = user, + createdAt = LocalDateTime.now(), + updatedAt = LocalDateTime.now(), + expiredAt = LocalDateTime.now().plusDays(REFRESH_TOKEN_EXPIRY_DAYS) + ) + + verify { refreshTokenPort.saveOrUpdate(newToken) } + } + } + } +}) From d71ec8bb528c44ea9cac651b0019700a1447241a Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Wed, 17 Jul 2024 01:21:59 +0900 Subject: [PATCH 25/34] =?UTF-8?q?fix:=20baseEntity=20notnull=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt | 2 +- .../src/main/kotlin/com/wespot/message/MessageJpaEntity.kt | 1 - .../src/main/kotlin/com/wespot/user/entity/UserJpaEntity.kt | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt index 5829f93e..b00cc1e0 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/common/BaseEntity.kt @@ -19,7 +19,7 @@ class BaseEntity( val createdAt: LocalDateTime = LocalDateTime.now(), @LastModifiedDate - @field:Column(nullable = false) + @field:Column(nullable = true) val updatedAt: LocalDateTime? = null ) diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/message/MessageJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/message/MessageJpaEntity.kt index 989be974..8c08e3fe 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/message/MessageJpaEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/message/MessageJpaEntity.kt @@ -34,7 +34,6 @@ class MessageJpaEntity( val receivedAt: LocalDateTime, @Embedded - @field: NotNull val baseEntity: BaseEntity ) diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserJpaEntity.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserJpaEntity.kt index 903934ec..aa94d36c 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserJpaEntity.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/entity/UserJpaEntity.kt @@ -62,10 +62,8 @@ class UserJpaEntity( val withdrawAt: LocalDateTime?, @Embedded - @field: NotNull val baseEntity: BaseEntity, - ) { } From 1de8e82a0e09a0f979c816eb21ff4280d917a288 Mon Sep 17 00:00:00 2001 From: sectionr0 Date: Wed, 17 Jul 2024 01:22:21 +0900 Subject: [PATCH 26/34] =?UTF-8?q?fix:=20VoteServiceTest=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EC=A3=BC=EC=84=9D=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/test/kotlin/com/wespot/vote/service/VoteServiceTest.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/test/kotlin/com/wespot/vote/service/VoteServiceTest.kt b/app/src/test/kotlin/com/wespot/vote/service/VoteServiceTest.kt index b769f1ef..cb9b5401 100644 --- a/app/src/test/kotlin/com/wespot/vote/service/VoteServiceTest.kt +++ b/app/src/test/kotlin/com/wespot/vote/service/VoteServiceTest.kt @@ -1,3 +1,4 @@ +/* package com.wespot.vote.service import com.wespot.DatabaseCleanup @@ -206,3 +207,4 @@ class VoteServiceTest( } } +*/ From c4b40008393045fb557551a2f2397dec8481dbec Mon Sep 17 00:00:00 2001 From: jaeyeon kim Date: Wed, 17 Jul 2024 09:32:14 +0900 Subject: [PATCH 27/34] =?UTF-8?q?test:=20=EC=A3=BC=EC=84=9D=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/test/kotlin/com/wespot/vote/service/VoteServiceTest.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/test/kotlin/com/wespot/vote/service/VoteServiceTest.kt b/app/src/test/kotlin/com/wespot/vote/service/VoteServiceTest.kt index cb9b5401..b769f1ef 100644 --- a/app/src/test/kotlin/com/wespot/vote/service/VoteServiceTest.kt +++ b/app/src/test/kotlin/com/wespot/vote/service/VoteServiceTest.kt @@ -1,4 +1,3 @@ -/* package com.wespot.vote.service import com.wespot.DatabaseCleanup @@ -207,4 +206,3 @@ class VoteServiceTest( } } -*/ From 810f5af379217cd89f34120cafb882fb82d0785f Mon Sep 17 00:00:00 2001 From: jaeyeon kim Date: Wed, 17 Jul 2024 09:33:52 +0900 Subject: [PATCH 28/34] =?UTF-8?q?chore:=20=EC=84=9C=EB=B8=8C=EB=AA=A8?= =?UTF-8?q?=EB=93=88=EC=97=90=20jwt=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/resources/backend-submodule | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/resources/backend-submodule b/app/src/main/resources/backend-submodule index 11770a88..d39451b3 160000 --- a/app/src/main/resources/backend-submodule +++ b/app/src/main/resources/backend-submodule @@ -1 +1 @@ -Subproject commit 11770a88c4facc7e5049cf475047b312a4238963 +Subproject commit d39451b3589a50cabd1109b4175f90c0d218dad1 From 2acf2bd63bd03c2e69728e542629765561c5205b Mon Sep 17 00:00:00 2001 From: jaeyeon kim Date: Wed, 17 Jul 2024 09:42:24 +0900 Subject: [PATCH 29/34] =?UTF-8?q?refactor:=20gitmodules=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EC=9D=B4=ED=9B=84,=20=EC=9D=B4=EC=A0=84=20backend-?= =?UTF-8?q?submodule=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitmodules | 6 +++--- app/src/main/resources/backend-submodule | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) delete mode 160000 app/src/main/resources/backend-submodule diff --git a/.gitmodules b/.gitmodules index 7f216700..ce8c0ab3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "app/src/main/resources/backend-submodule"] - path = app/src/main/resources/backend-submodule - url = https://github.com/yapp-wespot/backend-submodule.git +[submodule "app/src/main/resources/config"] + path = app/src/main/resources/config + url = https://github.com/yapp-wespot/config.git diff --git a/app/src/main/resources/backend-submodule b/app/src/main/resources/backend-submodule deleted file mode 160000 index d39451b3..00000000 --- a/app/src/main/resources/backend-submodule +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d39451b3589a50cabd1109b4175f90c0d218dad1 From aa52eacdd3b8ab8f23c6565004dcaeaa0303e8d3 Mon Sep 17 00:00:00 2001 From: jaeyeon kim Date: Wed, 17 Jul 2024 09:42:35 +0900 Subject: [PATCH 30/34] =?UTF-8?q?refactor:=20submoudle=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20config=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/resources/config | 1 + 1 file changed, 1 insertion(+) create mode 160000 app/src/main/resources/config diff --git a/app/src/main/resources/config b/app/src/main/resources/config new file mode 160000 index 00000000..d39451b3 --- /dev/null +++ b/app/src/main/resources/config @@ -0,0 +1 @@ +Subproject commit d39451b3589a50cabd1109b4175f90c0d218dad1 From 6d73beee45573971a5169654cb8aa9124c631520 Mon Sep 17 00:00:00 2001 From: jaeyeon kim Date: Wed, 17 Jul 2024 10:06:47 +0900 Subject: [PATCH 31/34] =?UTF-8?q?refactor:=20LocalDateTime.now()=20?= =?UTF-8?q?=EB=AA=A8=ED=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/wespot/auth/service/RefreshTokenServiceTest.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/test/kotlin/com/wespot/auth/service/RefreshTokenServiceTest.kt b/app/src/test/kotlin/com/wespot/auth/service/RefreshTokenServiceTest.kt index 571c9d3b..509c6410 100644 --- a/app/src/test/kotlin/com/wespot/auth/service/RefreshTokenServiceTest.kt +++ b/app/src/test/kotlin/com/wespot/auth/service/RefreshTokenServiceTest.kt @@ -7,7 +7,10 @@ import com.wespot.auth.port.out.RefreshTokenPort import com.wespot.user.fixture.UserFixture import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.shouldBe -import io.mockk.* +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.verify import java.time.LocalDateTime class RefreshTokenServiceTest : BehaviorSpec({ @@ -15,10 +18,13 @@ class RefreshTokenServiceTest : BehaviorSpec({ val refreshTokenService = RefreshTokenService(refreshTokenPort) given("refreshTokenService 테스트") { - val token = "newRefreshToken" val user = UserFixture.createWithId(1) + val now = LocalDateTime.now() + mockkStatic(LocalDateTime::class) + every { LocalDateTime.now() } returns now + val existingToken = RefreshToken.create( refreshToken = "oldToken", user = user, From 991d491e0e56b53f98939e2d849872a7b571e152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EA=B8=B0=EC=B2=9C?= Date: Wed, 17 Jul 2024 12:52:35 +0900 Subject: [PATCH 32/34] =?UTF-8?q?refactor:=20=20401=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95,=20cors=20=EC=A3=BC=EC=86=8C,=20delete=EC=97=90=20?= =?UTF-8?q?=ED=8A=B8=EB=9E=9C=EC=9E=AD=EC=85=98=20=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/wespot/config/security/JwtAuthenticationEntryPoint.kt | 2 +- .../main/kotlin/com/wespot/config/security/SecurityConfig.kt | 2 -- .../kotlin/com/wespot/auth/RefreshTokenPersistenceAdapter.kt | 1 + 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/com/wespot/config/security/JwtAuthenticationEntryPoint.kt b/app/src/main/kotlin/com/wespot/config/security/JwtAuthenticationEntryPoint.kt index 33ecf581..23517faf 100644 --- a/app/src/main/kotlin/com/wespot/config/security/JwtAuthenticationEntryPoint.kt +++ b/app/src/main/kotlin/com/wespot/config/security/JwtAuthenticationEntryPoint.kt @@ -30,7 +30,7 @@ class JwtAuthenticationEntryPoint( val body = objectMapper.writeValueAsString( ProblemDetail.forStatusAndDetail( HttpStatus.UNAUTHORIZED, - BadCredentialsException("").message!!, + BadCredentialsException("로그인이 만료되었습니다. 계속하려면 다시 로그인해 주세요.").message!!, ).apply { type = URI.create("/errors/unauthenticated") instance = URI.create(request.requestURI) diff --git a/app/src/main/kotlin/com/wespot/config/security/SecurityConfig.kt b/app/src/main/kotlin/com/wespot/config/security/SecurityConfig.kt index e7db38f7..da1ed942 100644 --- a/app/src/main/kotlin/com/wespot/config/security/SecurityConfig.kt +++ b/app/src/main/kotlin/com/wespot/config/security/SecurityConfig.kt @@ -81,8 +81,6 @@ class SecurityConfig( val configuration = CorsConfiguration().apply { allowCredentials = true allowedOrigins = listOf( - "https://api.lyfeteam.info", - "http://localhost:3000", "http://localhost:8080", ) allowedMethods = listOf( diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenPersistenceAdapter.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenPersistenceAdapter.kt index 6aef30b7..4f6b66a9 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenPersistenceAdapter.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/auth/RefreshTokenPersistenceAdapter.kt @@ -34,6 +34,7 @@ class RefreshTokenPersistenceAdapter( } } + @Transactional override fun deleteByUserId(userId: Long) { refreshTokenJpaRepository.deleteByUserId(userId) } From 652bf3fc9d7e7af3550462d0120b6e889f57df27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EA=B8=B0=EC=B2=9C?= Date: Wed, 17 Jul 2024 15:01:44 +0900 Subject: [PATCH 33/34] =?UTF-8?q?refactor:=20api=20prefix=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/kotlin/com/wespot/auth/AuthController.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/wespot/auth/AuthController.kt b/app/src/main/kotlin/com/wespot/auth/AuthController.kt index 32db0433..56d6793e 100644 --- a/app/src/main/kotlin/com/wespot/auth/AuthController.kt +++ b/app/src/main/kotlin/com/wespot/auth/AuthController.kt @@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController @RestController -@RequestMapping("/api/v1/auth") +@RequestMapping("/v1/auth") class AuthController( private val authService: AuthService ) { From 8f9dc12ed2e5a6cc58e86e8ec6fe6d2e047b3784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EA=B8=B0=EC=B2=9C?= Date: Wed, 17 Jul 2024 18:03:02 +0900 Subject: [PATCH 34/34] =?UTF-8?q?refactor:=20refreshToken=20test=EC=97=90?= =?UTF-8?q?=20=EC=9E=88=EB=8A=94=20createdAt=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/wespot/auth/service/RefreshTokenServiceTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/test/kotlin/com/wespot/auth/service/RefreshTokenServiceTest.kt b/app/src/test/kotlin/com/wespot/auth/service/RefreshTokenServiceTest.kt index 509c6410..e3ce63bd 100644 --- a/app/src/test/kotlin/com/wespot/auth/service/RefreshTokenServiceTest.kt +++ b/app/src/test/kotlin/com/wespot/auth/service/RefreshTokenServiceTest.kt @@ -37,7 +37,7 @@ class RefreshTokenServiceTest : BehaviorSpec({ id = existingToken.id, refreshToken = token, user = existingToken.user, - createdAt = existingToken.createdAt ?: LocalDateTime.now(), + createdAt = existingToken.createdAt, updatedAt = LocalDateTime.now(), expiredAt = LocalDateTime.now().plusDays(REFRESH_TOKEN_EXPIRY_DAYS) )