diff --git a/api/src/controllers/Controllers.kt b/api/src/controllers/Controllers.kt index 20003b9..b46c5b0 100644 --- a/api/src/controllers/Controllers.kt +++ b/api/src/controllers/Controllers.kt @@ -13,4 +13,5 @@ val controllerModule = Kodein.Module(name = "Controller") { bind() from setBinding() bind().inSet() with singleton { UserController(this.kodein) } + bind().inSet() with singleton { HealthCheckController(this.kodein) } } \ No newline at end of file diff --git a/api/src/controllers/HealthCheckController.kt b/api/src/controllers/HealthCheckController.kt new file mode 100644 index 0000000..311ece3 --- /dev/null +++ b/api/src/controllers/HealthCheckController.kt @@ -0,0 +1,21 @@ +package be.vandewalleh.controllers + +import io.ktor.application.call +import io.ktor.locations.Location +import io.ktor.locations.get +import io.ktor.response.respondText +import io.ktor.routing.Routing +import org.kodein.di.Kodein + +class HealthCheckController(kodein: Kodein) : KodeinController(kodein) { + override fun Routing.registerRoutes() { + get { + call.respondText("pong") + } + } + + object Routes { + @Location("/ping") + class Ping + } +} \ No newline at end of file diff --git a/api/src/controllers/UserController.kt b/api/src/controllers/UserController.kt index df03540..f8800f8 100644 --- a/api/src/controllers/UserController.kt +++ b/api/src/controllers/UserController.kt @@ -13,10 +13,7 @@ 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.eq -import me.liuwj.ktorm.dsl.from -import me.liuwj.ktorm.dsl.select -import me.liuwj.ktorm.dsl.where +import me.liuwj.ktorm.dsl.* import me.liuwj.ktorm.entity.add import me.liuwj.ktorm.entity.sequenceOf import org.kodein.di.Kodein @@ -39,11 +36,11 @@ class UserController(kodein: Kodein) : KodeinController(kodein) { .where { Users.username eq credential.username } .map { row -> row[Users.email]!! to row[Users.password]!! } .firstOrNull() - ?: return@post call.respond(HttpStatusCode.BadRequest, ApiError.InvalidCredentialError()) + ?: return@post call.respond(HttpStatusCode.BadRequest, ApiError.InvalidCredentialError) if (!BCrypt.checkpw(credential.password, password)) { - return@post call.respond(HttpStatusCode.BadRequest, ApiError.InvalidCredentialError()) + return@post call.respond(HttpStatusCode.BadRequest, ApiError.InvalidCredentialError) } return@post call.respond(Response(simpleJwt.sign(email))) @@ -54,8 +51,14 @@ class UserController(kodein: Kodein) : KodeinController(kodein) { val user = call.receive() - // TODO check if user does not already exists - // db won't let you insert it anyway + 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) + } val hashedPassword = BCrypt.hashpw(user.password, BCrypt.gensalt()) @@ -68,7 +71,7 @@ class UserController(kodein: Kodein) : KodeinController(kodein) { db.sequenceOf(Users).add(newUser) - call.respond(HttpStatusCode.Created, Response("User created successfully")) + return@post call.respond(HttpStatusCode.Created, Response("User created successfully")) } } diff --git a/api/src/errors/Errors.kt b/api/src/errors/Errors.kt index 8363139..8f6af26 100644 --- a/api/src/errors/Errors.kt +++ b/api/src/errors/Errors.kt @@ -1,5 +1,6 @@ package be.vandewalleh.errors sealed class ApiError(val message: String){ - class InvalidCredentialError : ApiError("Invalid credentials") + object InvalidCredentialError : ApiError("Invalid credentials") + object ExistingUserError : ApiError("User already exists") } diff --git a/api/src/features/CorsFeature.kt b/api/src/features/CorsFeature.kt index 55c4d4e..04484be 100644 --- a/api/src/features/CorsFeature.kt +++ b/api/src/features/CorsFeature.kt @@ -3,9 +3,11 @@ package be.vandewalleh.features import io.ktor.application.Application import io.ktor.application.install import io.ktor.features.CORS +import io.ktor.http.HttpHeaders fun Application.corsFeature() { install(CORS) { anyHost() + header(HttpHeaders.ContentType) } } \ No newline at end of file diff --git a/web/package.json b/web/package.json index 197ac43..a1cb737 100644 --- a/web/package.json +++ b/web/package.json @@ -8,6 +8,7 @@ "lint": "vue-cli-service lint" }, "dependencies": { + "axios": "^0.19.2", "bootstrap-vue": "^2.11.0", "bootswatch": "^4.4.1", "core-js": "^3.6.4", diff --git a/web/src/api/index.js b/web/src/api/index.js new file mode 100644 index 0000000..e8c1751 --- /dev/null +++ b/web/src/api/index.js @@ -0,0 +1,9 @@ +import axios from 'axios' + +export default axios.create({ + baseURL: 'http://localhost:8081', + timeout: 4000, + headers: { + 'Content-Type': 'application/json' + } +}) diff --git a/web/src/components/SignupForm.vue b/web/src/components/SignupForm.vue new file mode 100644 index 0000000..6227c72 --- /dev/null +++ b/web/src/components/SignupForm.vue @@ -0,0 +1,130 @@ + + + diff --git a/web/src/main.js b/web/src/main.js index ef74ccd..46b46c9 100644 --- a/web/src/main.js +++ b/web/src/main.js @@ -2,6 +2,8 @@ import Vue from 'vue' import App from './App.vue' import router from './router' import store from './store' +import Api from './api' + import BootstrapVue from 'bootstrap-vue' import 'bootswatch/dist/minty/bootstrap.css' @@ -15,5 +17,6 @@ Vue.config.productionTip = false new Vue({ router, store, + Api, render: h => h(App) }).$mount('#app') \ No newline at end of file diff --git a/web/src/router/index.js b/web/src/router/index.js index 15b81f4..5f43ce0 100644 --- a/web/src/router/index.js +++ b/web/src/router/index.js @@ -1,6 +1,7 @@ import Vue from 'vue' import VueRouter from 'vue-router' import Home from '../views/Home.vue' +import Signup from '../views/Signup.vue' Vue.use(VueRouter) @@ -9,6 +10,11 @@ const routes = [ path: '/', name: 'Home', component: Home + }, + { + path: '/signup', + name: 'Signup', + component: Signup } ] diff --git a/web/src/views/Signup.vue b/web/src/views/Signup.vue new file mode 100644 index 0000000..e3b3c74 --- /dev/null +++ b/web/src/views/Signup.vue @@ -0,0 +1,21 @@ + + + \ No newline at end of file diff --git a/web/yarn.lock b/web/yarn.lock index 0713e8f..cee04a9 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -1580,6 +1580,13 @@ aws4@^1.8.0: resolved "https://registry.npm.taobao.org/aws4/download/aws4-1.9.1.tgz?cache=0&sync_timestamp=1578958168482&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Faws4%2Fdownload%2Faws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e" integrity sha1-fjPY99RJs/ZzzXLeuavcVS2+Uo4= +axios@^0.19.2: + version "0.19.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" + integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA== + dependencies: + follow-redirects "1.5.10" + babel-eslint@^10.1.0: version "10.1.0" resolved "https://registry.npm.taobao.org/babel-eslint/download/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" @@ -2706,6 +2713,13 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" +debug@=3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + debug@^3.0.0, debug@^3.1.1, debug@^3.2.5: version "3.2.6" resolved "https://registry.npm.taobao.org/debug/download/debug-3.2.6.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" @@ -3614,6 +3628,13 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" +follow-redirects@1.5.10: + version "1.5.10" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" + integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== + dependencies: + debug "=3.1.0" + follow-redirects@^1.0.0: version "1.11.0" resolved "https://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.11.0.tgz#afa14f08ba12a52963140fe43212658897bc0ecb"