diff --git a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/core/external/yandex/YandexUser.kt b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/core/external/yandex/YandexUser.kt index 94114ce..56a6849 100644 --- a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/core/external/yandex/YandexUser.kt +++ b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/core/external/yandex/YandexUser.kt @@ -5,8 +5,12 @@ data class YandexUser( val login: Login, ) { @JvmInline - value class Id(val number: Int) + value class Id(val number: Int) { + override fun toString(): String = number.toString() + } @JvmInline - value class Login(val text: String) + value class Login(val text: String) { + override fun toString(): String = text + } } diff --git a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/storage/jooq/JooqYandexAuthStorage.kt b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/storage/jooq/JooqYandexAuthStorage.kt index 365fc2a..f3735e4 100644 --- a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/storage/jooq/JooqYandexAuthStorage.kt +++ b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/storage/jooq/JooqYandexAuthStorage.kt @@ -1,14 +1,16 @@ package ru.vityaman.lms.botalka.storage.jooq +import ru.vityaman.lms.botalka.core.exception.InvalidValueException import ru.vityaman.lms.botalka.core.external.yandex.YandexUser import ru.vityaman.lms.botalka.core.model.User import ru.vityaman.lms.botalka.core.storage.YandexAuthStorage +import ru.vityaman.lms.botalka.storage.jooq.exception.UniqueViolationException import ru.vityaman.lms.botalka.storage.jooq.tables.references.AUTH_YANDEX class JooqYandexAuthStorage( private val database: JooqDatabase, ) : YandexAuthStorage { - override suspend fun create(userId: User.Id, yandexUser: YandexUser) = + override suspend fun create(userId: User.Id, yandexUser: YandexUser) = try { database.only { insertInto( AUTH_YANDEX, @@ -21,6 +23,15 @@ class JooqYandexAuthStorage( yandexUser.login.text, ) }.let { } + } catch (e: UniqueViolationException) { + throw InvalidValueException( + buildString { + append("yandex user '${yandexUser.login}' ") + append("(id '${yandexUser.id}') already connected") + }, + e, + ) + } override suspend fun corresponding(id: YandexUser.Id): User.Id? = database.maybe { diff --git a/botalka/src/test/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/endpoint/AuthApiTest.kt b/botalka/src/test/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/endpoint/AuthApiTest.kt index 4c38040..2a25c8a 100644 --- a/botalka/src/test/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/endpoint/AuthApiTest.kt +++ b/botalka/src/test/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/endpoint/AuthApiTest.kt @@ -3,6 +3,8 @@ package ru.vityaman.lms.botalka.app.spring.api.http.endpoint import kotlinx.coroutines.reactor.awaitSingle import kotlinx.coroutines.runBlocking import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.springframework.web.reactive.function.client.WebClientResponseException import ru.vityaman.lms.botalka.app.spring.BotalkaTestSuite import ru.vityaman.lms.botalka.app.spring.api.http.client.Api import ru.vityaman.lms.botalka.app.spring.api.http.client.Auth2ViaCodeMessage @@ -32,4 +34,31 @@ class AuthApiTest : BotalkaTestSuite() { ), ).awaitSingle() } + + @Test + fun duplicateRegistration(): Unit = runBlocking { + val api = Api.ofNewbie() + + api.user.postUser( + PostUserRequestMessage( + user = UserDraftMessage("vanya"), + credential = Auth2ViaCodeMessage( + kind = CredentialKindMessage.yandex_code, + code = 654_321, + ), + ), + ).awaitSingle() + + assertThrows { + api.user.postUser( + PostUserRequestMessage( + user = UserDraftMessage("vitya"), + credential = Auth2ViaCodeMessage( + kind = CredentialKindMessage.yandex_code, + code = 654_321, + ), + ), + ).awaitSingle() + } + } }