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

Commit

Permalink
Merge pull request #267 from echo-webkom/feature/delete-regs
Browse files Browse the repository at this point in the history
✨ Add ability to delete registrations
  • Loading branch information
bakseter authored Mar 3, 2022
2 parents 18c1914 + 2aa110f commit 20ec974
Show file tree
Hide file tree
Showing 6 changed files with 246 additions and 93 deletions.
1 change: 1 addition & 0 deletions src/main/kotlin/no/uib/echo/Application.kt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ fun Application.module() {
configureRouting(
adminKey,
sendGridApiKey,
dev,
FeatureToggles(sendEmailReg = sendEmailReg, sendEmailHap = sendEmailHap, rateLimit = true)
)
}
116 changes: 87 additions & 29 deletions src/main/kotlin/no/uib/echo/plugins/Routing.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import io.ktor.routing.get
import io.ktor.routing.post
import io.ktor.routing.put
import io.ktor.routing.routing
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import no.uib.echo.FeatureToggles
import no.uib.echo.Response
import no.uib.echo.plugins.Routing.deleteHappening
Expand All @@ -45,16 +47,17 @@ import no.uib.echo.schema.HappeningJson
import no.uib.echo.schema.HappeningSlugJson
import no.uib.echo.schema.Registration
import no.uib.echo.schema.RegistrationJson
import no.uib.echo.schema.ShortRegistrationJson
import no.uib.echo.schema.SpotRange
import no.uib.echo.schema.SpotRangeWithCountJson
import no.uib.echo.schema.countRegistrationsDegreeYear
import no.uib.echo.schema.insertOrUpdateHappening
import no.uib.echo.schema.selectHappening
import no.uib.echo.schema.selectSpotRanges
import no.uib.echo.schema.toCsv
import no.uib.echo.schema.validateLink
import no.uib.echo.sendConfirmationEmail
import org.jetbrains.exposed.sql.SortOrder
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.StdOutSqlLogger
import org.jetbrains.exposed.sql.addLogger
import org.jetbrains.exposed.sql.and
Expand All @@ -64,12 +67,15 @@ import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.lowerCase
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
import org.joda.time.DateTime
import java.net.URLDecoder
import java.time.Duration

fun Application.configureRouting(
adminKey: String,
sendGridApiKey: String?,
dev: Boolean,
featureToggles: FeatureToggles
) {
val admin = "admin"
Expand Down Expand Up @@ -100,14 +106,14 @@ fun Application.configureRouting(
getStatus()

authenticate("auth-$admin") {
deleteRegistration()
putHappening(sendGridApiKey, featureToggles.sendEmailHap)
putHappening(sendGridApiKey, featureToggles.sendEmailHap, dev)
deleteHappening()
getRegistrationCount()
}

getRegistrations()
getRegistrations(dev)
postRegistration(sendGridApiKey, featureToggles.sendEmailReg)
deleteRegistration(dev)
}
}
}
Expand Down Expand Up @@ -160,25 +166,14 @@ object Routing {
}
}

