Add embed data
authorTheSaminator <TheSaminator@users.noreply.github.com>
Sun, 20 Feb 2022 18:23:12 +0000 (13:23 -0500)
committerTheSaminator <TheSaminator@users.noreply.github.com>
Sun, 20 Feb 2022 18:23:12 +0000 (13:23 -0500)
src/jvmMain/kotlin/starshipfights/auth/providers.kt
src/jvmMain/kotlin/starshipfights/info/html_metadata.kt [new file with mode: 0644]
src/jvmMain/kotlin/starshipfights/info/html_utils.kt
src/jvmMain/kotlin/starshipfights/info/view_tpl.kt
src/jvmMain/kotlin/starshipfights/info/views_error.kt
src/jvmMain/kotlin/starshipfights/info/views_main.kt
src/jvmMain/kotlin/starshipfights/info/views_ships.kt
src/jvmMain/kotlin/starshipfights/info/views_user.kt
src/jvmMain/kotlin/starshipfights/server_conf.kt
src/jvmMain/resources/static/images/embed-logo.png [new file with mode: 0644]

index 56ded5a0894b15c72ba302f026770394914aa2b7..b3599a1082a53046905d211f4bc4424870bfa1ae 100644 (file)
@@ -438,9 +438,9 @@ object TestAuthProvider : AuthProvider {
                                
                                val errorMsg = call.request.queryParameters["error"]
                                
-                               call.respondHtml(HttpStatusCode.OK, page("Authentication Test", call.standardNavBar(), CustomSidebar {
+                               call.respondHtml(HttpStatusCode.OK, call.page("Authentication Test", call.standardNavBar(), CustomSidebar {
                                        p {
-                                               +"This instance does not have Discord OAuth login set up. As a fallback, this authentication mode is used for testing."
+                                               +"This instance does not have Discord OAuth login set up. As a fallback, this authentication mode is used for testing only."
                                        }
                                }) {
                                        section {
@@ -516,7 +516,7 @@ class ProductionAuthProvider(private val discordLogin: DiscordLogin) : AuthProvi
                        get("/login") {
                                val errorMsg = call.request.queryParameters["error"]
                                
-                               call.respondHtml(HttpStatusCode.OK, page("Login with Discord", call.standardNavBar(), null) {
+                               call.respondHtml(HttpStatusCode.OK, call.page("Login with Discord", call.standardNavBar()) {
                                        section {
                                                p {
                                                        style = "text-align:center"
diff --git a/src/jvmMain/kotlin/starshipfights/info/html_metadata.kt b/src/jvmMain/kotlin/starshipfights/info/html_metadata.kt
new file mode 100644 (file)
index 0000000..2d96c7d
--- /dev/null
@@ -0,0 +1,47 @@
+package starshipfights.info
+
+import kotlinx.html.HEAD
+
+data class PageMetadata(
+       val title: String,
+       val description: String,
+       val type: PageMetadataType,
+) {
+       companion object {
+               val default = PageMetadata(
+                       title = "Starship Fights",
+                       description = "Starship Fights is a space fleet battle game. Choose your allegiance, create your admiral, build up your fleet, and destroy your enemies' fleets with it!",
+                       type = PageMetadataType.Website,
+               )
+       }
+}
+
+sealed class PageMetadataType {
+       object Website : PageMetadataType()
+       
+       data class Profile(
+               val name: String,
+               val isFemale: Boolean?,
+       ) : PageMetadataType()
+}
+
+fun HEAD.metadata(pageMetadata: PageMetadata, url: String) {
+       when (pageMetadata.type) {
+               is PageMetadataType.Profile -> {
+                       metaOG("og:type", "profile")
+                       metaOG("og:profile:username", pageMetadata.type.name)
+                       pageMetadata.type.isFemale?.let {
+                               metaOG("og:profile:gender", if (it) "female" else "male")
+                       }
+               }
+               PageMetadataType.Website -> {
+                       metaOG("og:type", "website")
+               }
+       }
+       
+       metaOG("og:title", pageMetadata.title)
+       metaOG("og:description", pageMetadata.description)
+       metaOG("og:site_name", "Starship Fights")
+       metaOG("og:url", url)
+       metaOG("og:image", "https://starshipfights.net/static/images/embed-logo.png")
+}
index 881ff9ed57192095fe562a703f11ff6ee9f25246..17f6d6feb87ae992f39cebb50028cc233cc89062 100644 (file)
@@ -1,8 +1,6 @@
 package starshipfights.info
 
-import kotlinx.html.A
-import kotlinx.html.FORM
-import kotlinx.html.hiddenInput
+import kotlinx.html.*
 import starshipfights.auth.CsrfProtector
 import starshipfights.data.Id
 import starshipfights.data.auth.UserSession
@@ -24,3 +22,17 @@ fun FORM.csrfToken(cookie: Id<UserSession>) = hiddenInput {
        name = CsrfProtector.csrfInputName
        value = CsrfProtector.newNonce(cookie, this@csrfToken.action)
 }
+
+var META.property: String?
+       get() = attributes["property"]
+       set(value) {
+               if (value != null)
+                       attributes["property"] = value
+               else
+                       attributes.remove("property")
+       }
+
+fun HEAD.metaOG(property: String, content: String) = meta {
+       this.property = property
+       this.content = content
+}
index 8ebbd3bd9e3712af6a6c00e6efcb4fc969d54043..aed4f316455e96f96c6aeae5cd873a17a16d841d 100644 (file)
@@ -1,11 +1,15 @@
 package starshipfights.info
 
+import io.ktor.application.*
+import io.ktor.util.*
 import kotlinx.html.*
 
-fun page(pageTitle: String?, navBar: List<NavItem>?, sidebar: Sidebar?, content: MAIN.() -> Unit): HTML.() -> Unit = {
+fun ApplicationCall.page(pageTitle: String? = null, navBar: List<NavItem>? = null, sidebar: Sidebar? = null, pageData: PageMetadata = PageMetadata.default, content: MAIN.() -> Unit): HTML.() -> Unit = {
        head {
                meta(charset = "utf-8")
                
+               metadata(pageData, url())
+               
                link(rel = "icon", type = "image/svg+xml", href = "/static/images/icon.svg")
                link(rel = "preconnect", href = "https://fonts.googleapis.com")
                link(rel = "preconnect", href = "https://fonts.gstatic.com") { attributes["crossorigin"] = "anonymous" }
index 3625d5fe5ecb4bdb54f1678f6cafe7a69a914ce3..da89eeb95dc93499eab72c73ae043cc5c593f8e6 100644 (file)
@@ -16,7 +16,7 @@ private fun MAIN.devModeCallId(callId: String?) {
        }
 }
 
-suspend fun ApplicationCall.error400(): HTML.() -> Unit = page("Bad Request", standardNavBar(), IndexSidebar) {
+suspend fun ApplicationCall.error400(): HTML.() -> Unit = page("Bad Request", standardNavBar()) {
        section {
                h1 { +"Bad Request" }
                p { +"The request your browser sent was improperly formatted." }
@@ -24,7 +24,7 @@ suspend fun ApplicationCall.error400(): HTML.() -> Unit = page("Bad Request", st
        devModeCallId(callId)
 }
 
-suspend fun ApplicationCall.error403(): HTML.() -> Unit = page("Not Allowed", standardNavBar(), IndexSidebar) {
+suspend fun ApplicationCall.error403(): HTML.() -> Unit = page("Not Allowed", standardNavBar()) {
        section {
                h1 { +"Not Allowed" }
                p { +"You are not allowed to do that." }
@@ -32,7 +32,7 @@ suspend fun ApplicationCall.error403(): HTML.() -> Unit = page("Not Allowed", st
        devModeCallId(callId)
 }
 
-suspend fun ApplicationCall.error404(): HTML.() -> Unit = page("Not Found", standardNavBar(), IndexSidebar) {
+suspend fun ApplicationCall.error404(): HTML.() -> Unit = page("Not Found", standardNavBar()) {
        section {
                h1 { +"Not Found" }
                p { +"Unfortunately, we could not find what you were looking for." }
@@ -40,7 +40,7 @@ suspend fun ApplicationCall.error404(): HTML.() -> Unit = page("Not Found", stan
        devModeCallId(callId)
 }
 
-suspend fun ApplicationCall.error503(): HTML.() -> Unit = page("Internal Error", standardNavBar(), IndexSidebar) {
+suspend fun ApplicationCall.error503(): HTML.() -> Unit = page("Internal Error", standardNavBar()) {
        section {
                h1 { +"Internal Error" }
                p { +"The servers made a bit of a mistake. Please be patient while we fix our mess." }
index 69b9beee6f59bc7c408634dc0de30a24762b0ef2..e50e48337c7ba1bc3b984682262c453d6250d80b 100644 (file)
@@ -129,7 +129,7 @@ suspend fun ApplicationCall.aboutPage(): HTML.() -> Unit {
 suspend fun ApplicationCall.newUsersPage(): HTML.() -> Unit {
        val newUsers = User.sorted(descending(User::registeredAt)).take(20).toList()
        
-       return page("New Users", standardNavBar(), IndexSidebar) {
+       return page("New Users", standardNavBar()) {
                section {
                        h1 { +"New Users" }
                        div {
index 56734646ebf03c75793e5043a4d05212707c5a8d..44c89fbbeee0d4020933221cffaa33320826f890 100644 (file)
@@ -71,7 +71,16 @@ suspend fun ApplicationCall.shipsPage(): HTML.() -> Unit = page("Game Manual", s
        }
 }
 
-suspend fun ApplicationCall.shipPage(shipType: ShipType): HTML.() -> Unit = page(shipType.fullerDisplayName, standardNavBar(), ShipViewSidebar(shipType)) {
+suspend fun ApplicationCall.shipPage(shipType: ShipType): HTML.() -> Unit = page(
+       shipType.fullerDisplayName,
+       standardNavBar(),
+       ShipViewSidebar(shipType),
+       PageMetadata(
+               shipType.displayName + "-class Starship",
+               "A ${shipType.weightClass.displayName} of the ${shipType.faction.navyName}",
+               PageMetadataType.Website
+       )
+) {
        section {
                h1 { +shipType.fullDisplayName }
                
index b337c4af8f15b65628776264b80207a4412af1c4..57957c840a5cb0a9ba9ba81ac46694bdb602fc14 100644 (file)
@@ -98,7 +98,15 @@ suspend fun ApplicationCall.userPage(): HTML.() -> Unit {
                                        }
                                }
                        }*/
-               }
+               },
+               PageMetadata(
+                       user.profileName,
+                       user.profileBio,
+                       PageMetadataType.Profile(
+                               user.profileName,
+                               null
+                       )
+               )
        ) {
                section {
                        h1 { +user.profileName }
@@ -442,6 +450,14 @@ suspend fun ApplicationCall.admiralPage(): HTML.() -> Unit {
                                        NavLink("/admiral/${admiral.id}/manage", "Manage Admiral")
                                )
                        else emptyList()
+               ),
+               PageMetadata(
+                       admiral.name,
+                       "${admiral.rank.getDisplayName(admiral.faction)} of the ${admiral.faction.navyName}",
+                       PageMetadataType.Profile(
+                               admiral.name,
+                               admiral.isFemale
+                       )
                )
        ) {
                section {
index 59a62301c75933a73974963bfb4a077362ccae4a..d84356f5618b88565997ce0f589f40d9bcd93423 100644 (file)
@@ -24,6 +24,7 @@ data class DiscordLogin(
        val redirectUrlOrigin: String,
        
        val clientId: String,
+       //val clientPubKey: String,
        val clientSecret: String,
        
        val ownerId: String,
diff --git a/src/jvmMain/resources/static/images/embed-logo.png b/src/jvmMain/resources/static/images/embed-logo.png
new file mode 100644 (file)
index 0000000..b81c35f
Binary files /dev/null and b/src/jvmMain/resources/static/images/embed-logo.png differ