Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/handle registrations improvement #1

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ dependencies {
implementation("io.ktor:ktor-server-config-yaml:$ktor_version")
implementation("io.ktor:ktor-server-cors-jvm:$ktor_version")
implementation("io.ktor:ktor-server-sessions-jvm:$ktor_version")

implementation("io.ktor:ktor-server-status-pages:$ktor_version")

//Ktor client dependencies
implementation("io.ktor:ktor-client-core:$ktor_version")
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ logstash_version=7.4
flyway_version=10.6.0
hikari_version=5.1.0
postgres_version=42.7.1
exposed_version=0.50.0
exposed_version=0.50.1
h2_version=2.1.214
kotlinx_datetime_version=0.2.1
24 changes: 21 additions & 3 deletions src/main/kotlin/no/javabin/App.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package no.javabin

import no.javabin.config.*
import com.inventy.plugins.DatabaseFactory
import io.ktor.server.application.*
import no.javabin.repository.UserRepository
import no.javabin.config.configureAuth
import no.javabin.config.configureRouting
import no.javabin.config.configureSerialization
import no.javabin.config.configureStatusPages
import no.javabin.repository.*
import no.javabin.service.UserService
import no.javabin.service.WorkshopService


fun main(args: Array<String>): Unit =
Expand All @@ -19,7 +24,20 @@ fun Application.module() {
databaseName = environment.config.property("database.databaseName").getString(),
embedded = environment.config.property("database.embedded").getString().toBoolean(),
).init()
configureStatusPages()
val userRepository = UserRepository()
val workshopRepository = WorkshopRepository()
val workshopRegistrationRepository = WorkshopRegistrationRepository()
val adminRepository = AdminRepository()
val speakerRepository = SpeakerRepository()
val workshopService = WorkshopService(
environment.config,
workshopRepository,
speakerRepository,
workshopRegistrationRepository
)
val userService = UserService(environment.config, workshopService, userRepository)

configureAuth(userRepository)
configureRouting(userRepository)
configureRouting(userRepository, workshopService, userService, adminRepository)
}
25 changes: 12 additions & 13 deletions src/main/kotlin/no/javabin/config/Routing.kt
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
package no.javabin.config

import no.javabin.route.*
import no.javabin.service.UserService
import no.javabin.service.WorkshopService
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import no.javabin.repository.*

