diff --git a/api/src/controllers/UserController.kt b/api/src/controllers/UserController.kt index 0c69c41..fce3b8e 100644 --- a/api/src/controllers/UserController.kt +++ b/api/src/controllers/UserController.kt @@ -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() - private val db by instance() + private val userService by instance() override fun Routing.registerRoutes() { - - post { data class Response(val token: String) val credential = call.receive() - 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 { data class Response(val message: String) - val user = call.receive() + val user = call.receive() - 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) } } @@ -85,6 +62,4 @@ class UserController(kodein: Kodein) : KodeinController(kodein) { class Register } -} - -data class RegisterInfo(val username: String, val email: String, val password: String) \ No newline at end of file +} \ No newline at end of file diff --git a/api/src/errors/Errors.kt b/api/src/errors/Errors.kt deleted file mode 100644 index c917a24..0000000 --- a/api/src/errors/Errors.kt +++ /dev/null @@ -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") -} diff --git a/api/src/services/UserService.kt b/api/src/services/UserService.kt index 59dd579..67887d2 100644 --- a/api/src/services/UserService.kt +++ b/api/src/services/UserService.kt @@ -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() } -} \ No newline at end of file + /** + * returns a user email and password from it's email if found or null + */ + fun getEmailAndPasswordFromUsername(username: String): Pair? { + 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) \ No newline at end of file