mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-03 19:04:39 -05:00
* Non-Extension Index changes for 1.6 * Changelog * Minor fixes * Implement extension store * Test build fix * Docs * Simplify fetching manga and chapters * Use EMPTY JsonObject * Update docs/Configuring-Suwayomi‐Server.md Co-authored-by: Constantin Piber <59023762+cpiber@users.noreply.github.com> * Improve Fetch Extension Store * Fixes * Simplify deprecated isNsfw in SourceQuery * Simplify ContentRating in Source.kt * Simplify isNsfw in SourceType * No magic numbers for ContentRating, improves safety for future versions of extension api * Fix SearchTest * Lint * Lint * Optimize imports and fix unchecked cast warning * Proper extension store queries * Optimize import fixes * Add ContentRatingFilter * Improve extension store sync * fix: re-sync (#2121) * Lint * Add ExtenionStores to the fetchExtensions result since its possible for the stores to change. * Use a single version of ContentRating * Exclude ServerConfig.extensionStores from GraphQL * Use syncDbToPrefs in ExtensionStoreMutation * Optimize Imports * Update server/server-config/src/main/kotlin/suwayomi/tachidesk/server/ServerConfig.kt Co-authored-by: Constantin Piber <59023762+cpiber@users.noreply.github.com> * Remove replaceWith and add specific description for GQL APIs * Include OkHttp ZSTD * Update to latest Mihon extension lib * Fix latest Mihon Extension Lib * Lint * Optimize imports * Lint * Review fixes * Add a index to extesnion table store url * Lint --------- Co-authored-by: Constantin Piber <59023762+cpiber@users.noreply.github.com>
193 lines
6.7 KiB
Kotlin
193 lines
6.7 KiB
Kotlin
package suwayomi.tachidesk.manga.controller
|
|
|
|
/*
|
|
* Copyright (C) Contributors to the Suwayomi project
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
import io.github.oshai.kotlinlogging.KotlinLogging
|
|
import io.javalin.http.HttpStatus
|
|
import suwayomi.tachidesk.manga.impl.extension.Extension
|
|
import suwayomi.tachidesk.manga.impl.extension.ExtensionsList
|
|
import suwayomi.tachidesk.manga.model.dataclass.ExtensionDataClass
|
|
import suwayomi.tachidesk.server.JavalinSetup.Attribute
|
|
import suwayomi.tachidesk.server.JavalinSetup.future
|
|
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
|
|
import suwayomi.tachidesk.server.user.requireUser
|
|
import suwayomi.tachidesk.server.util.handler
|
|
import suwayomi.tachidesk.server.util.pathParam
|
|
import suwayomi.tachidesk.server.util.withOperation
|
|
import kotlin.time.Duration.Companion.days
|
|
|
|
object ExtensionController {
|
|
private val logger = KotlinLogging.logger {}
|
|
|
|
/** list all extensions */
|
|
val list =
|
|
handler(
|
|
documentWith = {
|
|
withOperation {
|
|
summary("Extension list")
|
|
description("List all extensions")
|
|
}
|
|
},
|
|
behaviorOf = { ctx ->
|
|
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
|
ctx.future {
|
|
future {
|
|
ExtensionsList.getExtensionList()
|
|
}.thenApply {
|
|
ctx.json(it)
|
|
}
|
|
}
|
|
},
|
|
withResults = {
|
|
json<Array<ExtensionDataClass>>(HttpStatus.OK)
|
|
},
|
|
)
|
|
|
|
/** install extension identified with "pkgName" */
|
|
val install =
|
|
handler(
|
|
pathParam<String>("pkgName"),
|
|
documentWith = {
|
|
withOperation {
|
|
summary("Extension install")
|
|
description("install extension identified with \"pkgName\"")
|
|
}
|
|
},
|
|
behaviorOf = { ctx, pkgName ->
|
|
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
|
ctx.future {
|
|
future {
|
|
Extension.installExtension(pkgName)
|
|
}.thenApply {
|
|
ctx.status(it)
|
|
}
|
|
}
|
|
},
|
|
withResults = {
|
|
httpCode(HttpStatus.CREATED)
|
|
httpCode(HttpStatus.FOUND)
|
|
httpCode(HttpStatus.INTERNAL_SERVER_ERROR)
|
|
},
|
|
)
|
|
|
|
/** install the uploaded apk file */
|
|
val installFile =
|
|
handler(
|
|
documentWith = {
|
|
withOperation {
|
|
summary("Extension install apk")
|
|
description("Install the uploaded apk file")
|
|
}
|
|
uploadedFile("file") {
|
|
it.description("Extension apk")
|
|
it.required(true)
|
|
}
|
|
},
|
|
behaviorOf = { ctx ->
|
|
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
|
val uploadedFile = ctx.uploadedFile("file")!!
|
|
logger.debug { "Uploaded extension file name: " + uploadedFile.filename() }
|
|
|
|
ctx.future {
|
|
future {
|
|
Extension.installExternalExtension(
|
|
uploadedFile.content(),
|
|
uploadedFile.filename(),
|
|
)
|
|
}.thenApply {
|
|
ctx.status(it)
|
|
}
|
|
}
|
|
},
|
|
withResults = {
|
|
httpCode(HttpStatus.CREATED)
|
|
httpCode(HttpStatus.FOUND)
|
|
httpCode(HttpStatus.INTERNAL_SERVER_ERROR)
|
|
},
|
|
)
|
|
|
|
/** update extension identified with "pkgName" */
|
|
val update =
|
|
handler(
|
|
pathParam<String>("pkgName"),
|
|
documentWith = {
|
|
withOperation {
|
|
summary("Extension update")
|
|
description("Update extension identified with \"pkgName\"")
|
|
}
|
|
},
|
|
behaviorOf = { ctx, pkgName ->
|
|
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
|
ctx.future {
|
|
future {
|
|
Extension.updateExtension(pkgName)
|
|
}.thenApply {
|
|
ctx.status(it)
|
|
}
|
|
}
|
|
},
|
|
withResults = {
|
|
httpCode(HttpStatus.CREATED)
|
|
httpCode(HttpStatus.FOUND)
|
|
httpCode(HttpStatus.NOT_FOUND)
|
|
httpCode(HttpStatus.INTERNAL_SERVER_ERROR)
|
|
},
|
|
)
|
|
|
|
/** uninstall extension identified with "pkgName" */
|
|
val uninstall =
|
|
handler(
|
|
pathParam<String>("pkgName"),
|
|
documentWith = {
|
|
withOperation {
|
|
summary("Extension uninstall")
|
|
description("Uninstall extension identified with \"pkgName\"")
|
|
}
|
|
},
|
|
behaviorOf = { ctx, pkgName ->
|
|
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
|
Extension.uninstallExtension(pkgName)
|
|
ctx.status(200)
|
|
},
|
|
withResults = {
|
|
httpCode(HttpStatus.CREATED)
|
|
httpCode(HttpStatus.FOUND)
|
|
httpCode(HttpStatus.NOT_FOUND)
|
|
httpCode(HttpStatus.INTERNAL_SERVER_ERROR)
|
|
},
|
|
)
|
|
|
|
/** icon for extension named `apkName` */
|
|
val icon =
|
|
handler(
|
|
pathParam<String>("pkgName"),
|
|
documentWith = {
|
|
withOperation {
|
|
summary("Extension icon")
|
|
description("Icon for extension named `apkName`")
|
|
}
|
|
},
|
|
behaviorOf = { ctx, pkgName ->
|
|
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
|
ctx.future {
|
|
future { Extension.getExtensionIcon(pkgName) }
|
|
.thenApply {
|
|
ctx.header("content-type", it.second)
|
|
val httpCacheSeconds = 365.days.inWholeSeconds
|
|
ctx.header("cache-control", "max-age=$httpCacheSeconds, immutable")
|
|
ctx.result(it.first)
|
|
}
|
|
}
|
|
},
|
|
withResults = {
|
|
image(HttpStatus.OK)
|
|
httpCode(HttpStatus.NOT_FOUND)
|
|
},
|
|
)
|
|
}
|