mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-13 15:54:35 -05:00
* Update exposed to v1 * Update Exposed * Add Kotlinx.DateTime extensions * Update H2 * Review comments --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Syer10 <syer10@users.noreply.github.com>
119 lines
4.4 KiB
Kotlin
119 lines
4.4 KiB
Kotlin
/*
|
|
* 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/. */
|
|
|
|
package suwayomi.tachidesk.graphql.server
|
|
|
|
import com.expediagroup.graphql.server.execution.GraphQLRequestParser
|
|
import com.expediagroup.graphql.server.types.GraphQLBatchRequest
|
|
import com.expediagroup.graphql.server.types.GraphQLRequest
|
|
import com.expediagroup.graphql.server.types.GraphQLServerRequest
|
|
import io.github.oshai.kotlinlogging.KotlinLogging
|
|
import io.javalin.http.Context
|
|
import io.javalin.http.UploadedFile
|
|
import io.javalin.json.fromJsonStream
|
|
import io.javalin.json.fromJsonString
|
|
import java.io.IOException
|
|
|
|
class JavalinGraphQLRequestParser : GraphQLRequestParser<Context> {
|
|
private val logger = KotlinLogging.logger {}
|
|
|
|
@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
|
|
override suspend fun parseRequest(context: Context): GraphQLServerRequest? {
|
|
return try {
|
|
val jsonMapper = context.jsonMapper()
|
|
val contentType = context.contentType()
|
|
val formParam =
|
|
if (
|
|
contentType?.contains("application/x-www-form-urlencoded") == true ||
|
|
contentType?.contains("multipart/form-data") == true
|
|
) {
|
|
context.formParam("operations")
|
|
?: throw IllegalArgumentException("Cannot find 'operations' body")
|
|
} else {
|
|
return context.bodyInputStream().use { jsonMapper.fromJsonStream<GraphQLServerRequest>(it) }
|
|
}
|
|
|
|
val request =
|
|
jsonMapper.fromJsonString<GraphQLServerRequest>(formParam)
|
|
|
|
val map =
|
|
context
|
|
.formParam("map")
|
|
?.let {
|
|
jsonMapper.fromJsonString<Map<String, List<String>>>(it)
|
|
}.orEmpty()
|
|
|
|
val mapItems =
|
|
map
|
|
.flatMap { (key, variables) ->
|
|
val file = context.uploadedFile(key)
|
|
variables.map { fullVariable ->
|
|
val variable = fullVariable.removePrefix("variables.").substringBefore('.')
|
|
val listIndex = fullVariable.substringAfterLast('.').toIntOrNull()
|
|
MapItem(
|
|
variable,
|
|
listIndex,
|
|
file,
|
|
)
|
|
}
|
|
}.groupBy { it.variable }
|
|
|
|
when (request) {
|
|
is GraphQLRequest -> {
|
|
request.copy(variables = request.variables?.modifyFiles(mapItems))
|
|
}
|
|
|
|
is GraphQLBatchRequest -> {
|
|
request.copy(
|
|
requests =
|
|
request.requests.map {
|
|
it.copy(
|
|
variables = it.variables?.modifyFiles(mapItems),
|
|
)
|
|
},
|
|
)
|
|
}
|
|
}
|
|
} catch (e: IOException) {
|
|
logger.error(e) { "Error when parsing request" }
|
|
null
|
|
}
|
|
}
|
|
|
|
data class MapItem(
|
|
val variable: String,
|
|
val listIndex: Int?,
|
|
val file: UploadedFile?,
|
|
)
|
|
|
|
/**
|
|
* Example [this]: { "file": null }
|
|
* Example: '{ "query": "mutation ($file: Upload!) { singleUpload(file: $file) { id } }", "variables": { "file": null } }'
|
|
* Example map "{ "0": ["variables.file"] }"
|
|
* TODO nested objects
|
|
*/
|
|
private fun Map<String, Any?>.modifyFiles(map: Map<String, List<MapItem>>): Map<String, Any?> =
|
|
mapValues { (name, value) ->
|
|
if (map.containsKey(name)) {
|
|
val items = map[name].orEmpty()
|
|
if (items.size > 1) {
|
|
if (value is List<*>) {
|
|
value.mapIndexed { index, any ->
|
|
any ?: items.firstOrNull { it.listIndex == index }?.file
|
|
}
|
|
} else {
|
|
value
|
|
}
|
|
} else {
|
|
value ?: items.firstOrNull()?.file
|
|
}
|
|
} else {
|
|
value
|
|
}
|
|
}
|
|
}
|