Various QoL improvements and refactorings
authorTheSaminator <TheSaminator@users.noreply.github.com>
Mon, 28 Feb 2022 22:34:56 +0000 (17:34 -0500)
committerTheSaminator <TheSaminator@users.noreply.github.com>
Mon, 28 Feb 2022 22:34:56 +0000 (17:34 -0500)
src/jvmMain/kotlin/starshipfights/auth/providers.kt
src/jvmMain/kotlin/starshipfights/auth/ratelimit.kt
src/jvmMain/kotlin/starshipfights/auth/utils.kt
src/jvmMain/kotlin/starshipfights/info/views_user.kt

index caf1697ae1dc78e8da75e1e026fb77f2f4e88fac..a075e708e06746c57c6ebce40b67224a6a44ceff 100644 (file)
@@ -19,17 +19,21 @@ import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.flow.toList
 import kotlinx.coroutines.launch
 import kotlinx.html.*
-import kotlinx.serialization.json.JsonObject
-import kotlinx.serialization.json.JsonPrimitive
+import kotlinx.serialization.Serializable
 import org.litote.kmongo.*
-import starshipfights.*
+import starshipfights.CurrentConfiguration
+import starshipfights.DiscordLogin
 import starshipfights.data.Id
 import starshipfights.data.admiralty.*
 import starshipfights.data.auth.User
 import starshipfights.data.auth.UserSession
 import starshipfights.data.createNonce
-import starshipfights.game.*
+import starshipfights.forbid
+import starshipfights.game.Faction
+import starshipfights.game.ShipType
+import starshipfights.game.toUrlSlug
 import starshipfights.info.*
+import starshipfights.redirect
 import java.time.Instant
 import java.time.temporal.ChronoUnit
 
@@ -501,7 +505,9 @@ class ProductionAuthProvider(private val discordLogin: DiscordLogin) : AuthProvi
                        agent = discordLogin.userAgent
                }
                
-               install(RateLimit)
+               install(RateLimit) {
+                       jsonCodec = JsonClientCodec
+               }
        }
        
        override fun installAuth(conf: Authentication.Configuration) {
@@ -563,11 +569,8 @@ class ProductionAuthProvider(private val discordLogin: DiscordLogin) : AuthProvi
                                                }
                                        }
                                        
-                                       val userInfo = JsonConfigCodec.parseToJsonElement(userInfoJson) as? JsonObject ?: redirect("/login")
-                                       val discordId = (userInfo["id"] as? JsonPrimitive)?.content ?: redirect("/login")
-                                       val discordUsername = (userInfo["username"] as? JsonPrimitive)?.content ?: redirect("/login")
-                                       val discordDiscriminator = (userInfo["discriminator"] as? JsonPrimitive)?.content ?: redirect("/login")
-                                       val discordAvatar = (userInfo["avatar"] as? JsonPrimitive)?.content
+                                       val userInfo = JsonClientCodec.decodeFromString(DiscordUserInfo.serializer(), userInfoJson)
+                                       val (discordId, discordUsername, discordDiscriminator, discordAvatar) = userInfo
                                        
                                        var redirectTo = "/me"
                                        
@@ -591,7 +594,7 @@ class ProductionAuthProvider(private val discordLogin: DiscordLogin) : AuthProvi
                                        
                                        val userSession = UserSession(
                                                user = user.id,
-                                               clientAddresses = listOf(call.request.origin.remoteHost),
+                                               clientAddresses = if (user.logIpAddresses) listOf(call.request.origin.remoteHost) else emptyList(),
                                                userAgent = userAgent,
                                                expiration = Instant.now().plus(1, ChronoUnit.HOURS)
                                        )
@@ -620,3 +623,11 @@ object StateParameterManager : NonceManager {
                return nonces.remove(nonce)
        }
 }
+
+@Serializable
+data class DiscordUserInfo(
+       val id: String,
+       val username: String,
+       val discriminator: String,
+       val avatar: String
+)
index 6440690c1ba74479fd6afb45ff9cd86a791ae51f..e33959851427df0cc415828e1c6d6f88a54d30f8 100644 (file)
@@ -67,6 +67,5 @@ class RateLimit(
 data class RateLimitedResponse(
        val message: String,
        @SerialName("retry_after")
-       val retryAfter: Double,
-       val global: Boolean
+       val retryAfter: Double
 )
index 9c9c1ef4ba09847a5c62155a88c1e9d4ea1574e7..98082482487ce07a076a90cbebf3501ad16eec97 100644 (file)
@@ -6,6 +6,7 @@ import io.ktor.http.*
 import io.ktor.request.*
 import io.ktor.sessions.*
 import io.ktor.util.*
+import kotlinx.serialization.json.Json
 import starshipfights.forbid
 import starshipfights.data.Id
 import starshipfights.data.auth.User
@@ -20,7 +21,7 @@ suspend fun Id<UserSession>.resolve(userAgent: String) = UserSession.get(this)?.
 }
 
 suspend fun UserSession.renewed(clientAddress: String) = copy(
-       expiration = Instant.now().plus(1, ChronoUnit.HOURS),
+       expiration = Instant.now().plus(2, ChronoUnit.HOURS),
        clientAddresses = if (User.get(user)?.logIpAddresses != true)
                emptyList()
        else if (clientAddresses.lastOrNull() != clientAddress)
@@ -75,3 +76,7 @@ suspend fun ApplicationCall.receiveValidatedParameters(): Parameters {
        else
                forbid()
 }
+
+val JsonClientCodec = Json {
+       ignoreUnknownKeys = true
+}
index 610b1d5e8a706d1a44858dc9f8492c0505644bf6..a81ccb608c87e87e7c4b00289543093f853312e0 100644 (file)
@@ -10,11 +10,11 @@ import org.litote.kmongo.and
 import org.litote.kmongo.eq
 import org.litote.kmongo.gt
 import org.litote.kmongo.or
-import starshipfights.forbid
 import starshipfights.auth.*
 import starshipfights.data.Id
 import starshipfights.data.admiralty.*
 import starshipfights.data.auth.*
+import starshipfights.forbid
 import starshipfights.game.*
 import starshipfights.redirect
 import java.time.Instant
@@ -637,6 +637,32 @@ suspend fun ApplicationCall.manageAdmiralPage(): HTML.() -> Unit {
                                }
                        }
                }
+               section {
+                       val currRank = admiral.rank
+                       if (currRank.ordinal < AdmiralRank.values().size - 1) {
+                               val nextRank = AdmiralRank.values()[currRank.ordinal + 1]
+                               val reqAcumen = nextRank.minAcumen - currRank.minAcumen
+                               val hasAcumen = admiral.acumen - currRank.minAcumen
+                               
+                               label {
+                                       h2 { +"Progress to Promotion" }
+                                       progress {
+                                               style = "width:100%;box-sizing:border-box"
+                                               max = "$reqAcumen"
+                                               value = "$hasAcumen"
+                                               +"$hasAcumen/$reqAcumen"
+                                       }
+                               }
+                               p {
+                                       +"${admiral.fullName} is $hasAcumen/$reqAcumen Acumen away from being promoted to ${nextRank.getDisplayName(admiral.faction)}"
+                               }
+                       } else {
+                               h2 { +"Progress to Promotion" }
+                               p {
+                                       +"${admiral.fullName} is at the maximum rank possible for the ${admiral.faction.navyName}."
+                               }
+                       }
+               }
                section {
                        h2 { +"Manage Fleet" }
                        p {