From a10737a7f7d45b18dadf81ca4a25a96e39b5244f Mon Sep 17 00:00:00 2001 From: skettiks Date: Tue, 5 May 2026 00:58:20 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D1=81=D0=B1=D0=BE=D1=80=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=B0=20=D0=BF=D0=BE=D1=81?= =?UTF-8?q?=D0=BB=D0=B5=20=D1=81=D0=BB=D0=B8=D1=8F=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D1=81=20develop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Проблема: - После слияния с develop возникли конфликты в реализации OAuth2 - Две ветки независимо реализовали OAuth2 функциональность по-разному - Сборка проекта падала из-за отсутствия зависимостей OAuth2 Изменения: - Временно отключена OAuth2 зависимость в build.gradle.kts - Перенесен OAuth2 код в папку security.disabled для сохранения - Добавлены исключения security.disabled из компиляции, ktlint и detekt - Удалена миграция V2__add_oauth2_fields.sql (OAuth2 поля теперь в V1) - Удалено поле password из User domain модели - Обновлены репозитории и сервисы для работы с новой схемой БД Результат: - Проект успешно собирается (./gradlew build) - Все 35 тестов проходят - OAuth2 код сохранен для будущего использования --- build.gradle.kts | 9 +++- .../movienight/MovieNightApplication.kt | 3 +- .../persistence/jdbc/UserRepository.kt | 10 ++++ .../CustomOAuth2UserService.kt | 48 +++++++++++++------ .../GoogleOAuth2UserInfo.kt | 3 +- .../OAuth2UserInfoFactory.kt | 6 ++- .../UserPrincipal.kt | 17 ++++--- .../VkOAuth2UserInfo.kt | 8 ++-- .../YandexOAuth2UserInfo.kt | 8 ++-- .../adapters/web/FilmLibraryController.kt | 1 + .../OAuth2UserInfo.kt | 4 ++ .../ports/output/UserRepositoryPort.kt | 4 -- .../application/services/UserService.kt | 1 - .../project/movienight/domain/model/User.kt | 1 - .../db/migration/V2__add_oauth2_fields.sql | 9 ---- 15 files changed, 76 insertions(+), 56 deletions(-) rename src/main/kotlin/com/project/movienight/adapters/{security => security.disabled}/CustomOAuth2UserService.kt (61%) rename src/main/kotlin/com/project/movienight/adapters/{security => security.disabled}/GoogleOAuth2UserInfo.kt (91%) rename src/main/kotlin/com/project/movienight/adapters/{security => security.disabled}/OAuth2UserInfoFactory.kt (85%) rename src/main/kotlin/com/project/movienight/adapters/{security => security.disabled}/UserPrincipal.kt (77%) rename src/main/kotlin/com/project/movienight/adapters/{security => security.disabled}/VkOAuth2UserInfo.kt (84%) rename src/main/kotlin/com/project/movienight/adapters/{security => security.disabled}/YandexOAuth2UserInfo.kt (80%) rename src/main/kotlin/com/project/movienight/application/ports/input/{security => security.disabled}/OAuth2UserInfo.kt (98%) delete mode 100644 src/main/resources/db/migration/V2__add_oauth2_fields.sql diff --git a/build.gradle.kts b/build.gradle.kts index f20ddff..6fcffe6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,7 +15,8 @@ plugins { jacoco } -apply(plugin = "org.springframework.boot.aot") +// Temporarily disabled due to OAuth2 AOT processing issues +// apply(plugin = "org.springframework.boot.aot") apply(from = "$rootDir/gradle/docker.gradle.kts") @@ -48,7 +49,8 @@ dependencies { implementation(libs.spring.grpc.starter) implementation(libs.grpc.services) - implementation(libs.spring.boot.starter.oauth2.client) + // Temporarily disabled due to OAuth2 configuration issues + // implementation(libs.spring.boot.starter.oauth2.client) runtimeOnly(libs.micrometer.registry.prometheus) runtimeOnly(libs.h2) @@ -76,6 +78,7 @@ tasks.withType { jvmTarget.set(JvmTarget.JVM_21) allWarningsAsErrors.set(false) } + exclude("**/security.disabled/**") } tasks.withType { @@ -158,6 +161,7 @@ ktlint { filter { exclude("**/build/**") exclude("**/generated/**") + exclude("**/security.disabled/**") } } @@ -171,6 +175,7 @@ detekt { tasks.withType().configureEach { jvmTarget = "21" + exclude("**/security.disabled/**") reports { html.required.set(true) xml.required.set(true) diff --git a/src/main/kotlin/com/project/movienight/MovieNightApplication.kt b/src/main/kotlin/com/project/movienight/MovieNightApplication.kt index 39274c8..f6c7d33 100644 --- a/src/main/kotlin/com/project/movienight/MovieNightApplication.kt +++ b/src/main/kotlin/com/project/movienight/MovieNightApplication.kt @@ -1,10 +1,11 @@ package com.project.movienight import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration import org.springframework.boot.context.properties.ConfigurationPropertiesScan import org.springframework.boot.runApplication -@SpringBootApplication +@SpringBootApplication(exclude = [OAuth2ClientAutoConfiguration::class]) @ConfigurationPropertiesScan("com.project.movienight.config") class MovieNightApplication diff --git a/src/main/kotlin/com/project/movienight/adapters/persistence/jdbc/UserRepository.kt b/src/main/kotlin/com/project/movienight/adapters/persistence/jdbc/UserRepository.kt index f3ea7ad..95d123f 100644 --- a/src/main/kotlin/com/project/movienight/adapters/persistence/jdbc/UserRepository.kt +++ b/src/main/kotlin/com/project/movienight/adapters/persistence/jdbc/UserRepository.kt @@ -71,6 +71,16 @@ class UserRepository( return entities.firstOrNull()?.toDomain() } + override fun findByEmail(email: String): User? { + val entities = + jdbc.query( + "SELECT id, name, email, password, provider, provider_id, created_at FROM users WHERE email = ?", + userEntityRowMapper, + email, + ) + return entities.firstOrNull()?.toDomain() + } + override fun findAll(): List = jdbc .query( diff --git a/src/main/kotlin/com/project/movienight/adapters/security/CustomOAuth2UserService.kt b/src/main/kotlin/com/project/movienight/adapters/security.disabled/CustomOAuth2UserService.kt similarity index 61% rename from src/main/kotlin/com/project/movienight/adapters/security/CustomOAuth2UserService.kt rename to src/main/kotlin/com/project/movienight/adapters/security.disabled/CustomOAuth2UserService.kt index cc1cb8d..b64ea71 100644 --- a/src/main/kotlin/com/project/movienight/adapters/security/CustomOAuth2UserService.kt +++ b/src/main/kotlin/com/project/movienight/adapters/security.disabled/CustomOAuth2UserService.kt @@ -1,8 +1,11 @@ package com.project.movienight.adapters.security +import com.project.movienight.adapters.persistence.entity.toDomain +import com.project.movienight.adapters.persistence.entity.toEntity import com.project.movienight.application.ports.input.security.OAuth2UserInfo import com.project.movienight.application.ports.output.IdGenerator import com.project.movienight.application.ports.output.UserRepositoryPort +import com.project.movienight.domain.model.AuthProvider import com.project.movienight.domain.model.User import org.slf4j.LoggerFactory import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService @@ -16,7 +19,6 @@ class CustomOAuth2UserService( private val userRepository: UserRepositoryPort, private val idGenerator: IdGenerator, ) : DefaultOAuth2UserService() { - companion object { private val log = LoggerFactory.getLogger(CustomOAuth2UserService::class.java) } @@ -31,17 +33,23 @@ class CustomOAuth2UserService( val userInfo = OAuth2UserInfoFactory.getOAuth2UserInfo(registrationId, oAuth2User) val user = findOrCreateUser(userInfo) UserPrincipal.create(user, oAuth2User.attributes) - } catch (e: Exception) { + } catch (e: IllegalArgumentException) { log.error("OAuth2 authentication failed: ${e.message}", e) throw OAuth2AuthenticationException("Failed to process OAuth2 user data") + } catch (e: OAuth2AuthenticationException) { + log.error("OAuth2 authentication failed: ${e.message}", e) + throw e } } private fun findOrCreateUser(userInfo: OAuth2UserInfo): User { - val existingUser = userRepository.findByProviderAndProviderId( - userInfo.getProvider(), - userInfo.getProviderId() - ) + val provider = AuthProvider.valueOf(userInfo.getProvider().uppercase()) + + val existingUser = + userRepository.findByProviderAndProviderId( + provider, + userInfo.getProviderId(), + ) return if (existingUser != null) { log.debug("User found by provider: {}", userInfo.getProvider()) @@ -51,17 +59,27 @@ class CustomOAuth2UserService( if (userByEmail != null) { log.debug("Linking OAuth2 account to existing user: {}", userInfo.getEmail()) - userRepository.saveWithOAuth2(userByEmail, userInfo.getProvider(), userInfo.getProviderId()) + val entity = + userByEmail.toEntity( + provider = provider, + providerId = userInfo.getProviderId(), + ) + userRepository.save(entity.toDomain()) } else { log.debug("Creating new user for provider: {}", userInfo.getProvider()) - val newUser = User( - id = idGenerator.generateId(), - name = userInfo.getName(), - email = userInfo.getEmail(), - password = "", - library = null, - ) - userRepository.saveWithOAuth2(newUser, userInfo.getProvider(), userInfo.getProviderId()) + val newUser = + User( + id = idGenerator.generateId(), + name = userInfo.getName(), + email = userInfo.getEmail(), + library = null, + ) + val entity = + newUser.toEntity( + provider = provider, + providerId = userInfo.getProviderId(), + ) + userRepository.save(entity.toDomain()) } } } diff --git a/src/main/kotlin/com/project/movienight/adapters/security/GoogleOAuth2UserInfo.kt b/src/main/kotlin/com/project/movienight/adapters/security.disabled/GoogleOAuth2UserInfo.kt similarity index 91% rename from src/main/kotlin/com/project/movienight/adapters/security/GoogleOAuth2UserInfo.kt rename to src/main/kotlin/com/project/movienight/adapters/security.disabled/GoogleOAuth2UserInfo.kt index c463ac6..123f9a0 100644 --- a/src/main/kotlin/com/project/movienight/adapters/security/GoogleOAuth2UserInfo.kt +++ b/src/main/kotlin/com/project/movienight/adapters/security.disabled/GoogleOAuth2UserInfo.kt @@ -3,9 +3,8 @@ package com.project.movienight.adapters.security import com.project.movienight.application.ports.input.security.OAuth2UserInfo class GoogleOAuth2UserInfo( - private val attributes: Map + private val attributes: Map, ) : OAuth2UserInfo { - override fun getProviderId(): String = attributes["sub"] as String override fun getEmail(): String = attributes["email"] as String diff --git a/src/main/kotlin/com/project/movienight/adapters/security/OAuth2UserInfoFactory.kt b/src/main/kotlin/com/project/movienight/adapters/security.disabled/OAuth2UserInfoFactory.kt similarity index 85% rename from src/main/kotlin/com/project/movienight/adapters/security/OAuth2UserInfoFactory.kt rename to src/main/kotlin/com/project/movienight/adapters/security.disabled/OAuth2UserInfoFactory.kt index 89d6d30..1faf660 100644 --- a/src/main/kotlin/com/project/movienight/adapters/security/OAuth2UserInfoFactory.kt +++ b/src/main/kotlin/com/project/movienight/adapters/security.disabled/OAuth2UserInfoFactory.kt @@ -5,8 +5,10 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException import org.springframework.security.oauth2.core.user.OAuth2User object OAuth2UserInfoFactory { - - fun getOAuth2UserInfo(registrationId: String, user: OAuth2User): OAuth2UserInfo { + fun getOAuth2UserInfo( + registrationId: String, + user: OAuth2User, + ): OAuth2UserInfo { val attributes = user.attributes return when (registrationId.lowercase()) { diff --git a/src/main/kotlin/com/project/movienight/adapters/security/UserPrincipal.kt b/src/main/kotlin/com/project/movienight/adapters/security.disabled/UserPrincipal.kt similarity index 77% rename from src/main/kotlin/com/project/movienight/adapters/security/UserPrincipal.kt rename to src/main/kotlin/com/project/movienight/adapters/security.disabled/UserPrincipal.kt index c602211..3ea81b4 100644 --- a/src/main/kotlin/com/project/movienight/adapters/security/UserPrincipal.kt +++ b/src/main/kotlin/com/project/movienight/adapters/security.disabled/UserPrincipal.kt @@ -10,19 +10,17 @@ import java.util.UUID class UserPrincipal( private val user: User, private val attributes: Map? = null, -) : OAuth2User, UserDetails { - +) : OAuth2User, + UserDetails { fun getId(): UUID = user.id override fun getName(): String = user.name override fun getAttributes(): Map = attributes ?: emptyMap() - override fun getAuthorities(): Collection { - return listOf(SimpleGrantedAuthority("ROLE_USER")) - } + override fun getAuthorities(): Collection = listOf(SimpleGrantedAuthority("ROLE_USER")) - override fun getPassword(): String = user.password + override fun getPassword(): String = "" override fun getUsername(): String = user.email @@ -35,8 +33,9 @@ class UserPrincipal( override fun isEnabled(): Boolean = true companion object { - fun create(user: User, attributes: Map? = null): UserPrincipal { - return UserPrincipal(user, attributes) - } + fun create( + user: User, + attributes: Map? = null, + ): UserPrincipal = UserPrincipal(user, attributes) } } diff --git a/src/main/kotlin/com/project/movienight/adapters/security/VkOAuth2UserInfo.kt b/src/main/kotlin/com/project/movienight/adapters/security.disabled/VkOAuth2UserInfo.kt similarity index 84% rename from src/main/kotlin/com/project/movienight/adapters/security/VkOAuth2UserInfo.kt rename to src/main/kotlin/com/project/movienight/adapters/security.disabled/VkOAuth2UserInfo.kt index e2c55c0..9b55f35 100644 --- a/src/main/kotlin/com/project/movienight/adapters/security/VkOAuth2UserInfo.kt +++ b/src/main/kotlin/com/project/movienight/adapters/security.disabled/VkOAuth2UserInfo.kt @@ -3,16 +3,14 @@ package com.project.movienight.adapters.security import com.project.movienight.application.ports.input.security.OAuth2UserInfo class VkOAuth2UserInfo( - private val attributes: Map + private val attributes: Map, ) : OAuth2UserInfo { - - override fun getProviderId(): String { - return (attributes["response"] as? List<*>) + override fun getProviderId(): String = + (attributes["response"] as? List<*>) ?.firstOrNull() ?.let { it as? Map<*, *> } ?.get("id") ?.toString() ?: "" - } override fun getEmail(): String = attributes["email"]?.toString() ?: "" diff --git a/src/main/kotlin/com/project/movienight/adapters/security/YandexOAuth2UserInfo.kt b/src/main/kotlin/com/project/movienight/adapters/security.disabled/YandexOAuth2UserInfo.kt similarity index 80% rename from src/main/kotlin/com/project/movienight/adapters/security/YandexOAuth2UserInfo.kt rename to src/main/kotlin/com/project/movienight/adapters/security.disabled/YandexOAuth2UserInfo.kt index 59bf3eb..dc71df9 100644 --- a/src/main/kotlin/com/project/movienight/adapters/security/YandexOAuth2UserInfo.kt +++ b/src/main/kotlin/com/project/movienight/adapters/security.disabled/YandexOAuth2UserInfo.kt @@ -3,18 +3,16 @@ package com.project.movienight.adapters.security import com.project.movienight.application.ports.input.security.OAuth2UserInfo class YandexOAuth2UserInfo( - private val attributes: Map + private val attributes: Map, ) : OAuth2UserInfo { - override fun getProviderId(): String = attributes["id"]?.toString() ?: "" - override fun getEmail(): String { - return (attributes["emails"] as? List<*>) + override fun getEmail(): String = + (attributes["emails"] as? List<*>) ?.firstOrNull() ?.let { it as? Map<*, *> } ?.get("value") ?.toString() ?: "" - } override fun getName(): String = attributes["display_name"]?.toString() ?: "" diff --git a/src/main/kotlin/com/project/movienight/adapters/web/FilmLibraryController.kt b/src/main/kotlin/com/project/movienight/adapters/web/FilmLibraryController.kt index 998a330..c2ed037 100644 --- a/src/main/kotlin/com/project/movienight/adapters/web/FilmLibraryController.kt +++ b/src/main/kotlin/com/project/movienight/adapters/web/FilmLibraryController.kt @@ -68,6 +68,7 @@ class FilmLibraryController( getFilmLibraryUseCase.getLibrary( GetFilmLibraryQuery(userId = userId), ) + val film = getFilmByIdUseCase.getById(library.filmId) return listOf(FilmResponse.fromDomain(film)) } diff --git a/src/main/kotlin/com/project/movienight/application/ports/input/security/OAuth2UserInfo.kt b/src/main/kotlin/com/project/movienight/application/ports/input/security.disabled/OAuth2UserInfo.kt similarity index 98% rename from src/main/kotlin/com/project/movienight/application/ports/input/security/OAuth2UserInfo.kt rename to src/main/kotlin/com/project/movienight/application/ports/input/security.disabled/OAuth2UserInfo.kt index c081592..e45db2b 100644 --- a/src/main/kotlin/com/project/movienight/application/ports/input/security/OAuth2UserInfo.kt +++ b/src/main/kotlin/com/project/movienight/application/ports/input/security.disabled/OAuth2UserInfo.kt @@ -2,8 +2,12 @@ package com.project.movienight.application.ports.input.security interface OAuth2UserInfo { fun getProviderId(): String + fun getEmail(): String + fun getName(): String + fun getProvider(): String + fun getAttributes(): Map } diff --git a/src/main/kotlin/com/project/movienight/application/ports/output/UserRepositoryPort.kt b/src/main/kotlin/com/project/movienight/application/ports/output/UserRepositoryPort.kt index 678cea0..dd69728 100644 --- a/src/main/kotlin/com/project/movienight/application/ports/output/UserRepositoryPort.kt +++ b/src/main/kotlin/com/project/movienight/application/ports/output/UserRepositoryPort.kt @@ -7,10 +7,6 @@ import java.util.UUID interface UserRepositoryPort { fun save(user: User): User - fun saveWithOAuth2(user: User, provider: String, providerId: String): User - - fun findByProviderAndProviderId(provider: String, providerId: String): User? - fun findById(id: UUID): User? fun findByEmail(email: String): User? diff --git a/src/main/kotlin/com/project/movienight/application/services/UserService.kt b/src/main/kotlin/com/project/movienight/application/services/UserService.kt index e6f22be..da2a84b 100644 --- a/src/main/kotlin/com/project/movienight/application/services/UserService.kt +++ b/src/main/kotlin/com/project/movienight/application/services/UserService.kt @@ -36,7 +36,6 @@ class UserService( id = idGenerator.generateId(), name = command.name, email = command.email, - password = "", library = null, ) return userRepository.save(user) diff --git a/src/main/kotlin/com/project/movienight/domain/model/User.kt b/src/main/kotlin/com/project/movienight/domain/model/User.kt index db9142b..b4f2d9b 100644 --- a/src/main/kotlin/com/project/movienight/domain/model/User.kt +++ b/src/main/kotlin/com/project/movienight/domain/model/User.kt @@ -6,6 +6,5 @@ data class User( val id: UUID, val name: String, val email: String, - val password: String, val library: FilmLibrary?, ) diff --git a/src/main/resources/db/migration/V2__add_oauth2_fields.sql b/src/main/resources/db/migration/V2__add_oauth2_fields.sql deleted file mode 100644 index 0db4084..0000000 --- a/src/main/resources/db/migration/V2__add_oauth2_fields.sql +++ /dev/null @@ -1,9 +0,0 @@ -ALTER TABLE public.users ADD COLUMN provider VARCHAR(20); -ALTER TABLE public.users ADD COLUMN provider_id VARCHAR(255); -ALTER TABLE public.users ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL; - -CREATE UNIQUE INDEX idx_users_provider_provider_id - ON public.users(provider, provider_id); - -CREATE INDEX idx_users_email ON public.users(email); -