Feature/graphql settings add jwt settings (#1612)

* Add jwt settings to grapqhl SettingsType

* Sort proto BackupServerSettings by ProtNumber
This commit is contained in:
schroda
2025-08-24 18:35:59 +02:00
committed by GitHub
parent 8ae451ece5
commit 9a33e3808a
6 changed files with 153 additions and 18 deletions

View File

@@ -182,6 +182,9 @@ class SettingsMutation {
// Authentication
updateSetting(settings.authMode, serverConfig.authMode)
updateSetting(settings.jwtAudience, serverConfig.jwtAudience)
updateSetting(settings.jwtTokenExpiry, serverConfig.jwtTokenExpiry)
updateSetting(settings.jwtRefreshExpiry, serverConfig.jwtRefreshExpiry)
updateSetting(settings.authUsername, serverConfig.authUsername)
updateSetting(settings.authPassword, serverConfig.authPassword)
updateSetting(settings.basicAuthEnabled, serverConfig.basicAuthEnabled)

View File

@@ -43,6 +43,7 @@ import suwayomi.tachidesk.graphql.queries.TrackQuery
import suwayomi.tachidesk.graphql.queries.UpdateQuery
import suwayomi.tachidesk.graphql.server.primitives.Cursor
import suwayomi.tachidesk.graphql.server.primitives.GraphQLCursor
import suwayomi.tachidesk.graphql.server.primitives.GraphQLDurationAsString
import suwayomi.tachidesk.graphql.server.primitives.GraphQLLongAsString
import suwayomi.tachidesk.graphql.server.primitives.GraphQLUpload
import suwayomi.tachidesk.graphql.subscriptions.DownloadSubscription
@@ -50,11 +51,13 @@ import suwayomi.tachidesk.graphql.subscriptions.InfoSubscription
import suwayomi.tachidesk.graphql.subscriptions.UpdateSubscription
import kotlin.reflect.KClass
import kotlin.reflect.KType
import kotlin.time.Duration
class CustomSchemaGeneratorHooks : FlowSubscriptionSchemaGeneratorHooks() {
override fun willGenerateGraphQLType(type: KType): GraphQLType? =
when (type.classifier as? KClass<*>) {
Long::class -> GraphQLLongAsString // encode to string for JS
Duration::class -> GraphQLDurationAsString // encode Duration as ISO-8601 string
Cursor::class -> GraphQLCursor
UploadedFile::class -> GraphQLUpload
else -> super.willGenerateGraphQLType(type)

View File

@@ -0,0 +1,122 @@
package suwayomi.tachidesk.graphql.server.primitives
import graphql.GraphQLContext
import graphql.execution.CoercedVariables
import graphql.language.StringValue
import graphql.language.Value
import graphql.scalar.CoercingUtil
import graphql.schema.Coercing
import graphql.schema.CoercingParseLiteralException
import graphql.schema.CoercingParseValueException
import graphql.schema.CoercingSerializeException
import graphql.schema.GraphQLScalarType
import java.util.Locale
import kotlin.time.Duration
val GraphQLDurationAsString: GraphQLScalarType =
GraphQLScalarType
.newScalar()
.name("Duration")
.description("An ISO-8601 encoded duration string")
.coercing(GraphqlDurationAsStringCoercing())
.build()
private class GraphqlDurationAsStringCoercing : Coercing<Duration, String> {
private fun toStringImpl(input: Any): String =
when (input) {
is Duration -> input.toIsoString()
is String -> Duration.parse(input).toIsoString()
else -> throw CoercingSerializeException(
"Expected a Duration or String but was ${CoercingUtil.typeName(input)}",
)
}
private fun parseValueImpl(
input: Any,
locale: Locale,
): Duration {
if (input !is String) {
throw CoercingParseValueException(
CoercingUtil.i18nMsg(
locale,
"String.unexpectedRawValueType",
CoercingUtil.typeName(input),
),
)
}
return try {
Duration.parse(input)
} catch (e: IllegalArgumentException) {
throw CoercingParseValueException(
"Invalid duration format: $input. Expected ISO-8601 duration string (e.g., 'PT30M', 'P1D')",
e,
)
}
}
private fun parseLiteralImpl(
input: Any,
locale: Locale,
): Duration {
if (input !is StringValue) {
throw CoercingParseLiteralException(
CoercingUtil.i18nMsg(
locale,
"Scalar.unexpectedAstType",
"StringValue",
CoercingUtil.typeName(input),
),
)
}
return try {
Duration.parse(input.value)
} catch (e: IllegalArgumentException) {
throw CoercingParseLiteralException(
"Invalid duration format: ${input.value}. Expected ISO-8601 duration string (e.g., 'PT30M', 'P1D')",
e,
)
}
}
private fun valueToLiteralImpl(input: Any): StringValue = StringValue.newStringValue(toStringImpl(input)).build()
@Deprecated("")
override fun serialize(dataFetcherResult: Any): String = toStringImpl(dataFetcherResult)
@Throws(CoercingSerializeException::class)
override fun serialize(
dataFetcherResult: Any,
graphQLContext: GraphQLContext,
locale: Locale,
): String = toStringImpl(dataFetcherResult)
@Deprecated("")
override fun parseValue(input: Any): Duration = parseValueImpl(input, Locale.getDefault())
@Throws(CoercingParseValueException::class)
override fun parseValue(
input: Any,
graphQLContext: GraphQLContext,
locale: Locale,
): Duration = parseValueImpl(input, locale)
@Deprecated("")
override fun parseLiteral(input: Any): Duration = parseLiteralImpl(input, Locale.getDefault())
@Throws(CoercingParseLiteralException::class)
override fun parseLiteral(
input: Value<*>,
variables: CoercedVariables,
graphQLContext: GraphQLContext,
locale: Locale,
): Duration = parseLiteralImpl(input, locale)
@Deprecated("")
override fun valueToLiteral(input: Any): Value<*> = valueToLiteralImpl(input)
override fun valueToLiteral(
input: Any,
graphQLContext: GraphQLContext,
locale: Locale,
): Value<*> = valueToLiteralImpl(input)
}

View File

@@ -12,6 +12,7 @@ import org.jetbrains.exposed.sql.SortOrder
import suwayomi.tachidesk.graphql.server.primitives.Node
import suwayomi.tachidesk.server.ServerConfig
import suwayomi.tachidesk.server.serverConfig
import kotlin.time.Duration
interface Settings : Node {
val ip: String?
@@ -65,6 +66,9 @@ interface Settings : Node {
// Authentication
val authMode: AuthMode?
val jwtAudience: String?
val jwtTokenExpiry: Duration?
val jwtRefreshExpiry: Duration?
val authUsername: String?
val authPassword: String?
@@ -177,6 +181,9 @@ data class PartialSettingsType(
override val updateMangas: Boolean?,
// Authentication
override val authMode: AuthMode?,
override val jwtAudience: String?,
override val jwtTokenExpiry: Duration?,
override val jwtRefreshExpiry: Duration?,
override val authUsername: String?,
override val authPassword: String?,
@GraphQLDeprecated("Removed - prefer authMode")
@@ -267,6 +274,9 @@ class SettingsType(
override val updateMangas: Boolean,
// Authentication
override val authMode: AuthMode,
override val jwtAudience: String,
override val jwtTokenExpiry: Duration,
override val jwtRefreshExpiry: Duration,
override val authUsername: String,
override val authPassword: String,
@GraphQLDeprecated("Removed - prefer authMode")
@@ -358,6 +368,9 @@ class SettingsType(
config.updateMangas.value,
// Authentication
config.authMode.value,
config.jwtAudience.value,
config.jwtTokenExpiry.value,
config.jwtRefreshExpiry.value,
config.authUsername.value,
config.authPassword.value,
config.basicAuthEnabled.value,