fun Application.configureRouting(userRepository: UserRepository) {
val adminRepository = AdminRepository()
val workshopRepository = WorkshopRepository()
val workshopRegistrationRepository = WorkshopRegistrationRepository()
val speakerRepository = SpeakerRepository()
val workshopService = WorkshopService(environment.config, workshopRepository, speakerRepository, workshopRegistrationRepository )
val userService = UserService(environment.config, workshopService, userRepository)
import no.javabin.repository.AdminRepository
import no.javabin.repository.UserRepository
import no.javabin.route.*
import no.javabin.service.UserService
import no.javabin.service.WorkshopService

fun Application.configureRouting(
userRepository: UserRepository,
workshopService: WorkshopService,
userService: UserService,
adminRepository: AdminRepository,
) {
configureAuth0Route(userRepository)
configureUserRoutes(userService)
configureWorkshopRoutes(workshopService)
Expand All @@ -26,7 +25,7 @@ fun Application.configureRouting(userRepository: UserRepository) {
routing {
authenticate("auth0-user") {
get("/auth") {
call.respondText("Hello World!")
call.respondText("Hello World User!")
}
}

Expand Down
15 changes: 15 additions & 0 deletions src/main/kotlin/no/javabin/config/StatusPages.kt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package no.javabin.config

import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.plugins.statuspages.*
import io.ktor.server.response.*
import no.javabin.exception.DuplicateRegistrationException

fun Application.configureStatusPages() {
install(StatusPages) {
exception<DuplicateRegistrationException> { call, cause ->
call.respond(HttpStatusCode.Conflict, cause.message ?: "Conflict")
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package no.javabin.dto

import no.javabin.repository.WorkshopRegistrationState
import no.javabin.repository.WorkshopRegistrationStatus
import kotlinx.serialization.Serializable

@Serializable
data class AdminWorkshopRegistrationDTO(val firstName: String, val lastName: String, val email: String, val state: WorkshopRegistrationState)
data class AdminWorkshopRegistrationDTO(val firstName: String, val lastName: String, val email: String, val status: WorkshopRegistrationStatus)
4 changes: 2 additions & 2 deletions src/main/kotlin/no/javabin/dto/WorkshopRegistrationDTO.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ package no.javabin.dto

import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
import no.javabin.repository.WorkshopRegistrationState
import no.javabin.repository.WorkshopRegistrationStatus

@Serializable
class WorkshopRegistrationDTO (
val workshopTitle: String,
val workshopStartTime: Instant,
val workshopEndTime: Instant,
val state: WorkshopRegistrationState
val status: WorkshopRegistrationStatus
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package no.javabin.exception

class DuplicateRegistrationException(message: String?) : Exception(message)
4 changes: 2 additions & 2 deletions src/main/kotlin/no/javabin/repository/AdminRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class AdminRepository {
userMap[it.user.id]!!.firstName,
userMap[it.user.id]!!.lastName,
userMap[it.user.id]!!.email,
it.state,
it.status,
)
}
AdminWorkshopDTO(workshop.value.title, workshop.value.teacherName, registrations)
Expand All @@ -29,7 +29,7 @@ class AdminRepository {
userMap[it.user.id]!!.firstName,
userMap[it.user.id]!!.lastName,
userMap[it.user.id]!!.email,
it.state,
it.status,
)
}
return AdminWorkshopDTO(workshop.title, workshop.teacherName, registrations)
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/no/javabin/repository/SpeakerRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ data class Speaker(

class SpeakerRepository {

internal object SpeakerTable : Table() {
val name = varchar("name", 256)
internal object SpeakerTable : Table("speaker") {
val name = varchar("full_name", 256)
val bio = varchar("bio", 2048)
val twitter = varchar("twitter", 256)
val workshopId = reference("workshop_id", WorkshopRepository.WorkshopTable.id)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,71 +1,83 @@
package no.javabin.repository

import com.inventy.plugins.DatabaseFactory.Companion.dbQuery
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import no.javabin.dto.WorkshopRegistrationDTO
import no.javabin.repository.WorkshopRegistrationRepository.WorkshopRegistrationTable
import no.javabin.util.TimeUtil
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp


enum class WorkshopRegistrationState {
PENDING, WAITLIST, APPROVED, CANCELLED,
enum class WorkshopRegistrationStatus {
WAITLIST, APPROVED, CANCELLED,
}

class WorkshopRegistration(
override val id: Int,
data class WorkshopRegistration(
val userId: Int,
val workshopId: String,
val createdAt: Instant,
val updatedAt: Instant,
var state: WorkshopRegistrationState = WorkshopRegistrationState.PENDING,
) : Model
var status: WorkshopRegistrationStatus = WorkshopRegistrationStatus.WAITLIST,
)

class WorkshopRegistrationRepository {
private object WorkshopRegistrationTable : IntIdTable("workshop_registration") {
internal object WorkshopRegistrationTable : Table("workshop_registration") {
val userId = reference("user_id", UserRepository.UserTable.id)
val workshopId = reference("workshop_id", WorkshopRepository.WorkshopTable.id)
val state = enumerationByName<WorkshopRegistrationState>("state", 64)
val status = enumerationByName<WorkshopRegistrationStatus>("status", 64)
val createdAt = timestamp("created_at")
val updatedAt = timestamp("updated_at")

override val primaryKey = PrimaryKey(
arrayOf(
userId, workshopId
), "id"
)

fun toModel(it: ResultRow) = WorkshopRegistration(
it[id].value,
it[userId].value,
it[workshopId],
it[createdAt],
it[updatedAt],
it[state],
it[status],
)

fun toDTO(it: ResultRow) = WorkshopRegistrationDTO(
workshopTitle = it[WorkshopRepository.WorkshopTable.title],
workshopStartTime = TimeUtil.toGmtPlus2(it[WorkshopRepository.WorkshopTable.startTime]),
workshopEndTime = TimeUtil.toGmtPlus2(it[WorkshopRepository.WorkshopTable.endTime]),
state = it[state],
status = it[status],
)
}

suspend fun create(registration: WorkshopRegistration): Int = dbQuery {
WorkshopRegistrationTable.insertAndGetId {
suspend fun create(registration: WorkshopRegistration) = dbQuery {
WorkshopRegistrationTable.insert {
it[userId] = registration.userId
it[workshopId] = registration.workshopId
it[state] = registration.state
it[status] = registration.status
it[createdAt] = registration.createdAt
it[updatedAt] = registration.updatedAt
}.value
}
}

suspend fun createOrUpdate(registration: WorkshopRegistration) = dbQuery {
WorkshopRegistrationTable.upsert {
it[userId] = registration.userId
it[workshopId] = registration.workshopId
it[status] = registration.status
it[createdAt] = registration.createdAt
it[updatedAt] = registration.updatedAt
}
}

suspend fun list(userId: Int): List<WorkshopRegistrationDTO> = dbQuery {
( WorkshopRegistrationTable innerJoin WorkshopRepository.WorkshopTable )
(WorkshopRegistrationTable innerJoin WorkshopRepository.WorkshopTable)
.select(
WorkshopRepository.WorkshopTable.title,
WorkshopRepository.WorkshopTable.startTime,
WorkshopRepository.WorkshopTable.endTime,
WorkshopRegistrationTable.state
WorkshopRegistrationTable.status
).where { WorkshopRegistrationTable.userId eq userId }
.map(WorkshopRegistrationTable::toDTO)
}
Expand All @@ -85,18 +97,22 @@ class WorkshopRegistrationRepository {
}
}


suspend fun getByWorkshop(workshopId: String): List<WorkshopRegistration> {
return dbQuery {
WorkshopRegistrationTable.selectAll().where { WorkshopRegistrationTable.workshopId eq workshopId }
.orderBy(WorkshopRegistrationTable.updatedAt)
.map(WorkshopRegistrationTable::toModel)
}
}

suspend fun updateState(id: Int, state: WorkshopRegistrationState) {
suspend fun updateStatus(userId: Int, workshopId: String, status: WorkshopRegistrationStatus): Int {
return dbQuery {
WorkshopRegistrationTable.update({ WorkshopRegistrationTable.id eq id }) {
it[WorkshopRegistrationTable.state] = state
WorkshopRegistrationTable.update({
(WorkshopRegistrationTable.userId eq userId) and (WorkshopRegistrationTable.workshopId eq workshopId)
})
{
it[WorkshopRegistrationTable.status] = status
it[updatedAt] = Clock.System.now()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class WorkshopRepository {
}
}

suspend fun listByIdsNotInList(idLIst: List<String>): List<Workshop> = dbQuery {
private suspend fun listByIdsNotInList(idLIst: List<String>): List<Workshop> = dbQuery {
WorkshopTable.selectAll().where(WorkshopTable.id notInList idLIst)
.map(WorkshopTable::toModel)
}
Expand Down
Loading