Skip to content

Commit

Permalink
feature: Not found page and better default page determination
Browse files Browse the repository at this point in the history
  • Loading branch information
LichtHund committed Jul 6, 2024
1 parent 96fca20 commit 5eb41f3
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 9 deletions.
12 changes: 12 additions & 0 deletions backend/src/main/kotlin/Module.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@ package dev.triumphteam.backend
import dev.triumphteam.backend.api.apiRoutes
import dev.triumphteam.backend.api.auth.TriumphPrincipal
import dev.triumphteam.backend.meilisearch.Meili
import dev.triumphteam.backend.website.pages.respondNotFound
import dev.triumphteam.backend.website.websiteRoutes
import dev.triumphteam.website.JsonSerializer
import io.ktor.http.CacheControl
import io.ktor.http.ContentType
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpMethod
import io.ktor.http.HttpStatusCode
import io.ktor.http.content.CachingOptions
import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.application.Application
import io.ktor.server.application.install
import io.ktor.server.auth.Authentication
import io.ktor.server.auth.bearer
import io.ktor.server.html.respondHtml
import io.ktor.server.http.content.staticFiles
import io.ktor.server.http.content.staticResources
import io.ktor.server.plugins.cachingheaders.CachingHeaders
Expand All @@ -24,7 +27,10 @@ import io.ktor.server.plugins.cors.routing.CORS
import io.ktor.server.plugins.defaultheaders.DefaultHeaders
import io.ktor.server.plugins.forwardedheaders.ForwardedHeaders
import io.ktor.server.plugins.forwardedheaders.XForwardedHeaders
import io.ktor.server.plugins.statuspages.StatusPages
import io.ktor.server.resources.Resources
import io.ktor.server.response.respondRedirect
import io.ktor.server.response.respondText
import io.ktor.server.routing.routing

/** Module of the application. */
Expand All @@ -37,6 +43,12 @@ public fun Application.module() {
else -> propertyValue
}

install(StatusPages) {
status(HttpStatusCode.NotFound) { call, status ->
call.respondRedirect("/404")
}
}

