81 lines
3.0 KiB
Kotlin
81 lines
3.0 KiB
Kotlin
package be.simplenotes.domain
|
|
|
|
import arrow.core.Either
|
|
import arrow.core.raise.either
|
|
import arrow.core.raise.ensure
|
|
import arrow.core.raise.ensureNotNull
|
|
import be.simplenotes.domain.security.PasswordHash
|
|
import be.simplenotes.domain.security.SimpleJwt
|
|
import be.simplenotes.domain.validation.UserValidations
|
|
import be.simplenotes.persistence.repositories.UserRepository
|
|
import be.simplenotes.search.NoteSearcher
|
|
import be.simplenotes.types.LoggedInUser
|
|
import be.simplenotes.types.PersistedUser
|
|
import io.konform.validation.ValidationErrors
|
|
import jakarta.inject.Singleton
|
|
import kotlinx.serialization.Serializable
|
|
|
|
interface UserService {
|
|
fun register(form: RegisterForm): Either<RegisterError, PersistedUser>
|
|
fun login(form: LoginForm): Either<LoginError, Token>
|
|
fun delete(form: DeleteForm): Either<DeleteError, Unit>
|
|
}
|
|
|
|
@Singleton
|
|
internal class UserServiceImpl(
|
|
private val userRepository: UserRepository,
|
|
private val passwordHash: PasswordHash,
|
|
private val jwt: SimpleJwt<LoggedInUser>,
|
|
private val searcher: NoteSearcher,
|
|
) : UserService {
|
|
|
|
override fun register(form: RegisterForm) = either {
|
|
val user = UserValidations.validateRegister(form).bind()
|
|
ensure(!userRepository.exists(user.username)) { RegisterError.UserExists }
|
|
ensureNotNull(userRepository.create(user.copy(password = passwordHash.crypt(user.password)))) {
|
|
RegisterError.UserExists
|
|
}
|
|
}
|
|
|
|
override fun login(form: LoginForm) = either {
|
|
val user = UserValidations.validateLogin(form).bind()
|
|
val persistedUser = ensureNotNull(userRepository.find(user.username)) { LoginError.Unregistered }
|
|
ensure(passwordHash.verify(form.password!!, persistedUser.password)) { LoginError.WrongPassword }
|
|
jwt.sign(LoggedInUser(persistedUser))
|
|
}
|
|
|
|
override fun delete(form: DeleteForm) = either {
|
|
val user = UserValidations.validateDelete(form).bind()
|
|
val persistedUser = ensureNotNull(userRepository.find(user.username)) { DeleteError.Unregistered }
|
|
ensure(passwordHash.verify(user.password, persistedUser.password)) { DeleteError.WrongPassword }
|
|
ensure(userRepository.delete(persistedUser.id)) { DeleteError.Unregistered }
|
|
searcher.dropIndex(persistedUser.id)
|
|
}
|
|
}
|
|
|
|
sealed class DeleteError {
|
|
object Unregistered : DeleteError()
|
|
object WrongPassword : DeleteError()
|
|
class InvalidForm(val validationErrors: ValidationErrors) : DeleteError()
|
|
}
|
|
|
|
data class DeleteForm(val username: String?, val password: String?, val checked: Boolean)
|
|
|
|
sealed class LoginError {
|
|
object Unregistered : LoginError()
|
|
object WrongPassword : LoginError()
|
|
class InvalidLoginForm(val validationErrors: ValidationErrors) : LoginError()
|
|
}
|
|
|
|
typealias Token = String
|
|
|
|
sealed class RegisterError {
|
|
object UserExists : RegisterError()
|
|
class InvalidRegisterForm(val validationErrors: ValidationErrors) : RegisterError()
|
|
}
|
|
|
|
typealias RegisterForm = LoginForm
|
|
|
|
@Serializable
|
|
data class LoginForm(val username: String?, val password: String?)
|