From: TheSaminator Date: Wed, 23 Feb 2022 15:00:05 +0000 (-0500) Subject: Various refactoring X-Git-Url: https://gitweb.starshipfights.net/?a=commitdiff_plain;h=2f83e47bb876b7005be08b4ee2223ec98ae18645;p=starship-fights Various refactoring --- diff --git a/run b/run deleted file mode 100755 index c1cd6d7..0000000 --- a/run +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env sh - -screen -dmS starshipfights gradle runShadow diff --git a/src/commonMain/kotlin/starshipfights/game/ship_factions.kt b/src/commonMain/kotlin/starshipfights/game/ship_factions.kt index d6431f5..45e01d5 100644 --- a/src/commonMain/kotlin/starshipfights/game/ship_factions.kt +++ b/src/commonMain/kotlin/starshipfights/game/ship_factions.kt @@ -20,7 +20,7 @@ enum class Faction( navyName = "Mechyrdian Star Fleet", polityName = "Empire of Mechyrdia", demonymSingular = "Mechyrdian", - currencyName = "throne", + currencyName = "thrones", shipPrefix = "CMS ", // Ciarstuos Mehurdiasi Å telnau blurbDesc = { p { @@ -46,7 +46,7 @@ enum class Faction( navyName = "Masra Draetsen Khoy'qan", polityName = "Diadochus Masra Draetsen", demonymSingular = "Diadochi", - currencyName = "sylaph", + currencyName = "sylaphs", shipPrefix = "", // The Diadochi don't use ship prefixes blurbDesc = { p { @@ -66,8 +66,8 @@ enum class Faction( navyName = "Isarnareyksk Styurnamariyn", polityName = "Isarnareyksk Federation", demonymSingular = "Isarnareyksk", - currencyName = "mark", - shipPrefix = "ISMS ", // Isarnareyksk StyurnaMariyn nu Skyf + currencyName = "marks", + shipPrefix = "ISS ", // Isarnareyksk Styurnamariyn nu Skyf blurbDesc = { p { +"The Isarnareyksk Federation is the largest and most populous successor state to the Fulkreyksk Authoritariat. A shadow of its former glory, Isarnareykk is led by Faurasitand Demeter Ursalia and ruled by dissenting factions such as the tech barons and the revanchist military, that hate each other more than they hate Ursalia." @@ -92,8 +92,8 @@ enum class Faction( navyName = "Imperial States Space Force", polityName = "Imperial States of America", demonymSingular = "American", - currencyName = "dollar", - shipPrefix = "ISFC ", // Imperial Space Force Craft + currencyName = "dollars", + shipPrefix = "ASC ", // American Space Craft blurbDesc = { p { +"The Imperial States of America was once the political hyperpower of Earth and beyond, and the ideological bulwark of the Caesarism of its time. They were strong, they were proud... they were hated. Hated to the point that entire nations fled from Earth and colonized the stars just to escape American hegemony." diff --git a/src/jvmMain/kotlin/starshipfights/auth/providers.kt b/src/jvmMain/kotlin/starshipfights/auth/providers.kt index 23a9714..caf1697 100644 --- a/src/jvmMain/kotlin/starshipfights/auth/providers.kt +++ b/src/jvmMain/kotlin/starshipfights/auth/providers.kt @@ -161,7 +161,7 @@ interface AuthProvider { val admiralId = call.parameters["id"]?.let { Id(it) }!! val admiral = Admiral.get(admiralId)!! - if (admiral.owningUser != currentUser) throw ForbiddenException() + if (admiral.owningUser != currentUser) forbid() val newAdmiral = admiral.copy( name = form["name"]?.takeIf { it.isNotBlank() } ?: admiral.name, @@ -189,8 +189,8 @@ interface AuthProvider { admiral.await() to ship.await() } - if (admiral.owningUser != currentUser) throw ForbiddenException() - if (ship.owningAdmiral != admiralId) throw ForbiddenException() + if (admiral.owningUser != currentUser) forbid() + if (ship.owningAdmiral != admiralId) forbid() val newName = formParams["name"]?.takeIf { it.isNotBlank() && it.length <= SHIP_NAME_MAX_LENGTH } ?: redirect("/admiral/${admiralId}/manage") ShipInDrydock.set(shipId, setValue(ShipInDrydock::name, newName)) @@ -216,8 +216,8 @@ interface AuthProvider { admiral.await() to ship.await() } - if (admiral.owningUser != currentUser) throw ForbiddenException() - if (ship.owningAdmiral != admiralId) throw ForbiddenException() + if (admiral.owningUser != currentUser) forbid() + if (ship.owningAdmiral != admiralId) forbid() if (ship.status != DrydockStatus.Ready) redirect("/admiral/${admiralId}/manage") if (ship.shipType.weightClass.isUnique) redirect("/admiral/${admiralId}/manage") @@ -241,7 +241,7 @@ interface AuthProvider { val admiralId = call.parameters["id"]?.let { Id(it) }!! val admiral = Admiral.get(admiralId)!! - if (admiral.owningUser != currentUser) throw ForbiddenException() + if (admiral.owningUser != currentUser) forbid() val shipType = call.parameters["ship"]?.let { param -> ShipType.values().singleOrNull { it.toUrlSlug() == param } }!! @@ -288,7 +288,7 @@ interface AuthProvider { val admiralId = call.parameters["id"]?.let { Id(it) }!! val admiral = Admiral.get(admiralId)!! - if (admiral.owningUser != currentUser) throw ForbiddenException() + if (admiral.owningUser != currentUser) forbid() coroutineScope { launch { Admiral.del(admiralId) } @@ -555,7 +555,7 @@ class ProductionAuthProvider(private val discordLogin: DiscordLogin) : AuthProvi } get("/login/discord/callback") { - val userAgent = call.request.userAgent() ?: throw ForbiddenException() + val userAgent = call.request.userAgent() ?: forbid() val principal: OAuthAccessTokenResponse.OAuth2 = call.principal() ?: redirect("/login") val userInfoJson = httpClient.get("https://discord.com/api/users/@me") { headers { diff --git a/src/jvmMain/kotlin/starshipfights/auth/ratelimit.kt b/src/jvmMain/kotlin/starshipfights/auth/ratelimit.kt index 987c3d5..6440690 100644 --- a/src/jvmMain/kotlin/starshipfights/auth/ratelimit.kt +++ b/src/jvmMain/kotlin/starshipfights/auth/ratelimit.kt @@ -11,6 +11,7 @@ import kotlinx.coroutines.delay import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json +import starshipfights.rateLimit import kotlin.math.roundToLong class RateLimit( @@ -46,6 +47,8 @@ class RateLimit( val jsonBody = context.response.receive() val rateLimitedResponse = feature.jsonCodec.decodeFromString(RateLimitedResponse.serializer(), jsonBody) feature.resetAfter = rateLimitedResponse.retryAfter + + rateLimit() } else { context.response.headers[feature.remainingHeader]?.toIntOrNull()?.let { feature.remainingRequests = it diff --git a/src/jvmMain/kotlin/starshipfights/auth/utils.kt b/src/jvmMain/kotlin/starshipfights/auth/utils.kt index 2df4248..9c9c1ef 100644 --- a/src/jvmMain/kotlin/starshipfights/auth/utils.kt +++ b/src/jvmMain/kotlin/starshipfights/auth/utils.kt @@ -6,7 +6,7 @@ import io.ktor.http.* import io.ktor.request.* import io.ktor.sessions.* import io.ktor.util.* -import starshipfights.ForbiddenException +import starshipfights.forbid import starshipfights.data.Id import starshipfights.data.auth.User import starshipfights.data.auth.UserSession @@ -73,5 +73,5 @@ suspend fun ApplicationCall.receiveValidatedParameters(): Parameters { if (CsrfProtector.verifyNonce(csrfToken, sessionId, request.uri)) return formInput else - throw ForbiddenException() + forbid() } diff --git a/src/jvmMain/kotlin/starshipfights/data/admiralty/admiral_names.kt b/src/jvmMain/kotlin/starshipfights/data/admiralty/admiral_names.kt index 9e9a12e..137f5bf 100644 --- a/src/jvmMain/kotlin/starshipfights/data/admiralty/admiral_names.kt +++ b/src/jvmMain/kotlin/starshipfights/data/admiralty/admiral_names.kt @@ -229,7 +229,7 @@ object AdmiralNames { private val caliboreseVowels = "aeiouy".toSet() private fun randomCaliboreseName(isFemale: Boolean) = caliboreseNames.filter { - it.length < 8 && (if (isFemale) it.last() in caliboreseVowels else it.last() !in caliboreseVowels) + it.length < 8 && (isFemale == (it.last() in caliboreseVowels)) }.random() + " " + caliboreseNames.filter { it.length > 7 }.random() private val diadochiMaleNames = listOf( @@ -294,13 +294,13 @@ object AdmiralNames { "Murder", "Gore", "Daemon", - "Talon" + "Talon", ) private fun randomDiadochiName(isFemale: Boolean) = (if (isFemale) diadochiFemaleNames else diadochiMaleNames).random() + " " + diadochiEpithetParts.random() + diadochiEpithetParts.random().lowercase() private val thedishMaleNames = listOf( - "Prethoris", + "Praethoris", "Severus", "Augast", "Dagobar", @@ -313,7 +313,9 @@ object AdmiralNames { "Toval", "Ivon", "Belis", - "Jorh" + "Jorh", + "Svar", + "Alaric", ) private val thedishFemaleNames = listOf( @@ -330,6 +332,7 @@ object AdmiralNames { "Amberli", "Alysia", "Lenera", + "Demeter", ) private val thedishSurnames = listOf( @@ -349,7 +352,10 @@ object AdmiralNames { "Arvi", "Galvus", "Voss", - "Mandanof" + "Mandanof", + "Ursali", + "Vytunn", + "Quesrinn", ) private fun randomThedishName(isFemale: Boolean) = (if (isFemale) thedishFemaleNames else thedishMaleNames).random() + " " + thedishSurnames.random() diff --git a/src/jvmMain/kotlin/starshipfights/data/admiralty/ship_names.kt b/src/jvmMain/kotlin/starshipfights/data/admiralty/ship_names.kt index 507d086..ac20715 100644 --- a/src/jvmMain/kotlin/starshipfights/data/admiralty/ship_names.kt +++ b/src/jvmMain/kotlin/starshipfights/data/admiralty/ship_names.kt @@ -253,6 +253,7 @@ object ShipNames { "Catonsville", "Ocean City", "Philadelphia", + "Somerset", "Pittsburgh", "Las Vegas", diff --git a/src/jvmMain/kotlin/starshipfights/data/auth/user_trophies.kt b/src/jvmMain/kotlin/starshipfights/data/auth/user_trophies.kt index a2885e5..303b5c0 100644 --- a/src/jvmMain/kotlin/starshipfights/data/auth/user_trophies.kt +++ b/src/jvmMain/kotlin/starshipfights/data/auth/user_trophies.kt @@ -36,7 +36,7 @@ object SiteDeveloperTrophy : UserTrophy() { override fun ASIDE.render() { p { style = "text-align:center;border:2px solid #62a;padding:3px;background-color:#93f;color:#315;font-variant:small-caps;font-family:'Orbitron',sans-serif" - title = "This person helps with coding the site" + title = "This person helps with coding the game" +"Site Developer" } } @@ -80,9 +80,11 @@ data class SiteSupporterTrophy(val amountInUsCents: Int) : UserTrophy() { get() = 3 } -fun User.getTrophies(): List = +fun User.getTrophiesUnsorted(): Set = (if (discordId == CurrentConfiguration.discordClient?.ownerId) - listOf(SiteOwnerTrophy) - else emptyList()) + (if (amountDonatedInUsCents > 0) - listOf(SiteSupporterTrophy(amountDonatedInUsCents)) - else emptyList()) + setOf(SiteOwnerTrophy) + else emptySet()) + (if (amountDonatedInUsCents > 0) + setOf(SiteSupporterTrophy(amountDonatedInUsCents)) + else emptySet()) + +fun User.getTrophies(): List = getTrophiesUnsorted().sorted() diff --git a/src/jvmMain/kotlin/starshipfights/info/views_error.kt b/src/jvmMain/kotlin/starshipfights/info/views_error.kt index da89eeb..83f9bc2 100644 --- a/src/jvmMain/kotlin/starshipfights/info/views_error.kt +++ b/src/jvmMain/kotlin/starshipfights/info/views_error.kt @@ -40,6 +40,14 @@ suspend fun ApplicationCall.error404(): HTML.() -> Unit = page("Not Found", stan devModeCallId(callId) } +suspend fun ApplicationCall.error429(): HTML.() -> Unit = page("Too Many Requests", standardNavBar()) { + section { + h1 { +"Too Many Requests" } + p { +"Our server is being bogged down in a quagmire of HTTP requests. Please try again later." } + } + devModeCallId(callId) +} + suspend fun ApplicationCall.error503(): HTML.() -> Unit = page("Internal Error", standardNavBar()) { section { h1 { +"Internal Error" } diff --git a/src/jvmMain/kotlin/starshipfights/info/views_user.kt b/src/jvmMain/kotlin/starshipfights/info/views_user.kt index b337c4a..807927f 100644 --- a/src/jvmMain/kotlin/starshipfights/info/views_user.kt +++ b/src/jvmMain/kotlin/starshipfights/info/views_user.kt @@ -10,7 +10,7 @@ import org.litote.kmongo.and import org.litote.kmongo.eq import org.litote.kmongo.gt import org.litote.kmongo.or -import starshipfights.ForbiddenException +import starshipfights.forbid import starshipfights.auth.* import starshipfights.data.Id import starshipfights.data.admiralty.* @@ -558,7 +558,7 @@ suspend fun ApplicationCall.manageAdmiralPage(): HTML.() -> Unit { val admiralId = parameters["id"]?.let { Id(it) }!! val admiral = Admiral.get(admiralId)!! - if (admiral.owningUser != currentUser) throw ForbiddenException() + if (admiral.owningUser != currentUser) forbid() val ownedShips = ShipInDrydock.filter(ShipInDrydock::owningAdmiral eq admiralId).toList() @@ -640,7 +640,7 @@ suspend fun ApplicationCall.manageAdmiralPage(): HTML.() -> Unit { section { h2 { +"Manage Fleet" } p { - +"${admiral.fullName} currently owns ${admiral.money} ${admiral.faction.currencyName}s, and earns ${admiral.rank.dailyWage} ${admiral.faction.currencyName}s every day." + +"${admiral.fullName} currently owns ${admiral.money} ${admiral.faction.currencyName}, and earns ${admiral.rank.dailyWage} ${admiral.faction.currencyName}s every day." } table { tr { @@ -679,7 +679,6 @@ suspend fun ApplicationCall.manageAdmiralPage(): HTML.() -> Unit { +ship.shipType.weightClass.sellPrice.toString() +" " +admiral.faction.currencyName - +"s" if (ship.status == DrydockStatus.Ready && !ship.shipType.weightClass.isUnique) { br a(href = "/admiral/${admiralId}/sell/${ship.id}") { +"Sell" } @@ -703,7 +702,6 @@ suspend fun ApplicationCall.manageAdmiralPage(): HTML.() -> Unit { +st.weightClass.buyPrice.toString() +" " +admiral.faction.currencyName - +"s" br a(href = "/admiral/${admiralId}/buy/${st.toUrlSlug()}") { +"Buy" } } @@ -727,8 +725,8 @@ suspend fun ApplicationCall.renameShipPage(): HTML.() -> Unit { admiral.await() to ship.await() } - if (admiral.owningUser != currentUser) throw ForbiddenException() - if (ship.owningAdmiral != admiralId) throw ForbiddenException() + if (admiral.owningUser != currentUser) forbid() + if (ship.owningAdmiral != admiralId) forbid() return page("Renaming Ship", null, null) { section { @@ -777,8 +775,8 @@ suspend fun ApplicationCall.sellShipConfirmPage(): HTML.() -> Unit { admiral.await() to ship.await() } - if (admiral.owningUser != currentUser) throw ForbiddenException() - if (ship.owningAdmiral != admiralId) throw ForbiddenException() + if (admiral.owningUser != currentUser) forbid() + if (ship.owningAdmiral != admiralId) forbid() if (ship.status != DrydockStatus.Ready) redirect("/admiral/${admiralId}/manage") if (ship.shipType.weightClass.isUnique) redirect("/admiral/${admiralId}/manage") @@ -789,7 +787,7 @@ suspend fun ApplicationCall.sellShipConfirmPage(): HTML.() -> Unit { section { h1 { +"Are You Sure?" } p { - +"${admiral.fullName} is about to sell the ${ship.shipType.fullDisplayName} ${ship.shipData.fullName} for ${ship.shipType.weightClass.sellPrice} ${admiral.faction.currencyName}s." + +"${admiral.fullName} is about to sell the ${ship.shipType.fullDisplayName} ${ship.shipData.fullName} for ${ship.shipType.weightClass.sellPrice} ${admiral.faction.currencyName}." } form(method = FormMethod.get, action = "/admiral/${admiral.id}/manage") { submitInput { @@ -813,7 +811,7 @@ suspend fun ApplicationCall.buyShipConfirmPage(): HTML.() -> Unit { val admiralId = parameters["id"]?.let { Id(it) }!! val admiral = Admiral.get(admiralId)!! - if (admiral.owningUser != currentUser) throw ForbiddenException() + if (admiral.owningUser != currentUser) forbid() val shipType = parameters["ship"]?.let { param -> ShipType.values().singleOrNull { it.toUrlSlug() == param } }!! @@ -827,7 +825,7 @@ suspend fun ApplicationCall.buyShipConfirmPage(): HTML.() -> Unit { section { h1 { +"Too Expensive" } p { - +"Unfortunately, the ${shipType.fullDisplayName} is out of ${admiral.fullName}'s budget. It costs ${shipType.weightClass.buyPrice} ${admiral.faction.currencyName}s, and ${admiral.name} only has ${admiral.money} ${admiral.faction.currencyName}s." + +"Unfortunately, the ${shipType.fullDisplayName} is out of ${admiral.fullName}'s budget. It costs ${shipType.weightClass.buyPrice} ${admiral.faction.currencyName}, and ${admiral.name} only has ${admiral.money} ${admiral.faction.currencyName}s." } form(method = FormMethod.get, action = "/admiral/${admiral.id}/manage") { submitInput { @@ -844,7 +842,7 @@ suspend fun ApplicationCall.buyShipConfirmPage(): HTML.() -> Unit { section { h1 { +"Are You Sure?" } p { - +"${admiral.fullName} is about to buy a ${shipType.fullDisplayName} for ${shipType.weightClass.buyPrice} ${admiral.faction.currencyName}s." + +"${admiral.fullName} is about to buy a ${shipType.fullDisplayName} for ${shipType.weightClass.buyPrice} ${admiral.faction.currencyName}." } form(method = FormMethod.get, action = "/admiral/${admiral.id}/manage") { submitInput { @@ -868,7 +866,7 @@ suspend fun ApplicationCall.deleteAdmiralConfirmPage(): HTML.() -> Unit { val admiralId = parameters["id"]?.let { Id(it) }!! val admiral = Admiral.get(admiralId)!! - if (admiral.owningUser != currentUser) throw ForbiddenException() + if (admiral.owningUser != currentUser) forbid() return page( "Are You Sure?", null, null diff --git a/src/jvmMain/kotlin/starshipfights/server.kt b/src/jvmMain/kotlin/starshipfights/server.kt index 49c0c96..3453643 100644 --- a/src/jvmMain/kotlin/starshipfights/server.kt +++ b/src/jvmMain/kotlin/starshipfights/server.kt @@ -73,6 +73,10 @@ fun main() { exception { call.respondHtml(HttpStatusCode.NotFound, call.error404()) } + exception { + call.respondHtml(HttpStatusCode.TooManyRequests, call.error429()) + } + exception { call.respondHtml(HttpStatusCode.InternalServerError, call.error503()) throw it diff --git a/src/jvmMain/kotlin/starshipfights/server_utils.kt b/src/jvmMain/kotlin/starshipfights/server_utils.kt index 8fbd578..3d0b138 100644 --- a/src/jvmMain/kotlin/starshipfights/server_utils.kt +++ b/src/jvmMain/kotlin/starshipfights/server_utils.kt @@ -4,8 +4,12 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory class ForbiddenException : IllegalArgumentException() +fun forbid(): Nothing = throw ForbiddenException() data class HttpRedirectException(val url: String, val permanent: Boolean) : RuntimeException() fun redirect(url: String, permanent: Boolean = false): Nothing = throw HttpRedirectException(url, permanent) +class RateLimitException : RuntimeException() +fun rateLimit(): Nothing = throw RateLimitException() + val sfLogger: Logger = LoggerFactory.getLogger("StarshipFights") diff --git a/src/jvmMain/resources/static/images/embed-logo.png b/src/jvmMain/resources/static/images/embed-logo.png deleted file mode 100644 index b81c35f..0000000 Binary files a/src/jvmMain/resources/static/images/embed-logo.png and /dev/null differ diff --git a/update b/update index f40ecd1..7bd0ef6 100755 --- a/update +++ b/update @@ -2,5 +2,5 @@ screen -S starshipfights -X quit git pull -gradle shadowJar +gradle clean shadowJar screen -dmS starshipfights gradle runShadow