install(Resources)
install(ContentNegotiation) {
json(JsonSerializer.json)
Expand Down
1 change: 1 addition & 0 deletions backend/src/main/kotlin/api/ProjectSetup.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public suspend fun setupRepository(meili: Meili, projects: File) {
this.navigation = version.navigation
this.stable = version.stable
this.recommended = version.recommended
this.defaultPage = version.pages.find { it.default }?.id ?: error("Could not find default page.")
}

val versionFolder = DATA_FOLDER.resolve("core/${project.id}/${version.reference}").also {
Expand Down
2 changes: 2 additions & 0 deletions backend/src/main/kotlin/api/database/Entities.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public object DocVersions : IntIdTable("docs_version") {
public val navigation: Column<Navigation> = serializable<Navigation>("navigation")
public val stable: Column<Boolean> = bool("stable")
public val recommended: Column<Boolean> = bool("recommended")
public val defaultPage: Column<String> = varchar("default_page", 255)

init {
uniqueIndex("ref_project_uq", reference, project)
Expand Down Expand Up @@ -67,6 +68,7 @@ public class DocVersionEntity(id: EntityID<Int>) : IntEntity(id) {
public var navigation: Navigation by DocVersions.navigation
public var stable: Boolean by DocVersions.stable
public var recommended: Boolean by DocVersions.recommended
public var defaultPage: String by DocVersions.defaultPage
}

public class PageEntity(id: EntityID<Int>) : IntEntity(id) {
Expand Down
10 changes: 10 additions & 0 deletions backend/src/main/kotlin/website/WebsiteRoutes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,22 @@ package dev.triumphteam.backend.website
import dev.triumphteam.backend.meilisearch.Meili
import dev.triumphteam.backend.website.pages.docs.docsRoutes
import dev.triumphteam.backend.website.pages.home.homeRoutes
import dev.triumphteam.backend.website.pages.respondNotFound
import io.ktor.server.application.call
import io.ktor.server.application.plugin
import io.ktor.server.html.respondHtml
import io.ktor.server.routing.Routing
import io.ktor.server.routing.get

public fun Routing.websiteRoutes(developmentMode: Boolean) {
val meili = plugin(Meili)

homeRoutes(developmentMode)
docsRoutes(meili, developmentMode)

get("404") {
call.respondHtml {
respondNotFound(call.application.developmentMode)
}
}
}
46 changes: 46 additions & 0 deletions backend/src/main/kotlin/website/pages/NotFound.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package dev.triumphteam.backend.website.pages

import kotlinx.css.h1
import kotlinx.html.HTML
import kotlinx.html.body
import kotlinx.html.classes
import kotlinx.html.div
import kotlinx.html.h1
import kotlinx.html.meta
import kotlinx.html.title

public fun HTML.respondNotFound(developmentMode: Boolean) {
setupHead(developmentMode) {
meta {
name = "og:type"
content = "article"
}

meta {
name = "og:title"
content = "TriumphTeam"
}

meta {
name = "og:image"
// TODO: Replace with final URL, sucks that it can't be relative
content = "https://new.triumphteam.dev/static/images/banner_not_found.png"
}

title("TriumphTeam")
}

body {

classes = setOf(
"w-screen h-screen",
"bg-docs-bg",
"text-[20em] text-white/50",
"flex justify-center items-center",
)

h1 {
+"404"
}
}
}
8 changes: 5 additions & 3 deletions backend/src/main/kotlin/website/pages/docs/DocsPage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,12 @@ public fun Routing.docsRoutes(meili: Meili, developmentMode: Boolean) {

val pages = currentVersion.pages
val page = when {
paramPage != null -> pages[paramPage] ?: return@get call.respond(HttpStatusCode.NotFound)
!paramPage.isNullOrEmpty() -> pages[paramPage] ?: return@get call.respond(HttpStatusCode.NotFound)
else -> {
// If the page doesn't exist, redirect to 404
val page = pages.values.firstOrNull() ?: return@get call.respond(HttpStatusCode.NotFound)
val page = pages[currentVersion.defaultPage] ?: return@get call.respond(HttpStatusCode.NotFound)
// If exist redirect to default
return@get call.respondRedirect("${call.request.uri}/${page.id}")
return@get call.respondRedirect("${call.request.uri.removeSuffix("/")}/${page.id}")
}
}

Expand Down Expand Up @@ -511,6 +511,7 @@ private fun getProject(project: String): ProjectData? {
reference = entity.reference,
navigation = entity.navigation,
stable = entity.stable,
defaultPage = entity.defaultPage,
pages = PageEntity.find { (Pages.project eq projectEntity.id) and (Pages.version eq entity.id) }
.map { pageEntity ->
ProjectPage(
Expand Down Expand Up @@ -550,6 +551,7 @@ public data class Version(
public val navigation: Navigation,
public val stable: Boolean,
public val pages: Map<String, ProjectPage>,
public val defaultPage: String,
) {

public data class Data(public val reference: String, public val stable: Boolean)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions common/src/main/kotlin/project/SerialRepresentation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public data class Page(
public val content: String,
public val path: String,
public val description: Description,
public val default: Boolean,
) {

@Serializable
Expand Down
14 changes: 9 additions & 5 deletions docs/src/main/kotlin/Application.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import dev.triumphteam.website.docs.markdown.hint.HintExtension
import dev.triumphteam.website.docs.markdown.summary.SummaryExtractor
import dev.triumphteam.website.docs.markdown.tab.TabExtension
import dev.triumphteam.website.docs.serialization.GroupConfig
import dev.triumphteam.website.docs.serialization.PageConfig
import dev.triumphteam.website.docs.serialization.ProjectConfig
import dev.triumphteam.website.docs.serialization.RepoSettings
import dev.triumphteam.website.docs.serialization.VersionConfig
Expand Down Expand Up @@ -208,9 +207,9 @@ private fun parseVersions(versionDirs: List<File>, parentDir: File, repoSettings
navigationCollector.collect(Navigation.Group(parsedGroupConfig.header, parsedGroupConfig.mapPages()))

val filesMap = groupFiles.associateBy(File::nameWithoutExtension)
parsedGroupConfig.pages.map(PageConfig::link).forEach { link ->
val pageFile = requireNotNull(filesMap[link]) {
"Could not find file named '$link', make sure the file is created before adding it to the group config."
parsedGroupConfig.pages.forEach { page ->
val pageFile = requireNotNull(filesMap[page.link]) {
"Could not find file named '${page.link}', make sure the file is created before adding it to the group config."
}

if (pageFile.nameWithoutExtension.contains(" ")) {
Expand All @@ -233,6 +232,7 @@ private fun parseVersions(versionDirs: List<File>, parentDir: File, repoSettings
group = parsedGroupConfig.header,
summary = summaryExtractor.extract(parsedFile),
),
default = page.default,
)
)
}
Expand All @@ -243,7 +243,11 @@ private fun parseVersions(versionDirs: List<File>, parentDir: File, repoSettings
recommended = parsedVersionConfig.recommended,
stable = parsedVersionConfig.stable,
navigation = navigationCollector.collection(),
pages = pageCollector.collection(),
pages = pageCollector.collection().also { pages ->
require(pages.count { it.default } == 1) {
"Versions must have 1 and only 1 default page."
}
},
)
}.also { docVersions ->
require(docVersions.count(DocVersion::recommended) == 1) {
Expand Down
2 changes: 1 addition & 1 deletion docs/src/main/kotlin/serialization/FileRepresentation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ public data class GroupConfig(public val header: String, public val pages: List<
}

@Serializable
public data class PageConfig(public val header: String, public val link: String)
public data class PageConfig(public val header: String, public val link: String, public val default: Boolean = false)
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ ktor-server-caching-headers = { module = "io.ktor:ktor-server-caching-headers-jv
ktor-server-html = { module = "io.ktor:ktor-server-html-builder", version.ref = "ktor" }
ktor-server-css = { module = "org.jetbrains.kotlin-wrappers:kotlin-css", version.ref = "ktor-css" }
ktor-server-default-headers = { module = "io.ktor:ktor-server-default-headers-jvm", version.ref = "ktor" }
ktor-server-status-pages = { module = "io.ktor:ktor-server-status-pages", version.ref = "ktor" }

# Common
ktor-resources = { module = "io.ktor:ktor-resources", version.ref = "ktor" }
Expand Down Expand Up @@ -109,6 +110,7 @@ ktor-server = [
"ktor-server-caching-headers",
"ktor-server-default-headers",
"ktor-server-css",
"ktor-server-status-pages",
]
ktor-client = [
"ktor-client-core",
Expand Down

0 comments on commit 5eb41f3

Please sign in to comment.