fun Route.getRegistrations() {
fun Route.getRegistrations(dev: Boolean) {
get("/$registrationRoute/{link}") {
val link = call.parameters["link"]
val download = call.request.queryParameters["download"] != null
val json = call.request.queryParameters["json"] != null
val testing = call.request.queryParameters["testing"] != null

if ((link == null) || (link.length < 128)) {
call.respond(HttpStatusCode.NotFound)
return@get
}

val hap = transaction {
addLogger(StdOutSqlLogger)

Happening.select {
Happening.registrationsLink eq link
}.firstOrNull()
}
val hap = validateLink(link, dev)

if (hap == null) {
call.respond(HttpStatusCode.NotFound)
Expand Down Expand Up @@ -419,36 +414,99 @@ object Routing {
}
}

fun Route.deleteRegistration() {
delete("/$registrationRoute") {
fun Route.deleteRegistration(dev: Boolean) {
delete("/$registrationRoute/{link}/{email}") {
fun stdResponse() {
}

val link = call.parameters["link"]
val email = withContext(Dispatchers.IO) {
URLDecoder.decode(call.parameters["email"], "utf-8")
}

val hap = validateLink(link, dev)

if (hap == null || email == null) {
call.respond(HttpStatusCode.NotFound)
return@delete
}

try {
val shortReg = call.receive<ShortRegistrationJson>()
val reg = transaction {
addLogger(StdOutSqlLogger)

Registration.select {
Registration.happeningSlug eq hap[slug] and
(Registration.email.lowerCase() eq email.lowercase())
}.firstOrNull()
}

if (reg == null) {
call.respond(HttpStatusCode.BadRequest)
return@delete
}

transaction {
addLogger(StdOutSqlLogger)

Answer.deleteWhere {
Answer.happeningSlug eq hap[slug] and
(Answer.registrationEmail.lowerCase() eq email.lowercase())
}

Registration.deleteWhere {
Registration.happeningSlug eq shortReg.slug and
(Registration.email.lowerCase() eq shortReg.email.lowercase())
Registration.happeningSlug eq hap[slug] and
(Registration.email.lowerCase() eq email.lowercase())
}
}

call.respond(
HttpStatusCode.OK,
"Registration (${shortReg.type}) with email = ${shortReg.email} and slug = ${shortReg.slug} deleted."
)
if (reg[Registration.waitList]) {
call.respond(
HttpStatusCode.OK,
"Registration with email = ${email.lowercase()} and slug = ${hap[slug]} deleted."
)
return@delete
}

val highestOnWaitList = transaction {
addLogger(StdOutSqlLogger)

Registration.select {
Registration.waitList eq true
}.orderBy(Registration.submitDate).firstOrNull()
}

if (highestOnWaitList == null) {
call.respond(
HttpStatusCode.OK,
"Registration with email = ${email.lowercase()} and slug = ${hap[slug]} deleted."
)
} else {
transaction {
addLogger(StdOutSqlLogger)

Registration.update({ Registration.email eq highestOnWaitList[Registration.email].lowercase() }) {
it[waitList] = false
}
}
call.respond(
HttpStatusCode.OK,
"Registration with email = ${email.lowercase()} and slug = ${hap[slug]} deleted, " +
"and registration with email = ${highestOnWaitList[Registration.email].lowercase()} moved off wait list."
)
}
} catch (e: Exception) {
call.respond(HttpStatusCode.BadRequest, "Error deleting registration.")
e.printStackTrace()
}
}
}

fun Route.putHappening(sendGridApiKey: String?, sendEmail: Boolean) {
fun Route.putHappening(sendGridApiKey: String?, sendEmail: Boolean, dev: Boolean) {
put("/$happeningRoute") {
try {
val happ = call.receive<HappeningJson>()
val result = insertOrUpdateHappening(happ, sendEmail, sendGridApiKey)
val hap = call.receive<HappeningJson>()
val result = insertOrUpdateHappening(hap, sendGridApiKey, sendEmail, dev)

call.respond(result.first, result.second)
} catch (e: Exception) {
Expand Down
28 changes: 23 additions & 5 deletions src/main/kotlin/no/uib/echo/schema/Happening.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import no.uib.echo.schema.Happening.organizerEmail
import no.uib.echo.schema.Happening.registrationDate
import no.uib.echo.sendEmail
import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.sql.StdOutSqlLogger
import org.jetbrains.exposed.sql.Table
import org.jetbrains.exposed.sql.addLogger
Expand Down Expand Up @@ -75,8 +76,9 @@ fun selectHappening(slug: String): HappeningJson? {

suspend fun insertOrUpdateHappening(
newHappening: HappeningJson,
sendGridApiKey: String?,
sendEmail: Boolean,
sendGridApiKey: String?
dev: Boolean,
): Pair<HttpStatusCode, HappeningResponseJson> {
if (newHappening.spotRanges.isEmpty()) {
return Pair(
Expand All @@ -87,10 +89,13 @@ suspend fun insertOrUpdateHappening(

val happening = selectHappening(newHappening.slug)
val registrationsLink =
(1..REG_LINK_LENGTH).map {
(('A'..'Z') + ('a'..'z') + ('0'..'9'))
.random()
}.joinToString("")
if (dev)
newHappening.slug
else
(1..REG_LINK_LENGTH).map {
(('A'..'Z') + ('a'..'z') + ('0'..'9'))
.random()
}.joinToString("")

if (happening == null) {
transaction {
Expand Down Expand Up @@ -223,3 +228,16 @@ fun spotRangeToString(spotRanges: List<SpotRangeJson>): String {
}
} ]"
}

fun validateLink(link: String?, dev: Boolean): ResultRow? {
if (link == null || (link.length != 128 && !dev))
return null

return transaction {
addLogger(StdOutSqlLogger)

Happening.select {
Happening.registrationsLink eq link
}.firstOrNull()
}
}
2 changes: 0 additions & 2 deletions src/main/kotlin/no/uib/echo/schema/Registration.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ data class RegistrationJson(
val type: HAPPENING_TYPE
)

data class ShortRegistrationJson(val slug: String, val email: String, val type: HAPPENING_TYPE)

object Registration : Table() {
val email: Column<String> = text("email")
val firstName: Column<String> = text("first_name")
Expand Down
Loading

0 comments on commit 20ec974

Please sign in to comment.