Use UserService

This commit is contained in:
Hubert Van De Walle 2020-04-20 16:00:34 +02:00
parent d6f2489d50
commit dc7f6b7b3a
3 changed files with 58 additions and 47 deletions

View File

@ -2,9 +2,8 @@ package be.vandewalleh.controllers
import be.vandewalleh.auth.SimpleJWT
import be.vandewalleh.auth.UsernamePasswordCredential
import be.vandewalleh.entities.User
import be.vandewalleh.errors.ApiError
import be.vandewalleh.tables.Users
import be.vandewalleh.services.UserRegistrationDto
import be.vandewalleh.services.UserService
import io.ktor.application.call
import io.ktor.http.HttpStatusCode
import io.ktor.locations.Location
@ -12,37 +11,26 @@ import io.ktor.locations.post
import io.ktor.request.receive
import io.ktor.response.respond
import io.ktor.routing.Routing
import me.liuwj.ktorm.database.Database
import me.liuwj.ktorm.dsl.*
import me.liuwj.ktorm.entity.add
import me.liuwj.ktorm.entity.sequenceOf
import org.kodein.di.Kodein
import org.kodein.di.generic.instance
import org.mindrot.jbcrypt.BCrypt
import java.time.LocalDateTime
class UserController(kodein: Kodein) : KodeinController(kodein) {
private val simpleJwt by instance<SimpleJWT>()
private val db by instance<Database>()
private val userService by instance<UserService>()
override fun Routing.registerRoutes() {
post<Routes.Login> {
data class Response(val token: String)
val credential = call.receive<UsernamePasswordCredential>()
val (email, password) = db.from(Users)
.select(Users.email, Users.password)
.where { Users.username eq credential.username }
.map { row -> row[Users.email]!! to row[Users.password]!! }
.firstOrNull()
?: return@post call.respond(HttpStatusCode.Unauthorized, ApiError.InvalidCredentialError)
val (email, password) = userService.getEmailAndPasswordFromUsername(credential.username)
?: return@post call.respondStatus(HttpStatusCode.Unauthorized)
if (!BCrypt.checkpw(credential.password, password)) {
return@post call.respond(HttpStatusCode.Unauthorized, ApiError.InvalidCredentialError)
return@post call.respondStatus(HttpStatusCode.Unauthorized)
}
return@post call.respond(Response(simpleJwt.sign(email)))
@ -51,29 +39,18 @@ class UserController(kodein: Kodein) : KodeinController(kodein) {
post<Routes.Register> {
data class Response(val message: String)
val user = call.receive<RegisterInfo>()
val user = call.receive<UserRegistrationDto>()
val exists = db.from(Users)
.select()
.where { (Users.username eq user.username) or (Users.email eq user.email) }
.any()
if (exists) {
return@post call.respond(HttpStatusCode.Conflict, ApiError.ExistingUserError)
}
if (userService.userExists(user.username, user.email))
return@post call.respond(HttpStatusCode.Conflict)
val hashedPassword = BCrypt.hashpw(user.password, BCrypt.gensalt())
val newUser = User {
this.username = user.username
this.email = user.email
this.password = hashedPassword
this.createdAt = LocalDateTime.now()
}
userService.createUser(
UserRegistrationDto(user.username, user.email, hashedPassword)
)
db.sequenceOf(Users).add(newUser)
return@post call.respond(HttpStatusCode.Created, Response("User created successfully"))
return@post call.respondStatus(HttpStatusCode.Created)
}
}
@ -86,5 +63,3 @@ class UserController(kodein: Kodein) : KodeinController(kodein) {
}
}
data class RegisterInfo(val username: String, val email: String, val password: String)

View File

@ -1,7 +0,0 @@
package be.vandewalleh.errors
sealed class ApiError(val message: String){
object InvalidCredentialError : ApiError("Invalid credentials")
object ExistingUserError : ApiError("User already exists")
object DeletedUserError : ApiError("User has been deleted")
}

View File

@ -1,11 +1,15 @@
package be.vandewalleh.services
import be.vandewalleh.entities.User
import be.vandewalleh.tables.Users
import me.liuwj.ktorm.database.Database
import me.liuwj.ktorm.dsl.*
import me.liuwj.ktorm.entity.add
import me.liuwj.ktorm.entity.sequenceOf
import org.kodein.di.Kodein
import org.kodein.di.KodeinAware
import org.kodein.di.generic.instance
import java.time.LocalDateTime
/**
* service to handle database queries for users.
@ -25,4 +29,43 @@ class UserService(override val kodein: Kodein) : KodeinAware {
.firstOrNull()
}
/**
* returns a user email and password from it's email if found or null
*/
fun getEmailAndPasswordFromUsername(username: String): Pair<String, String>? {
return db.from(Users)
.select(Users.email, Users.password)
.where { Users.username eq username }
.limit(0, 1)
.map { row -> row[Users.email]!! to row[Users.password]!! }
.firstOrNull()
}
fun userExists(username: String, email: String): Boolean {
return db.from(Users)
.select(Users.id)
.where { (Users.username eq username) or (Users.email eq email) }
.limit(0, 1)
.firstOrNull() != null
}
/**
* create a new user
* password should already be hashed
*/
fun createUser(user: UserRegistrationDto) {
db.useTransaction {
val newUser = User {
this.username = user.username
this.email = user.email
this.password = user.password
this.createdAt = LocalDateTime.now()
}
db.sequenceOf(Users).add(newUser)
}
}
}
data class UserRegistrationDto(val username: String, val email: String, val password: String)