Merge branch 'user-validation'
This commit is contained in:
commit
d908d229a6
@ -160,6 +160,11 @@
|
|||||||
<artifactId>hoplite-yaml</artifactId>
|
<artifactId>hoplite-yaml</artifactId>
|
||||||
<version>${hoplite_version}</version>
|
<version>${hoplite_version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>am.ik.yavi</groupId>
|
||||||
|
<artifactId>yavi</artifactId>
|
||||||
|
<version>0.4.0</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.javafaker</groupId>
|
<groupId>com.github.javafaker</groupId>
|
||||||
<artifactId>javafaker</artifactId>
|
<artifactId>javafaker</artifactId>
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
package be.vandewalleh.features
|
package be.vandewalleh.features
|
||||||
|
|
||||||
|
import am.ik.yavi.core.ViolationDetail
|
||||||
|
import be.vandewalleh.validation.ValidationException
|
||||||
import io.ktor.application.*
|
import io.ktor.application.*
|
||||||
import io.ktor.features.*
|
import io.ktor.features.*
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
@ -11,5 +13,13 @@ fun Application.handleErrors() {
|
|||||||
exception<IOException> {
|
exception<IOException> {
|
||||||
call.respond(HttpStatusCode.BadRequest)
|
call.respond(HttpStatusCode.BadRequest)
|
||||||
}
|
}
|
||||||
|
exception<ValidationException> {
|
||||||
|
val error = ViolationError(it.details[0])
|
||||||
|
call.respond(HttpStatusCode.BadRequest, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViolationError(detail: ViolationDetail) {
|
||||||
|
val msg = detail.defaultMessage
|
||||||
|
}
|
||||||
|
|||||||
@ -4,6 +4,8 @@ import be.vandewalleh.entities.User
|
|||||||
import be.vandewalleh.extensions.respondStatus
|
import be.vandewalleh.extensions.respondStatus
|
||||||
import be.vandewalleh.extensions.userId
|
import be.vandewalleh.extensions.userId
|
||||||
import be.vandewalleh.services.UserService
|
import be.vandewalleh.services.UserService
|
||||||
|
import be.vandewalleh.validation.receiveValidated
|
||||||
|
import be.vandewalleh.validation.user.registerValidator
|
||||||
import io.ktor.application.*
|
import io.ktor.application.*
|
||||||
import io.ktor.auth.*
|
import io.ktor.auth.*
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
@ -18,14 +20,9 @@ import java.time.LocalDateTime
|
|||||||
fun Routing.user(kodein: Kodein) {
|
fun Routing.user(kodein: Kodein) {
|
||||||
val userService by kodein.instance<UserService>()
|
val userService by kodein.instance<UserService>()
|
||||||
|
|
||||||
post("/user/test") {
|
|
||||||
val user = call.receive<User>()
|
|
||||||
call.respond(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
route("/user") {
|
route("/user") {
|
||||||
post {
|
post {
|
||||||
val user = call.receive<User>()
|
val user = call.receiveValidated(registerValidator)
|
||||||
|
|
||||||
if (userService.userExists(user.username, user.email))
|
if (userService.userExists(user.username, user.email))
|
||||||
return@post call.respondStatus(HttpStatusCode.Conflict)
|
return@post call.respondStatus(HttpStatusCode.Conflict)
|
||||||
@ -39,7 +36,7 @@ fun Routing.user(kodein: Kodein) {
|
|||||||
|
|
||||||
authenticate {
|
authenticate {
|
||||||
put {
|
put {
|
||||||
val user = call.receive<User>()
|
val user = call.receiveValidated(registerValidator)
|
||||||
|
|
||||||
if (userService.userExists(user.username, user.email))
|
if (userService.userExists(user.username, user.email))
|
||||||
return@put call.respond(HttpStatusCode.Conflict)
|
return@put call.respond(HttpStatusCode.Conflict)
|
||||||
|
|||||||
14
api/src/validation/ValidationExtensions.kt
Normal file
14
api/src/validation/ValidationExtensions.kt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package be.vandewalleh.validation
|
||||||
|
|
||||||
|
import am.ik.yavi.core.Validator
|
||||||
|
import am.ik.yavi.core.ViolationDetail
|
||||||
|
import io.ktor.application.*
|
||||||
|
import io.ktor.request.*
|
||||||
|
|
||||||
|
suspend inline fun <reified T : Any> ApplicationCall.receiveValidated(validator: Validator<T>): T {
|
||||||
|
val value: T = receive()
|
||||||
|
validator.validate(value).throwIfInvalid { ValidationException(it.details()) }
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
data class ValidationException(val details: List<ViolationDetail>) : RuntimeException()
|
||||||
18
api/src/validation/user/UserValidation.kt
Normal file
18
api/src/validation/user/UserValidation.kt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package be.vandewalleh.validation.user
|
||||||
|
|
||||||
|
import am.ik.yavi.builder.ValidatorBuilder
|
||||||
|
import am.ik.yavi.builder.konstraint
|
||||||
|
import am.ik.yavi.core.Validator
|
||||||
|
import be.vandewalleh.entities.User
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
.build()
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package routing
|
package integration.routing
|
||||||
|
|
||||||
import be.vandewalleh.auth.SimpleJWT
|
import be.vandewalleh.auth.SimpleJWT
|
||||||
import be.vandewalleh.entities.User
|
import be.vandewalleh.entities.User
|
||||||
@ -70,7 +70,7 @@ class UserControllerKtTest {
|
|||||||
val res = testEngine.post("/user") {
|
val res = testEngine.post("/user") {
|
||||||
json {
|
json {
|
||||||
it["username"] = "new"
|
it["username"] = "new"
|
||||||
it["password"] = "test"
|
it["password"] = "test123abc"
|
||||||
it["email"] = "new@test.com"
|
it["email"] = "new@test.com"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,7 +84,7 @@ class UserControllerKtTest {
|
|||||||
json {
|
json {
|
||||||
it["username"] = "existing"
|
it["username"] = "existing"
|
||||||
it["email"] = "existing@test.com"
|
it["email"] = "existing@test.com"
|
||||||
it["password"] = "test"
|
it["password"] = "test123abc"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res.status() `should be equal to` HttpStatusCode.Conflict
|
res.status() `should be equal to` HttpStatusCode.Conflict
|
||||||
@ -129,6 +129,7 @@ class UserControllerKtTest {
|
|||||||
json {
|
json {
|
||||||
it["username"] = "ThisIsMyNewName"
|
it["username"] = "ThisIsMyNewName"
|
||||||
it["email"] = "ThisIsMyNewName@mail.com"
|
it["email"] = "ThisIsMyNewName@mail.com"
|
||||||
|
it["password"] = "ThisIsMyCurrentPassword"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package services
|
package integration.services
|
||||||
|
|
||||||
import be.vandewalleh.mainModule
|
import be.vandewalleh.mainModule
|
||||||
import be.vandewalleh.migrations.Migration
|
import be.vandewalleh.migrations.Migration
|
||||||
57
api/test/unit/validation/RegisterValidationTest.kt
Normal file
57
api/test/unit/validation/RegisterValidationTest.kt
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package unit.validation
|
||||||
|
|
||||||
|
import be.vandewalleh.entities.User
|
||||||
|
import be.vandewalleh.validation.user.registerValidator
|
||||||
|
import org.amshove.kluent.*
|
||||||
|
import org.junit.jupiter.api.*
|
||||||
|
import utils.firstInvalid
|
||||||
|
|
||||||
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
class RegisterValidationTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `valid register test`() {
|
||||||
|
val violations = registerValidator.validate(User {
|
||||||
|
username = "hubert"
|
||||||
|
password = "definitelyNotMyPassword"
|
||||||
|
email = "test@mail.com"
|
||||||
|
})
|
||||||
|
|
||||||
|
violations.isValid `should be equal to` true
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `invalid email test`() {
|
||||||
|
val violations = registerValidator.validate(User {
|
||||||
|
username = "hubert"
|
||||||
|
password = "definitelyNotMyPassword"
|
||||||
|
email = "teom"
|
||||||
|
})
|
||||||
|
|
||||||
|
violations.isValid `should be equal to` false
|
||||||
|
violations.firstInvalid `should be equal to` "email"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `missing email test`() {
|
||||||
|
val violations = registerValidator.validate(User {
|
||||||
|
username = "hubert"
|
||||||
|
password = "definitelyNotMyPassword"
|
||||||
|
})
|
||||||
|
|
||||||
|
violations.isValid `should be equal to` false
|
||||||
|
violations.firstInvalid `should be equal to` "email"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `username too long test`() {
|
||||||
|
val violations = registerValidator.validate(User {
|
||||||
|
username = "6X9iboWmEOWjVjkO328ReTJ1gGPTTmB/ZGgBLhB6EzAJoWkJht8"
|
||||||
|
password = "definitelyNotMyPassword"
|
||||||
|
email = "test@mail.com"
|
||||||
|
})
|
||||||
|
|
||||||
|
violations.isValid `should be equal to` false
|
||||||
|
violations.firstInvalid `should be equal to` "username"
|
||||||
|
}
|
||||||
|
}
|
||||||
6
api/test/utils/ValidationExtensions.kt
Normal file
6
api/test/utils/ValidationExtensions.kt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import am.ik.yavi.core.ConstraintViolations
|
||||||
|
|
||||||
|
val ConstraintViolations.firstInvalid: Any?
|
||||||
|
get() = this.violations().firstOrNull()?.name()
|
||||||
Loading…
x
Reference in New Issue
Block a user