Skip to content
This repository has been archived by the owner on May 7, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' of github.com:javaBin/workshop-wizard
Browse files Browse the repository at this point in the history
  • Loading branch information
tanettrimas committed Oct 28, 2023
2 parents 48d1cb5 + 1a423dc commit 67898b6
Show file tree
Hide file tree
Showing 14 changed files with 170 additions and 49 deletions.
1 change: 1 addition & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions backend/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ repositories {
}

dependencies {
implementation("io.ktor:ktor-server-auth-jvm:2.3.5")
val ktor_version = "2.3.5"
val logback_version = "1.4.11"
val slf4j_version = "2.0.9"
Expand All @@ -43,6 +44,10 @@ dependencies {
runtimeOnly("org.slf4j:slf4j-api:$slf4j_version")
runtimeOnly("net.logstash.logback:logstash-logback-encoder:$logstash_version")

// Auth
implementation("io.ktor:ktor-server-auth:$ktor_version")


// Serialization
implementation("io.ktor:ktor-server-content-negotiation:$ktor_version")
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")
Expand Down
34 changes: 28 additions & 6 deletions backend/app/src/main/kotlin/backend/App.kt
Original file line number Diff line number Diff line change
@@ -1,33 +1,55 @@
/*
* This Kotlin source file was generated by the Gradle 'init' task.
*/
package backend

import backend.admin.AdminRepository
import backend.admin.adminRoutes
import backend.user.Repository
import backend.user.UserRepository
import backend.user.userRoutes
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.response.*
import io.ktor.server.routing.*

fun server() = embeddedServer(factory = Netty, port = 8080) {
createServer()
}

private fun Application.createServer() {
configureAuth()
configureRouting()
}

class CustomPrincipal(val userId: Int) : Principal

fun Application.configureAuth() {
authentication {
basic(name = "basic") {
realm = "Ktor Server"
validate { credentials ->
if (credentials.name == "user" && credentials.password == "password") {
CustomPrincipal(1)
} else {
null
}
}
}
}
}


fun Application.configureRouting() {
val userRepository = Repository()
val userRepository = UserRepository()
val adminRepository = AdminRepository()

install(ContentNegotiation) {
json()
}
routing {
userRoutes(userRepository)
adminRoutes()
adminRoutes(adminRepository)
healthz()

get {
Expand Down
55 changes: 55 additions & 0 deletions backend/app/src/main/kotlin/backend/admin/AdminRepository.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package backend.admin

import backend.domain.RegistrationState
import backend.domain.User
import backend.domain.WorkShopRegistration
import backend.domain.Workshop

class AdminRepository {
var userMap = mutableMapOf<Int, User>(
1 to User(1, "John", "Doe", "[email protected]"),
2 to User(2, "Jane", "Doe", "[email protected]"),
3 to User(3, "John", "Smith", "[email protected]",)
)

var registrationMap = mutableMapOf<Int, WorkShopRegistration>(
1 to WorkShopRegistration(1,1, 1, RegistrationState.APPROVED),
2 to WorkShopRegistration(2, 1, 2, RegistrationState.APPROVED),
3 to WorkShopRegistration(3, 2, 1, RegistrationState.APPROVED),
4 to WorkShopRegistration(4,3, 3, RegistrationState.APPROVED)
)

var workshopMap = mutableMapOf<Int, Workshop>(
1 to Workshop(1, "Kotlin", "John Doe"),
2 to Workshop(2, "Ktor", "Jane Doe"),
3 to Workshop(3, "Kotlin Multiplatform", "John Doe")
)
fun getWorkshops(): List<AdminWorkshopDTO> {
return workshopMap.map { workshop ->
val registrations = registrationMap.filter { it.value.workshopId == workshop.key }
.map { it.value }
.map { AdminWorkshopRegistration(
userMap[it.userId]!!.firstName,
userMap[it.userId]!!.lastName,
userMap[it.userId]!!.email,
it.state)
}
AdminWorkshopDTO(workshop.value.title, workshop.value.teacherName, registrations)
}
}

fun getWorkshopRegistrations(workshopId: Int): AdminWorkshopDTO {
val workshop = workshopMap.get(workshopId) ?: throw RuntimeException("Workshop does not exist")
val registrations = registrationMap.filter { it.value.workshopId == workshop.id }
.map { it.value }
.map {
AdminWorkshopRegistration(
userMap[it.userId]!!.firstName,
userMap[it.userId]!!.lastName,
userMap[it.userId]!!.email,
it.state
)
}
return AdminWorkshopDTO(workshop.title, workshop.teacherName, registrations)
}
}
12 changes: 12 additions & 0 deletions backend/app/src/main/kotlin/backend/admin/DTO.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package backend.admin

import backend.domain.RegistrationState
import backend.user.WorkshopDTO
import kotlinx.serialization.Serializable

@Serializable
data class AdminWorkshopDTO(val title: String, val teacherName: String, val registrations: List<AdminWorkshopRegistration>)

@Serializable
data class AdminWorkshopRegistration(val firstName: String, val lastName: String, val email: String, val state: RegistrationState)

20 changes: 17 additions & 3 deletions backend/app/src/main/kotlin/backend/admin/Routing.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,22 @@ import io.ktor.server.application.*
import io.ktor.server.response.*
import io.ktor.server.routing.*

fun Routing.adminRoutes() {
get("/admin") {
call.respondText("Hello, world!")

fun Application.configureAdminRoutes() {
routing {
adminRoutes(AdminRepository())
}
}

fun Routing.adminRoutes(adminRepository: backend.admin.AdminRepository) {
get("/admin/workshop") {
call.respond(adminRepository.getWorkshops())
}
get("/admin/workshop/{workshopId}") {
try {
call.respond(adminRepository.getWorkshopRegistrations(call.parameters["workshopId"]!!.toInt()))
} catch (e: Exception) {
call.respondText("Workshop not found", status = io.ktor.http.HttpStatusCode.NotFound)
}
}
}
3 changes: 3 additions & 0 deletions backend/app/src/main/kotlin/backend/domain/User.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package backend.domain

class User(val id: Int, val firstName: String, val lastName: String, val email: String)
3 changes: 3 additions & 0 deletions backend/app/src/main/kotlin/backend/domain/Workshop.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package backend.domain

class Workshop(val id: Int, val title: String, val teacherName: String)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package backend.domain

class WorkShopRegistration(val id: Int, val userId: Int, val workshopId: Int, var state: RegistrationState = RegistrationState.PENDING)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package backend.domain


enum class RegistrationState {
PENDING, WAITLIST, APPROVED, CANCELED,
}

11 changes: 5 additions & 6 deletions backend/app/src/main/kotlin/backend/user/DTO.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package backend.user

class DTO {
var id: Int = 0
var firstName: String = ""
var lastName: String = ""
var email: String = ""
}
import kotlinx.serialization.Serializable

@Serializable
data class WorkshopDTO(val title: String, val teacherName: String)


37 changes: 22 additions & 15 deletions backend/app/src/main/kotlin/backend/user/Routing.kt
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
package backend.user

import backend.CustomPrincipal
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.response.*
import io.ktor.server.routing.*

fun Routing.userRoutes(userRepository: Repository) {
get("/user/workshop") {
// Should be based on the logged in user
call.respond(userRepository.getWorkShopRegistrations(1))
}
fun Routing.userRoutes(userRepository: UserRepository) {
authenticate ("basic") {
get("/user/workshop") {
// Should be based on the logged in user
val userId = call.authentication.principal<CustomPrincipal>()?.userId!!
call.respond(userRepository.getWorkShopRegistrations(userId))
}

post("/user/workshop/{workshopId}") {
try {
userRepository.addWorkshopRegistrations(1, call.parameters["workshopId"]!!.toInt())
call.respondText("Workshop added")
} catch (e: Exception) {
call.respondText("Workshop not found", status = io.ktor.http.HttpStatusCode.NotFound)
post("/user/workshop/{workshopId}") {
try {
val userId = call.authentication.principal<CustomPrincipal>()?.userId!!
userRepository.addWorkshopRegistrations(userId, call.parameters["workshopId"]!!.toInt())
call.respondText("Workshop added")
} catch (e: Exception) {
call.respondText("Workshop not found", status = io.ktor.http.HttpStatusCode.NotFound)
}
}
}

put("/user/workshop/{workshopId}/cancel") {
userRepository.cancelWorkshopRegistration(1, call.parameters["workshopId"]!!.toInt())
call.respondText("Workshop cancelled")
put("/user/workshop/{workshopId}/cancel") {
val userId = call.authentication.principal<CustomPrincipal>()?.userId!!
userRepository.cancelWorkshopRegistration(userId, call.parameters["workshopId"]!!.toInt())
call.respondText("Workshop cancelled")
}
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,12 @@
package backend.user

import kotlinx.serialization.*
import backend.domain.RegistrationState
import backend.domain.User
import backend.domain.WorkShopRegistration
import backend.domain.Workshop
import java.lang.RuntimeException


@Serializable
class User(val id: Int, val firstName: String, val lastName: String, val email: String)

enum class RegistrationState {
PENDING, WAITLIST, APPROVED, CANCELED,

}

@Serializable
class WorkShopRegistration(val id: Int, val userId: Int, val workshopId: Int, var state: RegistrationState = RegistrationState.PENDING)
@Serializable
class Workshop(val id: Int, val title: String, val teacherName: String)

class Repository {
class UserRepository {
var userMap = mutableMapOf<Int, User>(
1 to User(1, "John", "Doe", "[email protected]"),
2 to User(2, "Jane", "Doe", "[email protected]"),
Expand All @@ -37,9 +26,9 @@ class Repository {
3 to Workshop(3, "Kotlin Multiplatform", "John Doe")
)

fun getWorkShopRegistrations(userId: Int) : List<Workshop> {
fun getWorkShopRegistrations(userId: Int) : List<WorkshopDTO> {
val workshopIds = registrationMap.filter { it.value.userId == userId && it.value.state == RegistrationState.APPROVED }.map { it.value.workshopId }
return workshopMap.filter { workshopIds.contains(it.key) }.values.toList()
return workshopMap.filter { workshopIds.contains(it.key) }.values.map { WorkshopDTO(it.title, it.teacherName) }
}

fun addWorkshopRegistrations(userId: Int, workshopId: Int) {
Expand Down
3 changes: 2 additions & 1 deletion backend/app/src/main/kotlin/backend/workshop/Repository.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package backend.workshop

import backend.domain.Workshop


class Workshop(val id: Int, val title: String, val teacherName: String) {}
class Repository {
var map = mutableMapOf<Int, Workshop>(
1 to Workshop(1, "Kotlin", "John Doe"),
Expand Down

0 comments on commit 67898b6

Please sign in to comment.