Use graphql directive for auth handling (#1671)

This commit is contained in:
schroda
2025-09-29 17:24:19 +02:00
committed by GitHub
parent 5e48b05270
commit 5c79672d84
35 changed files with 297 additions and 555 deletions

View File

@@ -0,0 +1,23 @@
/*
* 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.directives
import com.expediagroup.graphql.generator.annotations.GraphQLDirective
import graphql.introspection.Introspection.DirectiveLocation
@GraphQLDirective(
name = "requireAuth",
description = "Requires user authentication",
locations = [
DirectiveLocation.FIELD_DEFINITION,
DirectiveLocation.OBJECT,
],
)
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class RequireAuth

View File

@@ -0,0 +1,50 @@
/*
* 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.directives
import com.expediagroup.graphql.generator.directives.KotlinFieldDirectiveEnvironment
import com.expediagroup.graphql.generator.directives.KotlinSchemaDirectiveWiring
import graphql.schema.DataFetcher
import graphql.schema.DataFetchingEnvironmentImpl
import graphql.schema.GraphQLFieldDefinition
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.user.requireUser
private const val USER_ID_PARAM = "userId"
class RequireAuthDirectiveWiring : KotlinSchemaDirectiveWiring {
override fun onField(environment: KotlinFieldDirectiveEnvironment): GraphQLFieldDefinition {
val originalDataFetcher = environment.getDataFetcher()
val authDataFetcher =
DataFetcher { env ->
val user = env.graphQlContext.getAttribute(Attribute.TachideskUser)
val userId = user.requireUser()
if (env.arguments.containsKey(USER_ID_PARAM)) {
throw Exception("\"$USER_ID_PARAM\" is a reserved parameter for RequireAuth")
}
// Create a new environment with userId added to arguments
val newArguments: MutableMap<String, Any> = env.arguments.toMutableMap()
newArguments[USER_ID_PARAM] = userId
val modifiedEnv =
DataFetchingEnvironmentImpl
.newDataFetchingEnvironment(env)
.arguments(newArguments)
.build()
originalDataFetcher.get(modifiedEnv)
}
environment.setDataFetcher(authDataFetcher)
return environment.element
}
}

View File

@@ -1,21 +1,17 @@
package suwayomi.tachidesk.graphql.mutations
import graphql.schema.DataFetchingEnvironment
import io.javalin.http.UploadedFile
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withTimeout
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.server.TemporaryFileStorage
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.types.BackupRestoreStatus
import suwayomi.tachidesk.graphql.types.toStatus
import suwayomi.tachidesk.manga.impl.backup.BackupFlags
import suwayomi.tachidesk.manga.impl.backup.proto.ProtoBackupExport
import suwayomi.tachidesk.manga.impl.backup.proto.ProtoBackupImport
import suwayomi.tachidesk.manga.impl.backup.proto.models.Backup
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 java.util.concurrent.CompletableFuture
import kotlin.time.Duration.Companion.seconds
@@ -31,11 +27,8 @@ class BackupMutation {
val status: BackupRestoreStatus?,
)
fun restoreBackup(
dataFetchingEnvironment: DataFetchingEnvironment,
input: RestoreBackupInput,
): CompletableFuture<RestoreBackupPayload> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun restoreBackup(input: RestoreBackupInput): CompletableFuture<RestoreBackupPayload> {
val (clientMutationId, backup) = input
return future {
@@ -66,11 +59,8 @@ class BackupMutation {
val url: String,
)
fun createBackup(
dataFetchingEnvironment: DataFetchingEnvironment,
input: CreateBackupInput? = null,
): CreateBackupPayload {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun createBackup(input: CreateBackupInput? = null): CreateBackupPayload {
val filename = Backup.getFilename()
val backup =

View File

@@ -1,7 +1,6 @@
package suwayomi.tachidesk.graphql.mutations
import graphql.execution.DataFetcherResult
import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList
import org.jetbrains.exposed.sql.SqlExpressionBuilder.minus
@@ -13,7 +12,7 @@ import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
import suwayomi.tachidesk.graphql.asDataFetcherResult
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.CategoryMetaType
import suwayomi.tachidesk.graphql.types.CategoryType
import suwayomi.tachidesk.graphql.types.MangaType
@@ -25,9 +24,6 @@ import suwayomi.tachidesk.manga.model.table.CategoryMangaTable
import suwayomi.tachidesk.manga.model.table.CategoryMetaTable
import suwayomi.tachidesk.manga.model.table.CategoryTable
import suwayomi.tachidesk.manga.model.table.MangaTable
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
import suwayomi.tachidesk.server.user.requireUser
class CategoryMutation {
data class SetCategoryMetaInput(
@@ -40,12 +36,9 @@ class CategoryMutation {
val meta: CategoryMetaType,
)
fun setCategoryMeta(
dataFetchingEnvironment: DataFetchingEnvironment,
input: SetCategoryMetaInput,
): DataFetcherResult<SetCategoryMetaPayload?> =
@RequireAuth
fun setCategoryMeta(input: SetCategoryMetaInput): DataFetcherResult<SetCategoryMetaPayload?> =
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (clientMutationId, meta) = input
Category.modifyMeta(meta.categoryId, meta.key, meta.value)
@@ -65,12 +58,9 @@ class CategoryMutation {
val category: CategoryType,
)
fun deleteCategoryMeta(
dataFetchingEnvironment: DataFetchingEnvironment,
input: DeleteCategoryMetaInput,
): DataFetcherResult<DeleteCategoryMetaPayload?> =
@RequireAuth
fun deleteCategoryMeta(input: DeleteCategoryMetaInput): DataFetcherResult<DeleteCategoryMetaPayload?> =
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (clientMutationId, categoryId, key) = input
val (meta, category) =
@@ -163,12 +153,9 @@ class CategoryMutation {
}
}
fun updateCategory(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UpdateCategoryInput,
): DataFetcherResult<UpdateCategoryPayload?> =
@RequireAuth
fun updateCategory(input: UpdateCategoryInput): DataFetcherResult<UpdateCategoryPayload?> =
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (clientMutationId, id, patch) = input
updateCategories(listOf(id), patch)
@@ -184,12 +171,9 @@ class CategoryMutation {
)
}
fun updateCategories(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UpdateCategoriesInput,
): DataFetcherResult<UpdateCategoriesPayload?> =
@RequireAuth
fun updateCategories(input: UpdateCategoriesInput): DataFetcherResult<UpdateCategoriesPayload?> =
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (clientMutationId, ids, patch) = input
updateCategories(ids, patch)
@@ -216,12 +200,9 @@ class CategoryMutation {
val position: Int,
)
fun updateCategoryOrder(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UpdateCategoryOrderInput,
): DataFetcherResult<UpdateCategoryOrderPayload?> =
@RequireAuth
fun updateCategoryOrder(input: UpdateCategoryOrderInput): DataFetcherResult<UpdateCategoryOrderPayload?> =
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (clientMutationId, categoryId, position) = input
require(position > 0) {
"'order' must not be <= 0"
@@ -278,12 +259,9 @@ class CategoryMutation {
val category: CategoryType,
)
fun createCategory(
dataFetchingEnvironment: DataFetchingEnvironment,
input: CreateCategoryInput,
): DataFetcherResult<CreateCategoryPayload?> =
@RequireAuth
fun createCategory(input: CreateCategoryInput): DataFetcherResult<CreateCategoryPayload?> =
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (clientMutationId, name, order, default, includeInUpdate, includeInDownload) = input
transaction {
require(CategoryTable.selectAll().where { CategoryTable.name eq input.name }.isEmpty()) {
@@ -341,12 +319,9 @@ class CategoryMutation {
val mangas: List<MangaType>,
)
fun deleteCategory(
dataFetchingEnvironment: DataFetchingEnvironment,
input: DeleteCategoryInput,
): DataFetcherResult<DeleteCategoryPayload?> {
@RequireAuth
fun deleteCategory(input: DeleteCategoryInput): DataFetcherResult<DeleteCategoryPayload?> {
return asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (clientMutationId, categoryId) = input
if (categoryId == 0) { // Don't delete default category
return@asDataFetcherResult DeleteCategoryPayload(
@@ -434,12 +409,9 @@ class CategoryMutation {
}
}
fun updateMangaCategories(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UpdateMangaCategoriesInput,
): DataFetcherResult<UpdateMangaCategoriesPayload?> =
@RequireAuth
fun updateMangaCategories(input: UpdateMangaCategoriesInput): DataFetcherResult<UpdateMangaCategoriesPayload?> =
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (clientMutationId, id, patch) = input
updateMangas(listOf(id), patch)
@@ -455,12 +427,9 @@ class CategoryMutation {
)
}
fun updateMangasCategories(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UpdateMangasCategoriesInput,
): DataFetcherResult<UpdateMangasCategoriesPayload?> =
@RequireAuth
fun updateMangasCategories(input: UpdateMangasCategoriesInput): DataFetcherResult<UpdateMangasCategoriesPayload?> =
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (clientMutationId, ids, patch) = input
updateMangas(ids, patch)

View File

@@ -1,7 +1,6 @@
package suwayomi.tachidesk.graphql.mutations
import graphql.execution.DataFetcherResult
import graphql.schema.DataFetchingEnvironment
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.jetbrains.exposed.dao.id.EntityID
@@ -13,7 +12,7 @@ import org.jetbrains.exposed.sql.statements.BatchUpdateStatement
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
import suwayomi.tachidesk.graphql.asDataFetcherResult
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.ChapterMetaType
import suwayomi.tachidesk.graphql.types.ChapterType
import suwayomi.tachidesk.graphql.types.SyncConflictInfoType
@@ -22,10 +21,7 @@ import suwayomi.tachidesk.manga.impl.chapter.getChapterDownloadReadyById
import suwayomi.tachidesk.manga.impl.sync.KoreaderSyncService
import suwayomi.tachidesk.manga.model.table.ChapterMetaTable
import suwayomi.tachidesk.manga.model.table.ChapterTable
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 java.net.URLEncoder
import java.time.Instant
import java.util.concurrent.CompletableFuture
@@ -117,12 +113,9 @@ class ChapterMutation {
}
}
fun updateChapter(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UpdateChapterInput,
): DataFetcherResult<UpdateChapterPayload?> =
@RequireAuth
fun updateChapter(input: UpdateChapterInput): DataFetcherResult<UpdateChapterPayload?> =
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (clientMutationId, id, patch) = input
updateChapters(listOf(id), patch)
@@ -138,12 +131,9 @@ class ChapterMutation {
)
}
fun updateChapters(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UpdateChaptersInput,
): DataFetcherResult<UpdateChaptersPayload?> =
@RequireAuth
fun updateChapters(input: UpdateChaptersInput): DataFetcherResult<UpdateChaptersPayload?> =
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (clientMutationId, ids, patch) = input
updateChapters(ids, patch)
@@ -169,11 +159,8 @@ class ChapterMutation {
val chapters: List<ChapterType>,
)
fun fetchChapters(
dataFetchingEnvironment: DataFetchingEnvironment,
input: FetchChaptersInput,
): CompletableFuture<DataFetcherResult<FetchChaptersPayload?>> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun fetchChapters(input: FetchChaptersInput): CompletableFuture<DataFetcherResult<FetchChaptersPayload?>> {
val (clientMutationId, mangaId) = input
return future {
@@ -207,12 +194,9 @@ class ChapterMutation {
val meta: ChapterMetaType,
)
fun setChapterMeta(
dataFetchingEnvironment: DataFetchingEnvironment,
input: SetChapterMetaInput,
): DataFetcherResult<SetChapterMetaPayload?> =
@RequireAuth
fun setChapterMeta(input: SetChapterMetaInput): DataFetcherResult<SetChapterMetaPayload?> =
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (clientMutationId, meta) = input
Chapter.modifyChapterMeta(meta.chapterId, meta.key, meta.value)
@@ -232,12 +216,9 @@ class ChapterMutation {
val chapter: ChapterType,
)
fun deleteChapterMeta(
dataFetchingEnvironment: DataFetchingEnvironment,
input: DeleteChapterMetaInput,
): DataFetcherResult<DeleteChapterMetaPayload?> =
@RequireAuth
fun deleteChapterMeta(input: DeleteChapterMetaInput): DataFetcherResult<DeleteChapterMetaPayload?> =
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (clientMutationId, chapterId, key) = input
val (meta, chapter) =
@@ -285,11 +266,8 @@ class ChapterMutation {
val syncConflict: SyncConflictInfoType?,
)
fun fetchChapterPages(
dataFetchingEnvironment: DataFetchingEnvironment,
input: FetchChapterPagesInput,
): CompletableFuture<DataFetcherResult<FetchChapterPagesPayload?>> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun fetchChapterPages(input: FetchChapterPagesInput): CompletableFuture<DataFetcherResult<FetchChapterPagesPayload?>> {
val (clientMutationId, chapterId) = input
val paramsMap = input.toParams()

View File

@@ -1,13 +1,12 @@
package suwayomi.tachidesk.graphql.mutations
import graphql.execution.DataFetcherResult
import graphql.schema.DataFetchingEnvironment
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withTimeout
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.asDataFetcherResult
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.ChapterType
import suwayomi.tachidesk.graphql.types.DownloadStatus
import suwayomi.tachidesk.manga.impl.Chapter
@@ -15,9 +14,7 @@ import suwayomi.tachidesk.manga.impl.download.DownloadManager
import suwayomi.tachidesk.manga.impl.download.model.DownloadUpdateType.DEQUEUED
import suwayomi.tachidesk.manga.impl.download.model.Status
import suwayomi.tachidesk.manga.model.table.ChapterTable
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.future
import suwayomi.tachidesk.server.user.requireUser
import java.util.concurrent.CompletableFuture
import kotlin.time.Duration.Companion.seconds
@@ -32,11 +29,8 @@ class DownloadMutation {
val chapters: List<ChapterType>,
)
fun deleteDownloadedChapters(
dataFetchingEnvironment: DataFetchingEnvironment,
input: DeleteDownloadedChaptersInput,
): DataFetcherResult<DeleteDownloadedChaptersPayload?> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun deleteDownloadedChapters(input: DeleteDownloadedChaptersInput): DataFetcherResult<DeleteDownloadedChaptersPayload?> {
val (clientMutationId, chapters) = input
return asDataFetcherResult {
@@ -65,11 +59,8 @@ class DownloadMutation {
val chapters: ChapterType,
)
fun deleteDownloadedChapter(
dataFetchingEnvironment: DataFetchingEnvironment,
input: DeleteDownloadedChapterInput,
): DataFetcherResult<DeleteDownloadedChapterPayload?> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun deleteDownloadedChapter(input: DeleteDownloadedChapterInput): DataFetcherResult<DeleteDownloadedChapterPayload?> {
val (clientMutationId, chapter) = input
return asDataFetcherResult {
@@ -95,11 +86,10 @@ class DownloadMutation {
val downloadStatus: DownloadStatus,
)
@RequireAuth
fun enqueueChapterDownloads(
dataFetchingEnvironment: DataFetchingEnvironment,
input: EnqueueChapterDownloadsInput,
): CompletableFuture<DataFetcherResult<EnqueueChapterDownloadsPayload?>> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (clientMutationId, chapters) = input
return future {
@@ -132,11 +122,8 @@ class DownloadMutation {
val downloadStatus: DownloadStatus,
)
fun enqueueChapterDownload(
dataFetchingEnvironment: DataFetchingEnvironment,
input: EnqueueChapterDownloadInput,
): CompletableFuture<DataFetcherResult<EnqueueChapterDownloadPayload?>> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun enqueueChapterDownload(input: EnqueueChapterDownloadInput): CompletableFuture<DataFetcherResult<EnqueueChapterDownloadPayload?>> {
val (clientMutationId, chapter) = input
return future {
@@ -168,11 +155,10 @@ class DownloadMutation {
val downloadStatus: DownloadStatus,
)
@RequireAuth
fun dequeueChapterDownloads(
dataFetchingEnvironment: DataFetchingEnvironment,
input: DequeueChapterDownloadsInput,
): CompletableFuture<DataFetcherResult<DequeueChapterDownloadsPayload?>> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (clientMutationId, chapters) = input
return future {
@@ -207,11 +193,8 @@ class DownloadMutation {
val downloadStatus: DownloadStatus,
)
fun dequeueChapterDownload(
dataFetchingEnvironment: DataFetchingEnvironment,
input: DequeueChapterDownloadInput,
): CompletableFuture<DataFetcherResult<DequeueChapterDownloadPayload?>> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun dequeueChapterDownload(input: DequeueChapterDownloadInput): CompletableFuture<DataFetcherResult<DequeueChapterDownloadPayload?>> {
val (clientMutationId, chapter) = input
return future {
@@ -245,13 +228,10 @@ class DownloadMutation {
val downloadStatus: DownloadStatus,
)
fun startDownloader(
dataFetchingEnvironment: DataFetchingEnvironment,
input: StartDownloaderInput,
): CompletableFuture<DataFetcherResult<StartDownloaderPayload?>> =
@RequireAuth
fun startDownloader(input: StartDownloaderInput): CompletableFuture<DataFetcherResult<StartDownloaderPayload?>> =
future {
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
DownloadManager.start()
StartDownloaderPayload(
@@ -277,13 +257,10 @@ class DownloadMutation {
val downloadStatus: DownloadStatus,
)
fun stopDownloader(
dataFetchingEnvironment: DataFetchingEnvironment,
input: StopDownloaderInput,
): CompletableFuture<DataFetcherResult<StopDownloaderPayload?>> =
@RequireAuth
fun stopDownloader(input: StopDownloaderInput): CompletableFuture<DataFetcherResult<StopDownloaderPayload?>> =
future {
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
DownloadManager.stop()
StopDownloaderPayload(
@@ -309,13 +286,10 @@ class DownloadMutation {
val downloadStatus: DownloadStatus,
)
fun clearDownloader(
dataFetchingEnvironment: DataFetchingEnvironment,
input: ClearDownloaderInput,
): CompletableFuture<DataFetcherResult<ClearDownloaderPayload?>> =
@RequireAuth
fun clearDownloader(input: ClearDownloaderInput): CompletableFuture<DataFetcherResult<ClearDownloaderPayload?>> =
future {
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
DownloadManager.clear()
ClearDownloaderPayload(
@@ -343,11 +317,8 @@ class DownloadMutation {
val downloadStatus: DownloadStatus,
)
fun reorderChapterDownload(
dataFetchingEnvironment: DataFetchingEnvironment,
input: ReorderChapterDownloadInput,
): CompletableFuture<DataFetcherResult<ReorderChapterDownloadPayload?>> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun reorderChapterDownload(input: ReorderChapterDownloadInput): CompletableFuture<DataFetcherResult<ReorderChapterDownloadPayload?>> {
val (clientMutationId, chapter, to) = input
return future {

View File

@@ -2,20 +2,16 @@ package suwayomi.tachidesk.graphql.mutations
import eu.kanade.tachiyomi.source.local.LocalSource
import graphql.execution.DataFetcherResult
import graphql.schema.DataFetchingEnvironment
import io.javalin.http.UploadedFile
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.asDataFetcherResult
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.ExtensionType
import suwayomi.tachidesk.manga.impl.extension.Extension
import suwayomi.tachidesk.manga.impl.extension.ExtensionsList
import suwayomi.tachidesk.manga.model.table.ExtensionTable
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 java.util.concurrent.CompletableFuture
class ExtensionMutation {
@@ -78,11 +74,8 @@ class ExtensionMutation {
}
}
fun updateExtension(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UpdateExtensionInput,
): CompletableFuture<DataFetcherResult<UpdateExtensionPayload?>> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun updateExtension(input: UpdateExtensionInput): CompletableFuture<DataFetcherResult<UpdateExtensionPayload?>> {
val (clientMutationId, id, patch) = input
return future {
@@ -106,11 +99,8 @@ class ExtensionMutation {
}
}
fun updateExtensions(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UpdateExtensionsInput,
): CompletableFuture<DataFetcherResult<UpdateExtensionsPayload?>> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun updateExtensions(input: UpdateExtensionsInput): CompletableFuture<DataFetcherResult<UpdateExtensionsPayload?>> {
val (clientMutationId, ids, patch) = input
return future {
@@ -142,11 +132,8 @@ class ExtensionMutation {
val extensions: List<ExtensionType>,
)
fun fetchExtensions(
dataFetchingEnvironment: DataFetchingEnvironment,
input: FetchExtensionsInput,
): CompletableFuture<DataFetcherResult<FetchExtensionsPayload?>> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun fetchExtensions(input: FetchExtensionsInput): CompletableFuture<DataFetcherResult<FetchExtensionsPayload?>> {
val (clientMutationId) = input
return future {
@@ -179,11 +166,10 @@ class ExtensionMutation {
val extension: ExtensionType,
)
@RequireAuth
fun installExternalExtension(
dataFetchingEnvironment: DataFetchingEnvironment,
input: InstallExternalExtensionInput,
): CompletableFuture<DataFetcherResult<InstallExternalExtensionPayload?>> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (clientMutationId, extensionFile) = input
return future {

View File

@@ -1,12 +1,8 @@
package suwayomi.tachidesk.graphql.mutations
import graphql.schema.DataFetchingEnvironment
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.manga.impl.util.storage.ImageResponse
import suwayomi.tachidesk.server.ApplicationDirs
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
import suwayomi.tachidesk.server.user.requireUser
import uy.kohesive.injekt.injectLazy
private val applicationDirs: ApplicationDirs by injectLazy()
@@ -26,11 +22,8 @@ class ImageMutation {
val cachedPages: Boolean?,
)
fun clearCachedImages(
dataFetchingEnvironment: DataFetchingEnvironment,
input: ClearCachedImagesInput,
): ClearCachedImagesPayload {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun clearCachedImages(input: ClearCachedImagesInput): ClearCachedImagesPayload {
val (clientMutationId, downloadedThumbnails, cachedThumbnails, cachedPages) = input
val downloadedThumbnailsResult =

View File

@@ -1,20 +1,16 @@
package suwayomi.tachidesk.graphql.mutations
import graphql.execution.DataFetcherResult
import graphql.schema.DataFetchingEnvironment
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withTimeout
import suwayomi.tachidesk.graphql.asDataFetcherResult
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.UpdateState.DOWNLOADING
import suwayomi.tachidesk.graphql.types.UpdateState.ERROR
import suwayomi.tachidesk.graphql.types.UpdateState.IDLE
import suwayomi.tachidesk.graphql.types.WebUIFlavor
import suwayomi.tachidesk.graphql.types.WebUIUpdateStatus
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.WebInterfaceManager
import java.util.concurrent.CompletableFuture
import kotlin.time.Duration.Companion.seconds
@@ -29,13 +25,10 @@ class InfoMutation {
val updateStatus: WebUIUpdateStatus,
)
fun updateWebUI(
dataFetchingEnvironment: DataFetchingEnvironment,
input: WebUIUpdateInput,
): CompletableFuture<DataFetcherResult<WebUIUpdatePayload?>> {
@RequireAuth
fun updateWebUI(input: WebUIUpdateInput): CompletableFuture<DataFetcherResult<WebUIUpdatePayload?>> {
return future {
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
withTimeout(30.seconds) {
if (WebInterfaceManager.status.value.state === DOWNLOADING) {
return@withTimeout WebUIUpdatePayload(input.clientMutationId, WebInterfaceManager.status.value)
@@ -68,10 +61,10 @@ class InfoMutation {
}
}
fun resetWebUIUpdateStatus(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<DataFetcherResult<WebUIUpdateStatus?>> =
@RequireAuth
fun resetWebUIUpdateStatus(): CompletableFuture<DataFetcherResult<WebUIUpdateStatus?>> =
future {
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
withTimeout(30.seconds) {
val isUpdateFinished = WebInterfaceManager.status.value.state != DOWNLOADING
if (!isUpdateFinished) {

View File

@@ -1,12 +1,11 @@
package suwayomi.tachidesk.graphql.mutations
import graphql.execution.DataFetcherResult
import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
import suwayomi.tachidesk.graphql.asDataFetcherResult
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.ChapterType
import suwayomi.tachidesk.graphql.types.KoSyncConnectPayload
import suwayomi.tachidesk.graphql.types.LogoutKoSyncAccountPayload
@@ -14,9 +13,7 @@ import suwayomi.tachidesk.graphql.types.SettingsType
import suwayomi.tachidesk.graphql.types.SyncConflictInfoType
import suwayomi.tachidesk.manga.impl.sync.KoreaderSyncService
import suwayomi.tachidesk.manga.model.table.ChapterTable
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.future
import suwayomi.tachidesk.server.user.requireUser
import java.util.concurrent.CompletableFuture
class KoreaderSyncMutation {
@@ -26,12 +23,9 @@ class KoreaderSyncMutation {
val password: String,
)
fun connectKoSyncAccount(
dataFetchingEnvironment: DataFetchingEnvironment,
input: ConnectKoSyncAccountInput,
): CompletableFuture<KoSyncConnectPayload> =
@RequireAuth
fun connectKoSyncAccount(input: ConnectKoSyncAccountInput): CompletableFuture<KoSyncConnectPayload> =
future {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val result = KoreaderSyncService.connect(input.username, input.password)
KoSyncConnectPayload(
@@ -47,12 +41,9 @@ class KoreaderSyncMutation {
val clientMutationId: String? = null,
)
fun logoutKoSyncAccount(
dataFetchingEnvironment: DataFetchingEnvironment,
input: LogoutKoSyncAccountInput,
): CompletableFuture<LogoutKoSyncAccountPayload> =
@RequireAuth
fun logoutKoSyncAccount(input: LogoutKoSyncAccountInput): CompletableFuture<LogoutKoSyncAccountPayload> =
future {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
KoreaderSyncService.logout()
LogoutKoSyncAccountPayload(
clientMutationId = input.clientMutationId,
@@ -72,14 +63,10 @@ class KoreaderSyncMutation {
val chapter: ChapterType?,
)
fun pushKoSyncProgress(
dataFetchingEnvironment: DataFetchingEnvironment,
input: PushKoSyncProgressInput,
): CompletableFuture<DataFetcherResult<PushKoSyncProgressPayload?>> =
@RequireAuth
fun pushKoSyncProgress(input: PushKoSyncProgressInput): CompletableFuture<DataFetcherResult<PushKoSyncProgressPayload?>> =
future {
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
KoreaderSyncService.pushProgress(input.chapterId)
val chapter =
@@ -110,14 +97,10 @@ class KoreaderSyncMutation {
val syncConflict: SyncConflictInfoType?,
)
fun pullKoSyncProgress(
dataFetchingEnvironment: DataFetchingEnvironment,
input: PullKoSyncProgressInput,
): CompletableFuture<DataFetcherResult<PullKoSyncProgressPayload?>> =
@RequireAuth
fun pullKoSyncProgress(input: PullKoSyncProgressInput): CompletableFuture<DataFetcherResult<PullKoSyncProgressPayload?>> =
future {
asDataFetcherResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val syncResult = KoreaderSyncService.checkAndPullProgress(input.chapterId)
var syncConflictInfo: SyncConflictInfoType? = null

View File

@@ -1,7 +1,6 @@
package suwayomi.tachidesk.graphql.mutations
import graphql.execution.DataFetcherResult
import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.deleteWhere
@@ -9,7 +8,7 @@ import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
import suwayomi.tachidesk.graphql.asDataFetcherResult
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.MangaMetaType
import suwayomi.tachidesk.graphql.types.MangaType
import suwayomi.tachidesk.manga.impl.Library
@@ -18,10 +17,7 @@ import suwayomi.tachidesk.manga.impl.update.IUpdater
import suwayomi.tachidesk.manga.model.table.MangaMetaTable
import suwayomi.tachidesk.manga.model.table.MangaTable
import suwayomi.tachidesk.manga.model.table.toDataClass
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 uy.kohesive.injekt.injectLazy
import java.time.Instant
import java.util.concurrent.CompletableFuture
@@ -95,11 +91,8 @@ class MangaMutation {
}
}
fun updateManga(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UpdateMangaInput,
): CompletableFuture<DataFetcherResult<UpdateMangaPayload?>> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun updateManga(input: UpdateMangaInput): CompletableFuture<DataFetcherResult<UpdateMangaPayload?>> {
val (clientMutationId, id, patch) = input
return future {
@@ -119,11 +112,8 @@ class MangaMutation {
}
}
fun updateMangas(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UpdateMangasInput,
): CompletableFuture<DataFetcherResult<UpdateMangasPayload?>> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun updateMangas(input: UpdateMangasInput): CompletableFuture<DataFetcherResult<UpdateMangasPayload?>> {
val (clientMutationId, ids, patch) = input
return future {
@@ -153,11 +143,8 @@ class MangaMutation {
val manga: MangaType,
)
fun fetchManga(
dataFetchingEnvironment: DataFetchingEnvironment,
input: FetchMangaInput,
): CompletableFuture<DataFetcherResult<FetchMangaPayload?>> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun fetchManga(input: FetchMangaInput): CompletableFuture<DataFetcherResult<FetchMangaPayload?>> {
val (clientMutationId, id) = input
return future {
@@ -186,11 +173,8 @@ class MangaMutation {
val meta: MangaMetaType,
)
fun setMangaMeta(
dataFetchingEnvironment: DataFetchingEnvironment,
input: SetMangaMetaInput,
): DataFetcherResult<SetMangaMetaPayload?> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun setMangaMeta(input: SetMangaMetaInput): DataFetcherResult<SetMangaMetaPayload?> {
val (clientMutationId, meta) = input
return asDataFetcherResult {
@@ -212,11 +196,8 @@ class MangaMutation {
val manga: MangaType,
)
fun deleteMangaMeta(
dataFetchingEnvironment: DataFetchingEnvironment,
input: DeleteMangaMetaInput,
): DataFetcherResult<DeleteMangaMetaPayload?> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun deleteMangaMeta(input: DeleteMangaMetaInput): DataFetcherResult<DeleteMangaMetaPayload?> {
val (clientMutationId, mangaId, key) = input
return asDataFetcherResult {

View File

@@ -1,7 +1,6 @@
package suwayomi.tachidesk.graphql.mutations
import graphql.execution.DataFetcherResult
import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.deleteWhere
import org.jetbrains.exposed.sql.selectAll
@@ -9,11 +8,8 @@ import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.global.impl.GlobalMeta
import suwayomi.tachidesk.global.model.table.GlobalMetaTable
import suwayomi.tachidesk.graphql.asDataFetcherResult
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.GlobalMetaType
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
import suwayomi.tachidesk.server.user.requireUser
class MetaMutation {
data class SetGlobalMetaInput(
@@ -26,11 +22,8 @@ class MetaMutation {
val meta: GlobalMetaType,
)
fun setGlobalMeta(
dataFetchingEnvironment: DataFetchingEnvironment,
input: SetGlobalMetaInput,
): DataFetcherResult<SetGlobalMetaPayload?> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun setGlobalMeta(input: SetGlobalMetaInput): DataFetcherResult<SetGlobalMetaPayload?> {
val (clientMutationId, meta) = input
return asDataFetcherResult {
@@ -50,11 +43,8 @@ class MetaMutation {
val meta: GlobalMetaType?,
)
fun deleteGlobalMeta(
dataFetchingEnvironment: DataFetchingEnvironment,
input: DeleteGlobalMetaInput,
): DataFetcherResult<DeleteGlobalMetaPayload?> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun deleteGlobalMeta(input: DeleteGlobalMetaInput): DataFetcherResult<DeleteGlobalMetaPayload?> {
val (clientMutationId, key) = input
return asDataFetcherResult {

View File

@@ -1,17 +1,14 @@
package suwayomi.tachidesk.graphql.mutations
import com.expediagroup.graphql.generator.annotations.GraphQLIgnore
import graphql.schema.DataFetchingEnvironment
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.PartialSettingsType
import suwayomi.tachidesk.graphql.types.Settings
import suwayomi.tachidesk.graphql.types.SettingsType
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.SERVER_CONFIG_MODULE_NAME
import suwayomi.tachidesk.server.ServerConfig
import suwayomi.tachidesk.server.settings.SettingsUpdater
import suwayomi.tachidesk.server.settings.SettingsValidator
import suwayomi.tachidesk.server.user.requireUser
import xyz.nulldev.ts.config.GlobalConfigManager
class SettingsMutation {
@@ -35,11 +32,8 @@ class SettingsMutation {
SettingsUpdater.updateAll(settings)
}
fun setSettings(
dataFetchingEnvironment: DataFetchingEnvironment,
input: SetSettingsInput,
): SetSettingsPayload {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun setSettings(input: SetSettingsInput): SetSettingsPayload {
val (clientMutationId, settings) = input
updateSettings(settings)
@@ -56,11 +50,8 @@ class SettingsMutation {
val settings: SettingsType,
)
fun resetSettings(
dataFetchingEnvironment: DataFetchingEnvironment,
input: ResetSettingsInput,
): ResetSettingsPayload {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun resetSettings(input: ResetSettingsInput): ResetSettingsPayload {
val (clientMutationId) = input
GlobalConfigManager.resetUserConfig()

View File

@@ -6,14 +6,13 @@ import androidx.preference.ListPreference
import androidx.preference.MultiSelectListPreference
import androidx.preference.SwitchPreferenceCompat
import graphql.execution.DataFetcherResult
import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.deleteWhere
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.asDataFetcherResult
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.FilterChange
import suwayomi.tachidesk.graphql.types.MangaType
import suwayomi.tachidesk.graphql.types.Preference
@@ -27,10 +26,7 @@ import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource
import suwayomi.tachidesk.manga.model.table.MangaTable
import suwayomi.tachidesk.manga.model.table.SourceMetaTable
import suwayomi.tachidesk.manga.model.table.SourceTable
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 java.util.concurrent.CompletableFuture
class SourceMutation {
@@ -44,11 +40,8 @@ class SourceMutation {
val meta: SourceMetaType,
)
fun setSourceMeta(
dataFetchingEnvironment: DataFetchingEnvironment,
input: SetSourceMetaInput,
): DataFetcherResult<SetSourceMetaPayload?> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun setSourceMeta(input: SetSourceMetaInput): DataFetcherResult<SetSourceMetaPayload?> {
val (clientMutationId, meta) = input
return asDataFetcherResult {
@@ -70,11 +63,8 @@ class SourceMutation {
val source: SourceType?,
)
fun deleteSourceMeta(
dataFetchingEnvironment: DataFetchingEnvironment,
input: DeleteSourceMetaInput,
): DataFetcherResult<DeleteSourceMetaPayload?> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun deleteSourceMeta(input: DeleteSourceMetaInput): DataFetcherResult<DeleteSourceMetaPayload?> {
val (clientMutationId, sourceId, key) = input
return asDataFetcherResult {
@@ -129,11 +119,8 @@ class SourceMutation {
val hasNextPage: Boolean,
)
fun fetchSourceManga(
dataFetchingEnvironment: DataFetchingEnvironment,
input: FetchSourceMangaInput,
): CompletableFuture<DataFetcherResult<FetchSourceMangaPayload?>> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun fetchSourceManga(input: FetchSourceMangaInput): CompletableFuture<DataFetcherResult<FetchSourceMangaPayload?>> {
val (clientMutationId, sourceId, type, page, query, filters) = input
return future {
@@ -199,11 +186,8 @@ class SourceMutation {
val source: SourceType,
)
fun updateSourcePreference(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UpdateSourcePreferenceInput,
): DataFetcherResult<UpdateSourcePreferencePayload?> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun updateSourcePreference(input: UpdateSourcePreferenceInput): DataFetcherResult<UpdateSourcePreferencePayload?> {
val (clientMutationId, sourceId, change) = input
return asDataFetcherResult {

View File

@@ -3,21 +3,17 @@ package suwayomi.tachidesk.graphql.mutations
import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated
import com.expediagroup.graphql.generator.annotations.GraphQLDescription
import graphql.execution.DataFetcherResult
import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.asDataFetcherResult
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.TrackRecordType
import suwayomi.tachidesk.graphql.types.TrackerType
import suwayomi.tachidesk.manga.impl.track.Track
import suwayomi.tachidesk.manga.impl.track.tracker.TrackerManager
import suwayomi.tachidesk.manga.model.table.TrackRecordTable
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 java.util.concurrent.CompletableFuture
class TrackMutation {
@@ -33,11 +29,8 @@ class TrackMutation {
val tracker: TrackerType,
)
fun loginTrackerOAuth(
dataFetchingEnvironment: DataFetchingEnvironment,
input: LoginTrackerOAuthInput,
): CompletableFuture<LoginTrackerOAuthPayload> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun loginTrackerOAuth(input: LoginTrackerOAuthInput): CompletableFuture<LoginTrackerOAuthPayload> {
val tracker =
requireNotNull(TrackerManager.getTracker(input.trackerId)) {
"Could not find tracker"
@@ -66,11 +59,8 @@ class TrackMutation {
val tracker: TrackerType,
)
fun loginTrackerCredentials(
dataFetchingEnvironment: DataFetchingEnvironment,
input: LoginTrackerCredentialsInput,
): CompletableFuture<LoginTrackerCredentialsPayload> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun loginTrackerCredentials(input: LoginTrackerCredentialsInput): CompletableFuture<LoginTrackerCredentialsPayload> {
val tracker =
requireNotNull(TrackerManager.getTracker(input.trackerId)) {
"Could not find tracker"
@@ -97,11 +87,8 @@ class TrackMutation {
val tracker: TrackerType,
)
fun logoutTracker(
dataFetchingEnvironment: DataFetchingEnvironment,
input: LogoutTrackerInput,
): CompletableFuture<LogoutTrackerPayload> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun logoutTracker(input: LogoutTrackerInput): CompletableFuture<LogoutTrackerPayload> {
val tracker =
requireNotNull(TrackerManager.getTracker(input.trackerId)) {
"Could not find tracker"
@@ -134,11 +121,8 @@ class TrackMutation {
val trackRecord: TrackRecordType,
)
fun bindTrack(
dataFetchingEnvironment: DataFetchingEnvironment,
input: BindTrackInput,
): CompletableFuture<BindTrackPayload> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun bindTrack(input: BindTrackInput): CompletableFuture<BindTrackPayload> {
val (clientMutationId, mangaId, trackerId, remoteId, private) = input
return future {
@@ -173,11 +157,8 @@ class TrackMutation {
val trackRecord: TrackRecordType,
)
fun fetchTrack(
dataFetchingEnvironment: DataFetchingEnvironment,
input: FetchTrackInput,
): CompletableFuture<FetchTrackPayload> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun fetchTrack(input: FetchTrackInput): CompletableFuture<FetchTrackPayload> {
val (clientMutationId, recordId) = input
return future {
@@ -209,11 +190,8 @@ class TrackMutation {
val trackRecord: TrackRecordType?,
)
fun unbindTrack(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UnbindTrackInput,
): CompletableFuture<UnbindTrackPayload> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun unbindTrack(input: UnbindTrackInput): CompletableFuture<UnbindTrackPayload> {
val (clientMutationId, recordId, deleteRemoteTrack) = input
return future {
@@ -243,11 +221,8 @@ class TrackMutation {
val trackRecords: List<TrackRecordType>,
)
fun trackProgress(
dataFetchingEnvironment: DataFetchingEnvironment,
input: TrackProgressInput,
): CompletableFuture<DataFetcherResult<TrackProgressPayload?>> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun trackProgress(input: TrackProgressInput): CompletableFuture<DataFetcherResult<TrackProgressPayload?>> {
val (clientMutationId, mangaId) = input
return future {
@@ -289,12 +264,9 @@ class TrackMutation {
val trackRecord: TrackRecordType?,
)
fun updateTrack(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UpdateTrackInput,
): CompletableFuture<UpdateTrackPayload> =
@RequireAuth
fun updateTrack(input: UpdateTrackInput): CompletableFuture<UpdateTrackPayload> =
future {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
Track.update(
Track.UpdateInput(
input.recordId,

View File

@@ -1,19 +1,15 @@
package suwayomi.tachidesk.graphql.mutations
import graphql.execution.DataFetcherResult
import graphql.schema.DataFetchingEnvironment
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withTimeout
import suwayomi.tachidesk.graphql.asDataFetcherResult
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.LibraryUpdateStatus
import suwayomi.tachidesk.graphql.types.UpdateStatus
import suwayomi.tachidesk.manga.impl.Category
import suwayomi.tachidesk.manga.impl.update.IUpdater
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 uy.kohesive.injekt.injectLazy
import java.util.concurrent.CompletableFuture
import kotlin.time.Duration.Companion.seconds
@@ -31,11 +27,8 @@ class UpdateMutation {
val updateStatus: LibraryUpdateStatus,
)
fun updateLibrary(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UpdateLibraryInput,
): CompletableFuture<DataFetcherResult<UpdateLibraryPayload?>> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun updateLibrary(input: UpdateLibraryInput): CompletableFuture<DataFetcherResult<UpdateLibraryPayload?>> {
updater.addCategoriesToUpdateQueue(
Category.getCategoryList().filter { input.categories?.contains(it.id) ?: true },
clear = true,
@@ -66,12 +59,9 @@ class UpdateMutation {
val updateStatus: UpdateStatus,
)
fun updateLibraryManga(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UpdateLibraryMangaInput,
): CompletableFuture<DataFetcherResult<UpdateLibraryMangaPayload?>> {
@RequireAuth
fun updateLibraryManga(input: UpdateLibraryMangaInput): CompletableFuture<DataFetcherResult<UpdateLibraryMangaPayload?>> {
updateLibrary(
dataFetchingEnvironment,
UpdateLibraryInput(
clientMutationId = input.clientMutationId,
categories = null,
@@ -101,12 +91,9 @@ class UpdateMutation {
val updateStatus: UpdateStatus,
)
fun updateCategoryManga(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UpdateCategoryMangaInput,
): CompletableFuture<DataFetcherResult<UpdateCategoryMangaPayload?>> {
@RequireAuth
fun updateCategoryManga(input: UpdateCategoryMangaInput): CompletableFuture<DataFetcherResult<UpdateCategoryMangaPayload?>> {
updateLibrary(
dataFetchingEnvironment,
UpdateLibraryInput(
clientMutationId = input.clientMutationId,
categories = input.categories,
@@ -134,11 +121,8 @@ class UpdateMutation {
val clientMutationId: String?,
)
fun updateStop(
dataFetchingEnvironment: DataFetchingEnvironment,
input: UpdateStopInput,
): UpdateStopPayload {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun updateStop(input: UpdateStopInput): UpdateStopPayload {
updater.reset()
return UpdateStopPayload(input.clientMutationId)
}

View File

@@ -2,9 +2,9 @@ package suwayomi.tachidesk.graphql.mutations
import graphql.schema.DataFetchingEnvironment
import suwayomi.tachidesk.global.impl.util.Jwt
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
import suwayomi.tachidesk.server.serverConfig
import suwayomi.tachidesk.server.user.UserType

View File

@@ -1,15 +1,11 @@
package suwayomi.tachidesk.graphql.queries
import graphql.schema.DataFetchingEnvironment
import io.javalin.http.UploadedFile
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.BackupRestoreStatus
import suwayomi.tachidesk.graphql.types.toStatus
import suwayomi.tachidesk.manga.impl.backup.proto.ProtoBackupImport
import suwayomi.tachidesk.manga.impl.backup.proto.ProtoBackupValidator
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
import suwayomi.tachidesk.server.user.requireUser
class BackupQuery {
data class ValidateBackupInput(
@@ -30,11 +26,8 @@ class BackupQuery {
val missingTrackers: List<ValidateBackupTracker>,
)
fun validateBackup(
dataFetchingEnvironment: DataFetchingEnvironment,
input: ValidateBackupInput,
): ValidateBackupResult {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun validateBackup(input: ValidateBackupInput): ValidateBackupResult {
val result = ProtoBackupValidator.validate(input.backup.content())
return ValidateBackupResult(
result.missingSourceIds.map { ValidateBackupSource(it.first, it.second) },
@@ -42,11 +35,6 @@ class BackupQuery {
)
}
fun restoreStatus(
dataFetchingEnvironment: DataFetchingEnvironment,
id: String,
): BackupRestoreStatus? {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
return ProtoBackupImport.getRestoreState(id)?.toStatus()
}
@RequireAuth
fun restoreStatus(id: String): BackupRestoreStatus? = ProtoBackupImport.getRestoreState(id)?.toStatus()
}

View File

@@ -17,6 +17,7 @@ import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
import suwayomi.tachidesk.graphql.queries.filter.Filter
import suwayomi.tachidesk.graphql.queries.filter.HasGetOp
@@ -27,7 +28,6 @@ import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompare
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompareEntity
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompareString
import suwayomi.tachidesk.graphql.queries.filter.applyOps
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.server.primitives.Cursor
import suwayomi.tachidesk.graphql.server.primitives.Order
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
@@ -40,19 +40,14 @@ import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
import suwayomi.tachidesk.graphql.types.CategoryNodeList
import suwayomi.tachidesk.graphql.types.CategoryType
import suwayomi.tachidesk.manga.model.table.CategoryTable
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
import suwayomi.tachidesk.server.user.requireUser
import java.util.concurrent.CompletableFuture
class CategoryQuery {
@RequireAuth
fun category(
dataFetchingEnvironment: DataFetchingEnvironment,
id: Int,
): CompletableFuture<CategoryType> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
return dataFetchingEnvironment.getValueFromDataLoader("CategoryDataLoader", id)
}
): CompletableFuture<CategoryType> = dataFetchingEnvironment.getValueFromDataLoader("CategoryDataLoader", id)
enum class CategoryOrderBy(
override val column: Column<*>,
@@ -127,8 +122,8 @@ class CategoryQuery {
)
}
@RequireAuth
fun categories(
dataFetchingEnvironment: DataFetchingEnvironment,
condition: CategoryCondition? = null,
filter: CategoryFilter? = null,
@GraphQLDeprecated(
@@ -148,7 +143,6 @@ class CategoryQuery {
last: Int? = null,
offset: Int? = null,
): CategoryNodeList {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val queryResults =
transaction {
val res = CategoryTable.selectAll()

View File

@@ -18,6 +18,7 @@ import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
import org.jetbrains.exposed.sql.andWhere
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
import suwayomi.tachidesk.graphql.queries.filter.Filter
import suwayomi.tachidesk.graphql.queries.filter.FloatFilter
@@ -30,7 +31,6 @@ import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompare
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompareEntity
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompareString
import suwayomi.tachidesk.graphql.queries.filter.applyOps
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.server.primitives.Cursor
import suwayomi.tachidesk.graphql.server.primitives.Order
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
@@ -44,9 +44,6 @@ import suwayomi.tachidesk.graphql.types.ChapterNodeList
import suwayomi.tachidesk.graphql.types.ChapterType
import suwayomi.tachidesk.manga.model.table.ChapterTable
import suwayomi.tachidesk.manga.model.table.MangaTable
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
import suwayomi.tachidesk.server.user.requireUser
import java.util.concurrent.CompletableFuture
/**
@@ -55,6 +52,7 @@ import java.util.concurrent.CompletableFuture
* - Get page list?
*/
class ChapterQuery {
@RequireAuth
fun chapter(
dataFetchingEnvironment: DataFetchingEnvironment,
id: Int,
@@ -200,8 +198,8 @@ class ChapterQuery {
fun getLibraryOp() = andFilterWithCompare(MangaTable.inLibrary, inLibrary)
}
@RequireAuth
fun chapters(
dataFetchingEnvironment: DataFetchingEnvironment,
condition: ChapterCondition? = null,
filter: ChapterFilter? = null,
@GraphQLDeprecated(
@@ -221,7 +219,6 @@ class ChapterQuery {
last: Int? = null,
offset: Int? = null,
): ChapterNodeList {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val queryResults =
transaction {
val res = ChapterTable.selectAll()

View File

@@ -1,19 +1,15 @@
package suwayomi.tachidesk.graphql.queries
import graphql.schema.DataFetchingEnvironment
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.DownloadStatus
import suwayomi.tachidesk.manga.impl.download.DownloadManager
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 java.util.concurrent.CompletableFuture
class DownloadQuery {
fun downloadStatus(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<DownloadStatus> =
@RequireAuth
fun downloadStatus(): CompletableFuture<DownloadStatus> =
future {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
DownloadStatus(DownloadManager.getStatus())
}
}

View File

@@ -19,6 +19,7 @@ import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
import org.jetbrains.exposed.sql.SqlExpressionBuilder.neq
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
import suwayomi.tachidesk.graphql.queries.filter.Filter
import suwayomi.tachidesk.graphql.queries.filter.HasGetOp
@@ -28,7 +29,6 @@ import suwayomi.tachidesk.graphql.queries.filter.StringFilter
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompare
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompareString
import suwayomi.tachidesk.graphql.queries.filter.applyOps
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.server.primitives.Cursor
import suwayomi.tachidesk.graphql.server.primitives.Order
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
@@ -41,19 +41,14 @@ import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
import suwayomi.tachidesk.graphql.types.ExtensionNodeList
import suwayomi.tachidesk.graphql.types.ExtensionType
import suwayomi.tachidesk.manga.model.table.ExtensionTable
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
import suwayomi.tachidesk.server.user.requireUser
import java.util.concurrent.CompletableFuture
class ExtensionQuery {
@RequireAuth
fun extension(
dataFetchingEnvironment: DataFetchingEnvironment,
pkgName: String,
): CompletableFuture<ExtensionType> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
return dataFetchingEnvironment.getValueFromDataLoader("ExtensionDataLoader", pkgName)
}
): CompletableFuture<ExtensionType> = dataFetchingEnvironment.getValueFromDataLoader("ExtensionDataLoader", pkgName)
enum class ExtensionOrderBy(
override val column: Column<*>,
@@ -159,8 +154,8 @@ class ExtensionQuery {
)
}
@RequireAuth
fun extensions(
dataFetchingEnvironment: DataFetchingEnvironment,
condition: ExtensionCondition? = null,
filter: ExtensionFilter? = null,
@GraphQLDeprecated(
@@ -180,7 +175,6 @@ class ExtensionQuery {
last: Int? = null,
offset: Int? = null,
): ExtensionNodeList {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val queryResults =
transaction {
val res = ExtensionTable.selectAll()

View File

@@ -1,19 +1,15 @@
package suwayomi.tachidesk.graphql.queries
import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated
import graphql.schema.DataFetchingEnvironment
import suwayomi.tachidesk.global.impl.AppUpdate
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.AboutWebUI
import suwayomi.tachidesk.graphql.types.WebUIFlavor
import suwayomi.tachidesk.graphql.types.WebUIUpdateCheck
import suwayomi.tachidesk.graphql.types.WebUIUpdateStatus
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.future
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
import suwayomi.tachidesk.server.generated.BuildConfig
import suwayomi.tachidesk.server.serverConfig
import suwayomi.tachidesk.server.user.requireUser
import suwayomi.tachidesk.server.util.WebInterfaceManager
import java.util.concurrent.CompletableFuture
@@ -47,9 +43,9 @@ class InfoQuery {
val url: String,
)
fun checkForServerUpdates(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<CheckForServerUpdatesPayload>> =
@RequireAuth
fun checkForServerUpdates(): CompletableFuture<List<CheckForServerUpdatesPayload>> =
future {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
AppUpdate.checkUpdate().map {
CheckForServerUpdatesPayload(
channel = it.channel,
@@ -59,15 +55,15 @@ class InfoQuery {
}
}
fun aboutWebUI(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<AboutWebUI> =
@RequireAuth
fun aboutWebUI(): CompletableFuture<AboutWebUI> =
future {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
WebInterfaceManager.getAboutInfo()
}
fun checkForWebUIUpdate(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<WebUIUpdateCheck> =
@RequireAuth
fun checkForWebUIUpdate(): CompletableFuture<WebUIUpdateCheck> =
future {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (version, updateAvailable) = WebInterfaceManager.isUpdateAvailable(WebUIFlavor.current, raiseError = true)
WebUIUpdateCheck(
channel = serverConfig.webUIChannel.value,
@@ -76,8 +72,6 @@ class InfoQuery {
)
}
fun getWebUIUpdateStatus(dataFetchingEnvironment: DataFetchingEnvironment): WebUIUpdateStatus {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
return WebInterfaceManager.status.value
}
@RequireAuth
fun getWebUIUpdateStatus(): WebUIUpdateStatus = WebInterfaceManager.status.value
}

View File

@@ -1,19 +1,15 @@
package suwayomi.tachidesk.graphql.queries
import graphql.schema.DataFetchingEnvironment
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.KoSyncStatusPayload
import suwayomi.tachidesk.manga.impl.sync.KoreaderSyncService
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 java.util.concurrent.CompletableFuture
class KoreaderSyncQuery {
fun koSyncStatus(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<KoSyncStatusPayload> =
@RequireAuth
fun koSyncStatus(): CompletableFuture<KoSyncStatusPayload> =
future {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
KoreaderSyncService.getStatus()
}
}

View File

@@ -16,6 +16,7 @@ import org.jetbrains.exposed.sql.SortOrder
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
import suwayomi.tachidesk.graphql.queries.filter.ComparableScalarFilter
import suwayomi.tachidesk.graphql.queries.filter.Filter
@@ -28,7 +29,6 @@ import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompare
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompareEntity
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompareString
import suwayomi.tachidesk.graphql.queries.filter.applyOps
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.server.primitives.Cursor
import suwayomi.tachidesk.graphql.server.primitives.Order
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
@@ -43,19 +43,14 @@ import suwayomi.tachidesk.graphql.types.MangaType
import suwayomi.tachidesk.manga.model.table.CategoryMangaTable
import suwayomi.tachidesk.manga.model.table.MangaStatus
import suwayomi.tachidesk.manga.model.table.MangaTable
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
import suwayomi.tachidesk.server.user.requireUser
import java.util.concurrent.CompletableFuture
class MangaQuery {
@RequireAuth
fun manga(
dataFetchingEnvironment: DataFetchingEnvironment,
id: Int,
): CompletableFuture<MangaType> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
return dataFetchingEnvironment.getValueFromDataLoader("MangaDataLoader", id)
}
): CompletableFuture<MangaType> = dataFetchingEnvironment.getValueFromDataLoader("MangaDataLoader", id)
enum class MangaOrderBy(
override val column: Column<*>,
@@ -222,8 +217,8 @@ class MangaQuery {
)
}
@RequireAuth
fun mangas(
dataFetchingEnvironment: DataFetchingEnvironment,
condition: MangaCondition? = null,
filter: MangaFilter? = null,
@GraphQLDeprecated(
@@ -243,7 +238,6 @@ class MangaQuery {
last: Int? = null,
offset: Int? = null,
): MangaNodeList {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val queryResults =
transaction {
val res =

View File

@@ -18,13 +18,13 @@ import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.global.model.table.GlobalMetaTable
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.queries.filter.Filter
import suwayomi.tachidesk.graphql.queries.filter.HasGetOp
import suwayomi.tachidesk.graphql.queries.filter.OpAnd
import suwayomi.tachidesk.graphql.queries.filter.StringFilter
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompareString
import suwayomi.tachidesk.graphql.queries.filter.applyOps
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.server.primitives.Cursor
import suwayomi.tachidesk.graphql.server.primitives.Order
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
@@ -36,19 +36,14 @@ import suwayomi.tachidesk.graphql.server.primitives.lessNotUnique
import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
import suwayomi.tachidesk.graphql.types.GlobalMetaNodeList
import suwayomi.tachidesk.graphql.types.GlobalMetaType
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
import suwayomi.tachidesk.server.user.requireUser
import java.util.concurrent.CompletableFuture
class MetaQuery {
@RequireAuth
fun meta(
dataFetchingEnvironment: DataFetchingEnvironment,
key: String,
): CompletableFuture<GlobalMetaType> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
return dataFetchingEnvironment.getValueFromDataLoader("GlobalMetaDataLoader", key)
}
): CompletableFuture<GlobalMetaType> = dataFetchingEnvironment.getValueFromDataLoader("GlobalMetaDataLoader", key)
enum class MetaOrderBy(
override val column: Column<*>,
@@ -111,8 +106,8 @@ class MetaQuery {
)
}
@RequireAuth
fun metas(
dataFetchingEnvironment: DataFetchingEnvironment,
condition: MetaCondition? = null,
filter: MetaFilter? = null,
@GraphQLDeprecated(
@@ -132,7 +127,6 @@ class MetaQuery {
last: Int? = null,
offset: Int? = null,
): GlobalMetaNodeList {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val queryResults =
transaction {
val res = GlobalMetaTable.selectAll()

View File

@@ -1,15 +1,9 @@
package suwayomi.tachidesk.graphql.queries
import graphql.schema.DataFetchingEnvironment
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.SettingsType
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
import suwayomi.tachidesk.server.user.requireUser
class SettingsQuery {
fun settings(dataFetchingEnvironment: DataFetchingEnvironment): SettingsType {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
return SettingsType()
}
@RequireAuth
fun settings(): SettingsType = SettingsType()
}

View File

@@ -17,6 +17,7 @@ import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
import suwayomi.tachidesk.graphql.queries.filter.Filter
import suwayomi.tachidesk.graphql.queries.filter.HasGetOp
@@ -27,7 +28,6 @@ import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompare
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompareEntity
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompareString
import suwayomi.tachidesk.graphql.queries.filter.applyOps
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.server.primitives.Cursor
import suwayomi.tachidesk.graphql.server.primitives.Order
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
@@ -40,19 +40,14 @@ import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
import suwayomi.tachidesk.graphql.types.SourceNodeList
import suwayomi.tachidesk.graphql.types.SourceType
import suwayomi.tachidesk.manga.model.table.SourceTable
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
import suwayomi.tachidesk.server.user.requireUser
import java.util.concurrent.CompletableFuture
class SourceQuery {
@RequireAuth
fun source(
dataFetchingEnvironment: DataFetchingEnvironment,
id: Long,
): CompletableFuture<SourceType> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
return dataFetchingEnvironment.getValueFromDataLoader("SourceDataLoader", id)
}
): CompletableFuture<SourceType> = dataFetchingEnvironment.getValueFromDataLoader("SourceDataLoader", id)
enum class SourceOrderBy(
override val column: Column<*>,
@@ -127,8 +122,8 @@ class SourceQuery {
)
}
@RequireAuth
fun sources(
dataFetchingEnvironment: DataFetchingEnvironment,
condition: SourceCondition? = null,
filter: SourceFilter? = null,
@GraphQLDeprecated(
@@ -148,7 +143,6 @@ class SourceQuery {
last: Int? = null,
offset: Int? = null,
): SourceNodeList {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (queryResults, resultsAsType) =
transaction {
val res = SourceTable.selectAll()

View File

@@ -10,6 +10,7 @@ import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
import suwayomi.tachidesk.graphql.queries.filter.DoubleFilter
import suwayomi.tachidesk.graphql.queries.filter.Filter
@@ -22,7 +23,6 @@ import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompare
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompareEntity
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompareString
import suwayomi.tachidesk.graphql.queries.filter.applyOps
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.server.primitives.Cursor
import suwayomi.tachidesk.graphql.server.primitives.Order
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
@@ -40,20 +40,15 @@ import suwayomi.tachidesk.graphql.types.TrackerType
import suwayomi.tachidesk.manga.impl.track.tracker.TrackerManager
import suwayomi.tachidesk.manga.model.table.TrackRecordTable
import suwayomi.tachidesk.manga.model.table.insertAll
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 java.util.concurrent.CompletableFuture
class TrackQuery {
@RequireAuth
fun tracker(
dataFetchingEnvironment: DataFetchingEnvironment,
id: Int,
): CompletableFuture<TrackerType> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
return dataFetchingEnvironment.getValueFromDataLoader<Int, TrackerType>("TrackerDataLoader", id)
}
): CompletableFuture<TrackerType> = dataFetchingEnvironment.getValueFromDataLoader<Int, TrackerType>("TrackerDataLoader", id)
enum class TrackerOrderBy {
ID,
@@ -121,8 +116,8 @@ class TrackQuery {
val not: TrackerFilter? = null,
)
@RequireAuth
fun trackers(
dataFetchingEnvironment: DataFetchingEnvironment,
condition: TrackerCondition? = null,
@GraphQLDeprecated(
"Replaced with order",
@@ -141,7 +136,6 @@ class TrackQuery {
last: Int? = null,
offset: Int? = null,
): TrackerNodeList {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val (queryResults, resultsAsType) =
run {
var res = TrackerManager.services.map { TrackerType(it) }
@@ -246,13 +240,12 @@ class TrackQuery {
)
}
@RequireAuth
fun trackRecord(
dataFetchingEnvironment: DataFetchingEnvironment,
id: Int,
): CompletableFuture<TrackRecordType> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
return dataFetchingEnvironment.getValueFromDataLoader<Int, TrackRecordType>("TrackRecordDataLoader", id)
}
): CompletableFuture<TrackRecordType> =
dataFetchingEnvironment.getValueFromDataLoader<Int, TrackRecordType>("TrackRecordDataLoader", id)
enum class TrackRecordOrderBy(
override val column: Column<*>,
@@ -399,8 +392,8 @@ class TrackQuery {
)
}
@RequireAuth
fun trackRecords(
dataFetchingEnvironment: DataFetchingEnvironment,
condition: TrackRecordCondition? = null,
filter: TrackRecordFilter? = null,
@GraphQLDeprecated(
@@ -420,7 +413,6 @@ class TrackQuery {
last: Int? = null,
offset: Int? = null,
): TrackRecordNodeList {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val queryResults =
transaction {
val res = TrackRecordTable.selectAll()
@@ -503,12 +495,9 @@ class TrackQuery {
val trackSearches: List<TrackSearchType>,
)
fun searchTracker(
dataFetchingEnvironment: DataFetchingEnvironment,
input: SearchTrackerInput,
): CompletableFuture<SearchTrackerPayload> =
@RequireAuth
fun searchTracker(input: SearchTrackerInput): CompletableFuture<SearchTrackerPayload> =
future {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
val tracker =
requireNotNull(TrackerManager.getTracker(input.trackerId)) {
"Tracker not found"

View File

@@ -1,16 +1,12 @@
package suwayomi.tachidesk.graphql.queries
import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated
import graphql.schema.DataFetchingEnvironment
import kotlinx.coroutines.flow.first
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.LibraryUpdateStatus
import suwayomi.tachidesk.graphql.types.UpdateStatus
import suwayomi.tachidesk.manga.impl.update.IUpdater
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 uy.kohesive.injekt.injectLazy
import java.util.concurrent.CompletableFuture
@@ -18,15 +14,15 @@ class UpdateQuery {
private val updater: IUpdater by injectLazy()
@GraphQLDeprecated("Replaced with libraryUpdateStatus", ReplaceWith("libraryUpdateStatus"))
fun updateStatus(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<UpdateStatus> =
@RequireAuth
fun updateStatus(): CompletableFuture<UpdateStatus> =
future {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
UpdateStatus(updater.status.first())
}
fun libraryUpdateStatus(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<LibraryUpdateStatus> =
@RequireAuth
fun libraryUpdateStatus(): CompletableFuture<LibraryUpdateStatus> =
future {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
LibraryUpdateStatus(updater.getStatus())
}
@@ -34,8 +30,6 @@ class UpdateQuery {
val timestamp: Long,
)
fun lastUpdateTimestamp(dataFetchingEnvironment: DataFetchingEnvironment): LastUpdateTimestampPayload {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
return LastUpdateTimestampPayload(updater.getLastUpdateTimestamp())
}
@RequireAuth
fun lastUpdateTimestamp(): LastUpdateTimestampPayload = LastUpdateTimestampPayload(updater.getLastUpdateTimestamp())
}

View File

@@ -9,10 +9,12 @@ package suwayomi.tachidesk.graphql.server
import com.expediagroup.graphql.generator.SchemaGeneratorConfig
import com.expediagroup.graphql.generator.TopLevelObject
import com.expediagroup.graphql.generator.directives.KotlinDirectiveWiringFactory
import com.expediagroup.graphql.generator.hooks.FlowSubscriptionSchemaGeneratorHooks
import com.expediagroup.graphql.generator.toSchema
import graphql.schema.GraphQLType
import io.javalin.http.UploadedFile
import suwayomi.tachidesk.graphql.directives.RequireAuthDirectiveWiring
import suwayomi.tachidesk.graphql.mutations.BackupMutation
import suwayomi.tachidesk.graphql.mutations.CategoryMutation
import suwayomi.tachidesk.graphql.mutations.ChapterMutation
@@ -54,6 +56,11 @@ import kotlin.reflect.KType
import kotlin.time.Duration
class CustomSchemaGeneratorHooks : FlowSubscriptionSchemaGeneratorHooks() {
override val wiringFactory =
KotlinDirectiveWiringFactory(
manualWiring = mapOf("requireAuth" to RequireAuthDirectiveWiring()),
)
override fun willGenerateGraphQLType(type: KType): GraphQLType? =
when (type.classifier as? KClass<*>) {
Long::class -> GraphQLLongAsString // encode to string for JS

View File

@@ -16,6 +16,7 @@ import graphql.GraphQL
import graphql.execution.AsyncExecutionStrategy
import graphql.execution.DataFetcherExceptionHandler
import graphql.execution.DataFetcherExceptionHandlerResult
import graphql.schema.idl.RuntimeWiring
import io.github.oshai.kotlinlogging.KotlinLogging
import io.javalin.http.Context
import io.javalin.websocket.WsCloseContext

View File

@@ -9,25 +9,20 @@ package suwayomi.tachidesk.graphql.subscriptions
import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated
import com.expediagroup.graphql.generator.annotations.GraphQLDescription
import graphql.schema.DataFetchingEnvironment
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.DownloadStatus
import suwayomi.tachidesk.graphql.types.DownloadUpdates
import suwayomi.tachidesk.manga.impl.download.DownloadManager
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
import suwayomi.tachidesk.server.user.requireUser
class DownloadSubscription {
@GraphQLDeprecated("Replaced with downloadStatusChanged", ReplaceWith("downloadStatusChanged(input)"))
fun downloadChanged(dataFetchingEnvironment: DataFetchingEnvironment): Flow<DownloadStatus> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
return DownloadManager.status.map { downloadStatus ->
@RequireAuth
fun downloadChanged(): Flow<DownloadStatus> =
DownloadManager.status.map { downloadStatus ->
DownloadStatus(downloadStatus)
}
}
data class DownloadChangedInput(
@GraphQLDescription(
@@ -40,11 +35,8 @@ class DownloadSubscription {
val maxUpdates: Int?,
)
fun downloadStatusChanged(
dataFetchingEnvironment: DataFetchingEnvironment,
input: DownloadChangedInput,
): Flow<DownloadUpdates> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun downloadStatusChanged(input: DownloadChangedInput): Flow<DownloadUpdates> {
val omitUpdates = input.maxUpdates != null
val maxUpdates = input.maxUpdates ?: 50

View File

@@ -1,17 +1,11 @@
package suwayomi.tachidesk.graphql.subscriptions
import graphql.schema.DataFetchingEnvironment
import kotlinx.coroutines.flow.Flow
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.WebUIUpdateStatus
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
import suwayomi.tachidesk.server.user.requireUser
import suwayomi.tachidesk.server.util.WebInterfaceManager
class InfoSubscription {
fun webUIUpdateStatusChange(dataFetchingEnvironment: DataFetchingEnvironment): Flow<WebUIUpdateStatus> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
return WebInterfaceManager.status
}
@RequireAuth
fun webUIUpdateStatusChange(): Flow<WebUIUpdateStatus> = WebInterfaceManager.status
}

View File

@@ -9,29 +9,24 @@ package suwayomi.tachidesk.graphql.subscriptions
import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated
import com.expediagroup.graphql.generator.annotations.GraphQLDescription
import graphql.schema.DataFetchingEnvironment
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import suwayomi.tachidesk.graphql.server.getAttribute
import suwayomi.tachidesk.graphql.directives.RequireAuth
import suwayomi.tachidesk.graphql.types.UpdateStatus
import suwayomi.tachidesk.graphql.types.UpdaterUpdates
import suwayomi.tachidesk.manga.impl.update.IUpdater
import suwayomi.tachidesk.manga.impl.update.UpdateUpdates
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
import suwayomi.tachidesk.server.user.requireUser
import uy.kohesive.injekt.injectLazy
class UpdateSubscription {
private val updater: IUpdater by injectLazy()
@GraphQLDeprecated("Replaced with updates", ReplaceWith("updates(input)"))
fun updateStatusChanged(dataFetchingEnvironment: DataFetchingEnvironment): Flow<UpdateStatus> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
return updater.status.map { updateStatus ->
@RequireAuth
fun updateStatusChanged(): Flow<UpdateStatus> =
updater.status.map { updateStatus ->
UpdateStatus(updateStatus)
}
}
data class LibraryUpdateStatusChangedInput(
@GraphQLDescription(
@@ -44,11 +39,8 @@ class UpdateSubscription {
val maxUpdates: Int?,
)
fun libraryUpdateStatusChanged(
dataFetchingEnvironment: DataFetchingEnvironment,
input: LibraryUpdateStatusChangedInput,
): Flow<UpdaterUpdates> {
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
@RequireAuth
fun libraryUpdateStatusChanged(input: LibraryUpdateStatusChangedInput): Flow<UpdaterUpdates> {
val omitUpdates = input.maxUpdates != null
val maxUpdates = input.maxUpdates ?: 50