Upgrade to ktorm 3.0.0, remove email field from users
This commit is contained in:
@@ -1,15 +1,14 @@
|
||||
package be.vandewalleh.entities
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import me.liuwj.ktorm.entity.*
|
||||
import java.time.LocalDateTime
|
||||
|
||||
interface User : Entity<User> {
|
||||
companion object : Entity.Factory<User>()
|
||||
|
||||
val id: Int
|
||||
var username: String
|
||||
var email: String
|
||||
|
||||
@get:JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
|
||||
var password: String
|
||||
var createdAt: LocalDateTime
|
||||
var lastLogin: LocalDateTime?
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import java.nio.ByteBuffer
|
||||
import java.sql.PreparedStatement
|
||||
import java.sql.ResultSet
|
||||
import java.sql.Types
|
||||
import java.util.*
|
||||
import java.util.UUID as JavaUUID
|
||||
|
||||
class UuidBinarySqlType : SqlType<JavaUUID>(Types.BINARY, typeName = "uuidBinary") {
|
||||
@@ -23,6 +22,6 @@ class UuidBinarySqlType : SqlType<JavaUUID>(Types.BINARY, typeName = "uuidBinary
|
||||
}
|
||||
}
|
||||
|
||||
fun <E : Any> BaseTable<E>.uuidBinary(name: String): BaseTable<E>.ColumnRegistration<JavaUUID> {
|
||||
fun <E : Any> BaseTable<E>.uuidBinary(name: String): Column<JavaUUID> {
|
||||
return registerColumn(name, UuidBinarySqlType())
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ fun Routing.auth(kodein: Kodein) {
|
||||
post("/user/login") {
|
||||
val credential = call.receive<UsernamePasswordCredential>()
|
||||
|
||||
val user = userService.getFromUsername(credential.username)
|
||||
val user = userService.find(credential.username)
|
||||
?: return@post call.respondStatus(HttpStatusCode.Unauthorized)
|
||||
|
||||
if (!BCrypt.checkpw(credential.password, user.password)) {
|
||||
@@ -51,7 +51,7 @@ fun Routing.auth(kodein: Kodein) {
|
||||
return@post call.respondStatus(HttpStatusCode.Unauthorized)
|
||||
}
|
||||
|
||||
if (!userService.userExists(id))
|
||||
if (!userService.exists(id))
|
||||
return@post call.respondStatus(HttpStatusCode.Unauthorized)
|
||||
|
||||
val response = DualToken(
|
||||
@@ -63,9 +63,8 @@ fun Routing.auth(kodein: Kodein) {
|
||||
|
||||
authenticate {
|
||||
get("/user/me") {
|
||||
// retrieve email from token
|
||||
val id = call.principal<UserDbIdPrincipal>()!!.id
|
||||
val info = userService.getUserInfo(id)
|
||||
val info = userService.find(id)
|
||||
if (info != null) call.respond(mapOf("user" to info))
|
||||
else call.respondStatus(HttpStatusCode.Unauthorized)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package be.vandewalleh.routing
|
||||
|
||||
import be.vandewalleh.entities.User
|
||||
import be.vandewalleh.extensions.respondStatus
|
||||
import be.vandewalleh.extensions.userId
|
||||
import be.vandewalleh.services.UserService
|
||||
@@ -9,13 +8,11 @@ import be.vandewalleh.validation.user.registerValidator
|
||||
import io.ktor.application.*
|
||||
import io.ktor.auth.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.request.*
|
||||
import io.ktor.response.*
|
||||
import io.ktor.routing.*
|
||||
import org.kodein.di.Kodein
|
||||
import org.kodein.di.generic.instance
|
||||
import org.mindrot.jbcrypt.BCrypt
|
||||
import java.time.LocalDateTime
|
||||
|
||||
fun Routing.user(kodein: Kodein) {
|
||||
val userService by kodein.instance<UserService>()
|
||||
@@ -24,32 +21,20 @@ fun Routing.user(kodein: Kodein) {
|
||||
post {
|
||||
val user = call.receiveValidated(registerValidator)
|
||||
|
||||
if (userService.userExists(user.username, user.email))
|
||||
if (userService.exists(user.username))
|
||||
return@post call.respondStatus(HttpStatusCode.Conflict)
|
||||
|
||||
val hashedPassword = BCrypt.hashpw(user.password, BCrypt.gensalt())
|
||||
|
||||
userService.createUser(user.username, user.email, hashedPassword)
|
||||
val newUser = userService.create(user.username, hashedPassword)
|
||||
?: return@post call.respondStatus(HttpStatusCode.Conflict)
|
||||
|
||||
call.respondStatus(HttpStatusCode.Created)
|
||||
call.respond(HttpStatusCode.Created, newUser)
|
||||
}
|
||||
|
||||
authenticate {
|
||||
put {
|
||||
val user = call.receiveValidated(registerValidator)
|
||||
|
||||
if (userService.userExists(user.username, user.email))
|
||||
return@put call.respond(HttpStatusCode.Conflict)
|
||||
|
||||
val hashedPassword = BCrypt.hashpw(user.password, BCrypt.gensalt())
|
||||
|
||||
userService.updateUser(call.userId(), user.username, user.email, hashedPassword)
|
||||
|
||||
call.respondStatus(HttpStatusCode.OK)
|
||||
}
|
||||
|
||||
delete {
|
||||
val status = if (userService.deleteUser(call.userId()))
|
||||
val status = if (userService.delete(call.userId()))
|
||||
HttpStatusCode.OK
|
||||
else
|
||||
HttpStatusCode.NotFound
|
||||
|
||||
@@ -47,12 +47,11 @@ class NotesService(override val kodein: Kodein) : KodeinAware {
|
||||
}
|
||||
|
||||
fun noteExists(userId: Int, uuid: UUID): Boolean {
|
||||
return db.from(Notes)
|
||||
.select(Notes.uuid)
|
||||
.where { Notes.userId eq userId }
|
||||
.where { Notes.uuid eq uuid }
|
||||
.limit(0, 1)
|
||||
.toList().size == 1
|
||||
return db.sequenceOf(Notes)
|
||||
.filterColumns { listOf(it.uuid) }
|
||||
.find {
|
||||
it.userId eq userId and (it.uuid eq uuid)
|
||||
} == null
|
||||
}
|
||||
|
||||
fun createNote(userId: Int, note: FullNoteCreateDTO): UUID {
|
||||
|
||||
@@ -20,62 +20,39 @@ import java.time.LocalDateTime
|
||||
class UserService(override val kodein: Kodein) : KodeinAware {
|
||||
private val db by instance<Database>()
|
||||
|
||||
/**
|
||||
* returns a user ID if present or null
|
||||
*/
|
||||
suspend fun getUserId(userEmail: String): Int? = launchIo {
|
||||
db.from(Users)
|
||||
.select(Users.id)
|
||||
.where { Users.email eq userEmail }
|
||||
.map { it[Users.id] }
|
||||
.firstOrNull()
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a user email and password from it's username if found or null
|
||||
* returns a user from it's username if found or null
|
||||
*/
|
||||
suspend fun getFromUsername(username: String): User? = launchIo {
|
||||
db.from(Users)
|
||||
.select(Users.email, Users.password, Users.id)
|
||||
.where { Users.username eq username }
|
||||
.map { row ->
|
||||
Users.createEntity(row)
|
||||
}
|
||||
.firstOrNull()
|
||||
suspend fun find(username: String): User? = launchIo {
|
||||
db.sequenceOf(Users, withReferences = false)
|
||||
.find { it.username eq username }
|
||||
}
|
||||
|
||||
suspend fun userExists(username: String, email: String): Boolean = launchIo {
|
||||
db.from(Users)
|
||||
.select(Users.id)
|
||||
.where { (Users.username eq username) or (Users.email eq email) }
|
||||
.firstOrNull() != null
|
||||
suspend fun find(id: Int): User? = launchIo {
|
||||
db.sequenceOf(Users, withReferences = false)
|
||||
.find { it.id eq id }
|
||||
}
|
||||
|
||||
suspend fun userExists(userId: Int): Boolean = launchIo {
|
||||
db.from(Users)
|
||||
.select(Users.id)
|
||||
.where { Users.id eq userId }
|
||||
.firstOrNull() != null
|
||||
|
||||
suspend fun exists(username: String) = launchIo {
|
||||
db.sequenceOf(Users, withReferences = false)
|
||||
.any { it.username eq username }
|
||||
}
|
||||
|
||||
suspend fun getUserInfo(id: Int): User? = launchIo {
|
||||
db.from(Users)
|
||||
.select(Users.email, Users.username)
|
||||
.where { Users.id eq id }
|
||||
.map { Users.createEntity(it) }
|
||||
.firstOrNull()
|
||||
suspend fun exists(userId: Int) = launchIo {
|
||||
db.sequenceOf(Users).any { it.id eq userId }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* create a new user
|
||||
* password should already be hashed
|
||||
*/
|
||||
suspend fun createUser(username: String, email: String, hashedPassword: String): User? {
|
||||
suspend fun create(username: String, hashedPassword: String): User? {
|
||||
val newUser = User {
|
||||
this.username = username
|
||||
this.email = email
|
||||
password = hashedPassword
|
||||
createdAt = LocalDateTime.now()
|
||||
}
|
||||
|
||||
return try {
|
||||
@@ -90,25 +67,11 @@ class UserService(override val kodein: Kodein) : KodeinAware {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateUser(userId: Int, username: String, email: String, hashedPassword: String): Unit = launchIo {
|
||||
db.useTransaction {
|
||||
db.update(Users) {
|
||||
it.username to username
|
||||
it.email to email
|
||||
it.password to hashedPassword
|
||||
where {
|
||||
it.id eq userId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun deleteUser(userId: Int): Boolean = launchIo {
|
||||
db.useTransaction {
|
||||
suspend fun delete(userId: Int): Boolean = launchIo {
|
||||
val updateCount = db.useTransaction {
|
||||
db.delete(Users) { it.id eq userId }
|
||||
}
|
||||
}.let {
|
||||
when (it) {
|
||||
when (updateCount) {
|
||||
1 -> true
|
||||
0 -> false
|
||||
else -> error("??")
|
||||
|
||||
@@ -5,10 +5,10 @@ import be.vandewalleh.extensions.uuidBinary
|
||||
import me.liuwj.ktorm.schema.*
|
||||
|
||||
object Chapters : Table<Chapter>("Chapters") {
|
||||
val id by int("id").primaryKey().bindTo { it.id }
|
||||
val number by int("number").bindTo { it.number }
|
||||
val content by text("content").bindTo { it.content }
|
||||
val title by varchar("title").bindTo { it.title }
|
||||
val noteUuid by uuidBinary("note_uuid").references(Notes) { it.note }
|
||||
val id = int("id").primaryKey().bindTo { it.id }
|
||||
val number = int("number").bindTo { it.number }
|
||||
val content = text("content").bindTo { it.content }
|
||||
val title = varchar("title").bindTo { it.title }
|
||||
val noteUuid = uuidBinary("note_uuid").references(Notes) { it.note }
|
||||
val note get() = noteUuid.referenceTable as Notes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ import be.vandewalleh.extensions.uuidBinary
|
||||
import me.liuwj.ktorm.schema.*
|
||||
|
||||
object Notes : Table<Note>("Notes") {
|
||||
val uuid by uuidBinary("uuid").primaryKey().bindTo { it.uuid }
|
||||
val title by varchar("title").bindTo { it.title }
|
||||
val userId by int("user_id").references(Users) { it.user }
|
||||
val updatedAt by datetime("updated_at").bindTo { it.updatedAt }
|
||||
val uuid = uuidBinary("uuid").primaryKey().bindTo { it.uuid }
|
||||
val title = varchar("title").bindTo { it.title }
|
||||
val userId = int("user_id").references(Users) { it.user }
|
||||
val updatedAt = datetime("updated_at").bindTo { it.updatedAt }
|
||||
val user get() = userId.referenceTable as Users
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ import be.vandewalleh.extensions.uuidBinary
|
||||
import me.liuwj.ktorm.schema.*
|
||||
|
||||
object Tags : Table<Tag>("Tags") {
|
||||
val id by int("id").primaryKey().bindTo { it.id }
|
||||
val name by varchar("name").bindTo { it.name }
|
||||
val noteUuid by uuidBinary("note_uuid").references(Notes) { it.note }
|
||||
val id = int("id").primaryKey().bindTo { it.id }
|
||||
val name = varchar("name").bindTo { it.name }
|
||||
val noteUuid = uuidBinary("note_uuid").references(Notes) { it.note }
|
||||
val note get() = noteUuid.referenceTable as Notes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,7 @@ import be.vandewalleh.entities.User
|
||||
import me.liuwj.ktorm.schema.*
|
||||
|
||||
object Users : Table<User>("Users") {
|
||||
val id by int("id").primaryKey().bindTo { it.id }
|
||||
val username by varchar("username").bindTo { it.username }
|
||||
val email by varchar("email").bindTo { it.email }
|
||||
val password by varchar("password").bindTo { it.password }
|
||||
val createdAt by datetime("created_at").bindTo { it.createdAt }
|
||||
val lastLogin by datetime("last_login").bindTo { it.lastLogin }
|
||||
}
|
||||
val id = int("id").primaryKey().bindTo { it.id }
|
||||
val username = varchar("username").bindTo { it.username }
|
||||
val password = varchar("password").bindTo { it.password }
|
||||
}
|
||||
|
||||
@@ -9,9 +9,6 @@ val registerValidator: Validator<User> = ValidatorBuilder.of<User>()
|
||||
.konstraint(User::username) {
|
||||
notNull().lessThanOrEqual(50).greaterThanOrEqual(3)
|
||||
}
|
||||
.konstraint(User::email) {
|
||||
notNull().notEmpty().lessThanOrEqual(255).email()
|
||||
}
|
||||
.konstraint(User::password) {
|
||||
notNull().greaterThanOrEqual(6)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user