diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/FontsController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/FontsController.kt index 7f732f35c..6737769e9 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/FontsController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/FontsController.kt @@ -3,6 +3,7 @@ package org.gotson.komga.interfaces.api.rest import io.github.oshai.kotlinlogging.KotlinLogging import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag +import org.apache.commons.io.FilenameUtils import org.gotson.komga.infrastructure.configuration.KomgaProperties import org.gotson.komga.infrastructure.swagger.OpenApiConfiguration import org.gotson.komga.language.contains @@ -45,9 +46,9 @@ class FontsController( resolver .getResources("/embeddedFonts/**/*.*") .filterNot { it.filename == null } - .filter { supportedExtensions.contains(Path(it.uri.toString()).extension, true) } + .filter { supportedExtensions.contains(FilenameUtils.getExtension(it.uri.toString()), true) } .groupBy { - Path(it.uri.toString()).parent.name + FilenameUtils.getName(FilenameUtils.getPathNoEndSeparator(it.uri.toString())) } } catch (e: Exception) { logger.error(e) { "Could not load embedded fonts" } @@ -96,7 +97,7 @@ class FontsController( ): ResponseEntity { fonts[fontFamily]?.let { resources -> val resource = resources.firstOrNull { it.filename == fontFile } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) - val mediaType = "font/${Path(resource.uri.toString()).extension.lowercase()}" + val mediaType = "font/${FilenameUtils.getExtension(resource.uri.toString()).lowercase()}" return ResponseEntity .ok() .headers { @@ -116,7 +117,7 @@ class FontsController( @PathVariable fontFamily: String, ): ResponseEntity { fonts[fontFamily]?.let { files -> - val groups = files.groupBy { getFontCharacteristics(Path(it.uri.toString()).name) } + val groups = files.groupBy { getFontCharacteristics(FilenameUtils.getName(it.uri.toString())) } val css = groups @@ -142,14 +143,14 @@ class FontsController( ): String { val srcBlock = fonts.joinToString(separator = ",", postfix = ";") { resource -> - val path = Path(resource.uri.toString()) + val filename = FilenameUtils.getName(resource.uri.toString()) val format = - when (val extension = path.extension.lowercase()) { + when (val extension = FilenameUtils.getExtension(resource.uri.toString()).lowercase()) { "ttf" -> "truetype" "otf" -> "opentype" else -> extension } - """url('${path.name}') format('$format')""" + """url('$filename') format('$format')""" } // language=CSS return """ diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/FontsControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/FontsControllerTest.kt new file mode 100644 index 000000000..b3782f4e2 --- /dev/null +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/FontsControllerTest.kt @@ -0,0 +1,87 @@ +package org.gotson.komga.interfaces.api.rest + +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.http.HttpHeaders +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.get + +@SpringBootTest +@AutoConfigureMockMvc(printOnlyOnFailure = false) +class FontsControllerTest( + @Autowired private val mockMvc: MockMvc, +) { + @Test + @WithMockCustomUser + fun `when getting font families then the embedded fonts are returned`() { + mockMvc + .get("/api/v1/fonts/families") + .andExpect { + status { isOk() } + jsonPath("$.length()") { value(1) } + jsonPath("$[0]") { value("OpenDyslexic") } + } + } + + @Test + @WithMockCustomUser + fun `when getting font file then the content type headers are correct`() { + mockMvc + .get("/api/v1/fonts/resource/OpenDyslexic/OpenDyslexic-Bold.woff") + .andExpect { + status { isOk() } + header { + string(HttpHeaders.CONTENT_TYPE, "font/woff") + } + } + } + + @Test + @WithMockCustomUser + fun `when getting font css file then the content is correct`() { + mockMvc + .get("/api/v1/fonts/resource/OpenDyslexic/css") + .andExpect { + status { isOk() } + header { + string(HttpHeaders.CONTENT_TYPE, "text/css") + } + content { + string( + """ + @font-face { + font-family: 'OpenDyslexic'; + src: url('OpenDyslexic-Bold-Italic.woff') format('woff'),url('OpenDyslexic-Bold-Italic.woff2') format('woff2'); + font-weight: bold; + font-style: italic; + } + + @font-face { + font-family: 'OpenDyslexic'; + src: url('OpenDyslexic-Bold.woff') format('woff'),url('OpenDyslexic-Bold.woff2') format('woff2'); + font-weight: bold; + font-style: normal; + } + + @font-face { + font-family: 'OpenDyslexic'; + src: url('OpenDyslexic-Italic.woff') format('woff'),url('OpenDyslexic-Italic.woff2') format('woff2'); + font-weight: normal; + font-style: italic; + } + + @font-face { + font-family: 'OpenDyslexic'; + src: url('OpenDyslexic-Regular.woff') format('woff'),url('OpenDyslexic-Regular.woff2') format('woff2'); + font-weight: normal; + font-style: normal; + } + + """.trimIndent(), + ) + } + } + } +}