+@file:JvmName("Factbooks")
+
package info.mechyrdia
import info.mechyrdia.lore.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
+import io.ktor.server.sessions.*
+import io.ktor.util.*
import org.slf4j.event.Level
import java.io.File
import java.io.IOException
import java.util.concurrent.atomic.AtomicLong
-object Factbooks {
- @JvmStatic
- fun main(args: Array<String>) {
- System.setProperty("logback.statusListenerClass", "ch.qos.logback.core.status.NopStatusListener")
+fun main() {
+ System.setProperty("logback.statusListenerClass", "ch.qos.logback.core.status.NopStatusListener")
+
+ System.setProperty("io.ktor.development", "false")
+
+ embeddedServer(Netty, port = Configuration.CurrentConfiguration.port, host = Configuration.CurrentConfiguration.host, module = Application::factbooks).start(wait = true)
+}
+
+fun Application.factbooks() {
+ install(IgnoreTrailingSlash)
+ install(XForwardedHeaders)
+
+ install(CallId) {
+ val counter = AtomicLong(0)
+ generate {
+ "call-${counter.incrementAndGet().toULong()}-${System.currentTimeMillis()}"
+ }
+ }
+
+ install(CallLogging) {
+ level = Level.INFO
- System.setProperty("io.ktor.development", "false")
+ callIdMdc("ktor-call-id")
- embeddedServer(Netty, port = Configuration.CurrentConfiguration.port, host = Configuration.CurrentConfiguration.host) {
- install(IgnoreTrailingSlash)
- install(XForwardedHeaders)
-
- install(CallId) {
- val counter = AtomicLong(0)
- generate {
- "call-${counter.incrementAndGet().toULong()}-${System.currentTimeMillis()}"
- }
- }
-
- install(CallLogging) {
- level = Level.INFO
-
- callIdMdc("ktor-call-id")
-
- format { call ->
- "Call #${call.callId} Client ${call.request.origin.remoteHost} `${call.request.userAgent()}` Request ${call.request.httpMethod.value} ${call.request.uri} Response ${call.response.status()}"
- }
- }
+ format { call ->
+ "Call #${call.callId} Client ${call.request.origin.remoteHost} `${call.request.userAgent()}` Request ${call.request.httpMethod.value} ${call.request.uri} Response ${call.response.status()}"
+ }
+ }
+
+ /*
+ install(Sessions) {
+ cookie<UserSession>("USER_SESSION", SessionStorageMongoDB()) {
+ identity { Id<UserSession>().id }
- install(StatusPages) {
- status(HttpStatusCode.NotFound) { call, _ ->
- call.respondHtml(HttpStatusCode.NotFound, call.error404())
- }
-
- exception<HttpRedirectException> { call, (url, permanent) ->
- call.respondRedirect(url, permanent)
- }
- exception<MissingRequestParameterException> { call, _ ->
- call.respondHtml(HttpStatusCode.BadRequest, call.error400())
- }
- exception<NullPointerException> { call, _ ->
- call.respondHtml(HttpStatusCode.NotFound, call.error404())
- }
- exception<IOException> { call, _ ->
- call.respondHtml(HttpStatusCode.NotFound, call.error404())
- }
-
- exception<Throwable> { call, ex ->
- call.application.log.error("Got uncaught exception from serving call ${call.callId}", ex)
-
- call.respondHtml(HttpStatusCode.InternalServerError, call.error500())
- throw ex
- }
- }
+ cookie.extensions["SameSite"] = "lax"
+ cookie.extensions["Secure"] = null
+ }
+ }
+ */
+
+ install(StatusPages) {
+ status(HttpStatusCode.NotFound) { call, _ ->
+ call.respondHtml(HttpStatusCode.NotFound, call.error404())
+ }
+
+ exception<HttpRedirectException> { call, (url, permanent) ->
+ call.respondRedirect(url, permanent)
+ }
+ exception<MissingRequestParameterException> { call, _ ->
+ call.respondHtml(HttpStatusCode.BadRequest, call.error400())
+ }
+ exception<NullPointerException> { call, _ ->
+ call.respondHtml(HttpStatusCode.NotFound, call.error404())
+ }
+ exception<IOException> { call, _ ->
+ call.respondHtml(HttpStatusCode.NotFound, call.error404())
+ }
+
+ exception<Throwable> { call, ex ->
+ call.application.log.error("Got uncaught exception from serving call ${call.callId}", ex)
- routing {
- get("/") {
- redirect("/lore")
- }
-
- static("/static") {
- resources("static")
- }
-
- get("/lore/{path...}") {
- call.respondHtml(HttpStatusCode.OK, call.loreArticlePage())
- }
-
- static("/assets") {
- files(File(Configuration.CurrentConfiguration.assetDir))
- }
-
- get("/change-theme") {
- call.respondHtml(HttpStatusCode.OK, call.changeThemePage())
- }
-
- post("/change-theme") {
- val newTheme = when (call.receiveParameters()["theme"]) {
- "light" -> "light"
- "dark" -> "dark"
- else -> "system"
- }
- call.response.cookies.append("factbook-theme", newTheme, maxAge = Int.MAX_VALUE.toLong())
- redirect("/lore")
- }
-
- post("/tylan-lang") {
- call.respondText(TylanAlphabet.tylanToFontAlphabet(call.receiveText()))
- }
+ call.respondHtml(HttpStatusCode.InternalServerError, call.error500())
+ throw ex
+ }
+ }
+
+ routing {
+ get("/") {
+ redirect("/lore")
+ }
+
+ static("/static") {
+ resources("static")
+ }
+
+ get("/lore/{path...}") {
+ call.respondHtml(HttpStatusCode.OK, call.loreArticlePage())
+ }
+
+ static("/assets") {
+ files(File(Configuration.CurrentConfiguration.assetDir))
+ }
+
+ get("/change-theme") {
+ call.respondHtml(HttpStatusCode.OK, call.changeThemePage())
+ }
+
+ post("/change-theme") {
+ val newTheme = when (call.receiveParameters()["theme"]) {
+ "light" -> "light"
+ "dark" -> "dark"
+ else -> "system"
}
- }.start(wait = true)
+ call.response.cookies.append("factbook-theme", newTheme, maxAge = Int.MAX_VALUE.toLong())
+ redirect("/lore")
+ }
+
+ post("/tylan-lang") {
+ call.respondText(TylanAlphabet.tylanToFontAlphabet(call.receiveText()))
+ }
}
}
border-bottom-color: var(--err-ul);
}
-input[type=submit] {
+button, input[type=submit] {
background-color: var(--btn-bg);
border: none;
border-radius: 0.3em;
padding: 0.85em 1.15em;
}
-input[type=submit]:hover {
+button:hover, input[type=submit]:hover {
background-color: var(--btn-h-bg);
}
-input[type=submit]:active {
+button:active, input[type=submit]:active {
background-color: var(--btn-a-bg);
}
-input[type=submit].evil {
+button.evil, input[type=submit].evil {
background-color: var(--evil-btn-bg);
border: none;
border-radius: 0.3em;
padding: 0.85em 1.15em;
}
-input[type=submit].evil:hover {
+button.evil:hover, input[type=submit].evil:hover {
background-color: var(--evil-btn-h-bg);
}
-input[type=submit].evil:active {
+button.evil:active, input[type=submit].evil:active {
background-color: var(--evil-btn-a-bg);
}
+button:disabled,
+button.evil:disabled,
input[type=submit]:disabled,
input[type=submit].evil:disabled {
background-color: var(--btn-na-bg);