mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-15 16:54:09 -05:00
Basic JWT implementation (#1524)
* Basic JWT implementation * Move JWT to UI_LOGIN mode and bring back SIMPLE_LOGIN as before * Update server/src/main/kotlin/suwayomi/tachidesk/global/impl/util/Jwt.kt Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com> * Refresh: Update only access token Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com> * Implement JWT Audience * Store JWT key Generates the key on startup if not set * Handle invalid Base64 * Make JWT expiry configurable * Missing value parse * Update server/src/main/kotlin/suwayomi/tachidesk/global/impl/util/Jwt.kt Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com> * Simplify Duration parsing * JWT Protect Mutations * JWT Protect Queries and Subscriptions * JWT Protect v1 WebSockets * WebSockets allow sending token via protocol header * Also respect the `suwayomi-server-token` cookie * JWT reduce default token expiry * JWT Support cookie on WebSocket as well * Lint * Authenticate graphql subscription via connection_init payload * WebView: Prefer explicit token over cookie This hack was implemented because WebView sent `"null"` if no token was supplied, just don't send a bad token, then we can do this properly * WebView: Implement basic login dialog if no token supplied --------- Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com> Co-authored-by: schroda <50052685+schroda@users.noreply.github.com>
This commit is contained in:
@@ -1,16 +1,21 @@
|
||||
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.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
|
||||
|
||||
@@ -26,7 +31,11 @@ class BackupMutation {
|
||||
val status: BackupRestoreStatus?,
|
||||
)
|
||||
|
||||
fun restoreBackup(input: RestoreBackupInput): CompletableFuture<RestoreBackupPayload> {
|
||||
fun restoreBackup(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: RestoreBackupInput,
|
||||
): CompletableFuture<RestoreBackupPayload> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, backup) = input
|
||||
|
||||
return future {
|
||||
@@ -53,7 +62,11 @@ class BackupMutation {
|
||||
val url: String,
|
||||
)
|
||||
|
||||
fun createBackup(input: CreateBackupInput? = null): CreateBackupPayload {
|
||||
fun createBackup(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: CreateBackupInput? = null,
|
||||
): CreateBackupPayload {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val filename = Backup.getFilename()
|
||||
|
||||
val backup =
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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
|
||||
@@ -12,6 +13,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.types.CategoryMetaType
|
||||
import suwayomi.tachidesk.graphql.types.CategoryType
|
||||
import suwayomi.tachidesk.graphql.types.MangaType
|
||||
@@ -23,6 +25,9 @@ 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(
|
||||
@@ -35,8 +40,12 @@ class CategoryMutation {
|
||||
val meta: CategoryMetaType,
|
||||
)
|
||||
|
||||
fun setCategoryMeta(input: SetCategoryMetaInput): DataFetcherResult<SetCategoryMetaPayload?> =
|
||||
fun setCategoryMeta(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: SetCategoryMetaInput,
|
||||
): DataFetcherResult<SetCategoryMetaPayload?> =
|
||||
asDataFetcherResult {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, meta) = input
|
||||
|
||||
Category.modifyMeta(meta.categoryId, meta.key, meta.value)
|
||||
@@ -56,8 +65,12 @@ class CategoryMutation {
|
||||
val category: CategoryType,
|
||||
)
|
||||
|
||||
fun deleteCategoryMeta(input: DeleteCategoryMetaInput): DataFetcherResult<DeleteCategoryMetaPayload?> =
|
||||
fun deleteCategoryMeta(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: DeleteCategoryMetaInput,
|
||||
): DataFetcherResult<DeleteCategoryMetaPayload?> =
|
||||
asDataFetcherResult {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, categoryId, key) = input
|
||||
|
||||
val (meta, category) =
|
||||
@@ -150,8 +163,12 @@ class CategoryMutation {
|
||||
}
|
||||
}
|
||||
|
||||
fun updateCategory(input: UpdateCategoryInput): DataFetcherResult<UpdateCategoryPayload?> =
|
||||
fun updateCategory(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UpdateCategoryInput,
|
||||
): DataFetcherResult<UpdateCategoryPayload?> =
|
||||
asDataFetcherResult {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, id, patch) = input
|
||||
|
||||
updateCategories(listOf(id), patch)
|
||||
@@ -167,8 +184,12 @@ class CategoryMutation {
|
||||
)
|
||||
}
|
||||
|
||||
fun updateCategories(input: UpdateCategoriesInput): DataFetcherResult<UpdateCategoriesPayload?> =
|
||||
fun updateCategories(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UpdateCategoriesInput,
|
||||
): DataFetcherResult<UpdateCategoriesPayload?> =
|
||||
asDataFetcherResult {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, ids, patch) = input
|
||||
|
||||
updateCategories(ids, patch)
|
||||
@@ -195,8 +216,12 @@ class CategoryMutation {
|
||||
val position: Int,
|
||||
)
|
||||
|
||||
fun updateCategoryOrder(input: UpdateCategoryOrderInput): DataFetcherResult<UpdateCategoryOrderPayload?> =
|
||||
fun updateCategoryOrder(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UpdateCategoryOrderInput,
|
||||
): DataFetcherResult<UpdateCategoryOrderPayload?> =
|
||||
asDataFetcherResult {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, categoryId, position) = input
|
||||
require(position > 0) {
|
||||
"'order' must not be <= 0"
|
||||
@@ -253,8 +278,12 @@ class CategoryMutation {
|
||||
val category: CategoryType,
|
||||
)
|
||||
|
||||
fun createCategory(input: CreateCategoryInput): DataFetcherResult<CreateCategoryPayload?> =
|
||||
fun createCategory(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
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()) {
|
||||
@@ -312,8 +341,12 @@ class CategoryMutation {
|
||||
val mangas: List<MangaType>,
|
||||
)
|
||||
|
||||
fun deleteCategory(input: DeleteCategoryInput): DataFetcherResult<DeleteCategoryPayload?> {
|
||||
fun deleteCategory(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
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(
|
||||
@@ -401,8 +434,12 @@ class CategoryMutation {
|
||||
}
|
||||
}
|
||||
|
||||
fun updateMangaCategories(input: UpdateMangaCategoriesInput): DataFetcherResult<UpdateMangaCategoriesPayload?> =
|
||||
fun updateMangaCategories(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UpdateMangaCategoriesInput,
|
||||
): DataFetcherResult<UpdateMangaCategoriesPayload?> =
|
||||
asDataFetcherResult {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, id, patch) = input
|
||||
|
||||
updateMangas(listOf(id), patch)
|
||||
@@ -418,8 +455,12 @@ class CategoryMutation {
|
||||
)
|
||||
}
|
||||
|
||||
fun updateMangasCategories(input: UpdateMangasCategoriesInput): DataFetcherResult<UpdateMangasCategoriesPayload?> =
|
||||
fun updateMangasCategories(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UpdateMangasCategoriesInput,
|
||||
): DataFetcherResult<UpdateMangasCategoriesPayload?> =
|
||||
asDataFetcherResult {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, ids, patch) = input
|
||||
|
||||
updateMangas(ids, patch)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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
|
||||
@@ -12,6 +13,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.types.ChapterMetaType
|
||||
import suwayomi.tachidesk.graphql.types.ChapterType
|
||||
import suwayomi.tachidesk.graphql.types.SyncConflictInfoType
|
||||
@@ -20,7 +22,10 @@ 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
|
||||
@@ -112,8 +117,12 @@ class ChapterMutation {
|
||||
}
|
||||
}
|
||||
|
||||
fun updateChapter(input: UpdateChapterInput): DataFetcherResult<UpdateChapterPayload?> =
|
||||
fun updateChapter(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UpdateChapterInput,
|
||||
): DataFetcherResult<UpdateChapterPayload?> =
|
||||
asDataFetcherResult {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, id, patch) = input
|
||||
|
||||
updateChapters(listOf(id), patch)
|
||||
@@ -129,8 +138,12 @@ class ChapterMutation {
|
||||
)
|
||||
}
|
||||
|
||||
fun updateChapters(input: UpdateChaptersInput): DataFetcherResult<UpdateChaptersPayload?> =
|
||||
fun updateChapters(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UpdateChaptersInput,
|
||||
): DataFetcherResult<UpdateChaptersPayload?> =
|
||||
asDataFetcherResult {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, ids, patch) = input
|
||||
|
||||
updateChapters(ids, patch)
|
||||
@@ -156,7 +169,11 @@ class ChapterMutation {
|
||||
val chapters: List<ChapterType>,
|
||||
)
|
||||
|
||||
fun fetchChapters(input: FetchChaptersInput): CompletableFuture<DataFetcherResult<FetchChaptersPayload?>> {
|
||||
fun fetchChapters(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: FetchChaptersInput,
|
||||
): CompletableFuture<DataFetcherResult<FetchChaptersPayload?>> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, mangaId) = input
|
||||
|
||||
return future {
|
||||
@@ -190,8 +207,12 @@ class ChapterMutation {
|
||||
val meta: ChapterMetaType,
|
||||
)
|
||||
|
||||
fun setChapterMeta(input: SetChapterMetaInput): DataFetcherResult<SetChapterMetaPayload?> =
|
||||
fun setChapterMeta(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: SetChapterMetaInput,
|
||||
): DataFetcherResult<SetChapterMetaPayload?> =
|
||||
asDataFetcherResult {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, meta) = input
|
||||
|
||||
Chapter.modifyChapterMeta(meta.chapterId, meta.key, meta.value)
|
||||
@@ -211,8 +232,12 @@ class ChapterMutation {
|
||||
val chapter: ChapterType,
|
||||
)
|
||||
|
||||
fun deleteChapterMeta(input: DeleteChapterMetaInput): DataFetcherResult<DeleteChapterMetaPayload?> =
|
||||
fun deleteChapterMeta(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: DeleteChapterMetaInput,
|
||||
): DataFetcherResult<DeleteChapterMetaPayload?> =
|
||||
asDataFetcherResult {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, chapterId, key) = input
|
||||
|
||||
val (meta, chapter) =
|
||||
@@ -260,7 +285,11 @@ class ChapterMutation {
|
||||
val syncConflict: SyncConflictInfoType?,
|
||||
)
|
||||
|
||||
fun fetchChapterPages(input: FetchChapterPagesInput): CompletableFuture<DataFetcherResult<FetchChapterPagesPayload?>> {
|
||||
fun fetchChapterPages(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: FetchChapterPagesInput,
|
||||
): CompletableFuture<DataFetcherResult<FetchChapterPagesPayload?>> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, chapterId) = input
|
||||
val paramsMap = input.toParams()
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
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.types.ChapterType
|
||||
import suwayomi.tachidesk.graphql.types.DownloadStatus
|
||||
import suwayomi.tachidesk.manga.impl.Chapter
|
||||
@@ -13,7 +15,10 @@ 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.JavalinSetup.getAttribute
|
||||
import suwayomi.tachidesk.server.user.requireUser
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@@ -28,7 +33,11 @@ class DownloadMutation {
|
||||
val chapters: List<ChapterType>,
|
||||
)
|
||||
|
||||
fun deleteDownloadedChapters(input: DeleteDownloadedChaptersInput): DataFetcherResult<DeleteDownloadedChaptersPayload?> {
|
||||
fun deleteDownloadedChapters(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: DeleteDownloadedChaptersInput,
|
||||
): DataFetcherResult<DeleteDownloadedChaptersPayload?> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, chapters) = input
|
||||
|
||||
return asDataFetcherResult {
|
||||
@@ -57,7 +66,11 @@ class DownloadMutation {
|
||||
val chapters: ChapterType,
|
||||
)
|
||||
|
||||
fun deleteDownloadedChapter(input: DeleteDownloadedChapterInput): DataFetcherResult<DeleteDownloadedChapterPayload?> {
|
||||
fun deleteDownloadedChapter(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: DeleteDownloadedChapterInput,
|
||||
): DataFetcherResult<DeleteDownloadedChapterPayload?> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, chapter) = input
|
||||
|
||||
return asDataFetcherResult {
|
||||
@@ -84,8 +97,10 @@ class DownloadMutation {
|
||||
)
|
||||
|
||||
fun enqueueChapterDownloads(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: EnqueueChapterDownloadsInput,
|
||||
): CompletableFuture<DataFetcherResult<EnqueueChapterDownloadsPayload?>> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, chapters) = input
|
||||
|
||||
return future {
|
||||
@@ -118,7 +133,11 @@ class DownloadMutation {
|
||||
val downloadStatus: DownloadStatus,
|
||||
)
|
||||
|
||||
fun enqueueChapterDownload(input: EnqueueChapterDownloadInput): CompletableFuture<DataFetcherResult<EnqueueChapterDownloadPayload?>> {
|
||||
fun enqueueChapterDownload(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: EnqueueChapterDownloadInput,
|
||||
): CompletableFuture<DataFetcherResult<EnqueueChapterDownloadPayload?>> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, chapter) = input
|
||||
|
||||
return future {
|
||||
@@ -151,8 +170,10 @@ class DownloadMutation {
|
||||
)
|
||||
|
||||
fun dequeueChapterDownloads(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: DequeueChapterDownloadsInput,
|
||||
): CompletableFuture<DataFetcherResult<DequeueChapterDownloadsPayload?>> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, chapters) = input
|
||||
|
||||
return future {
|
||||
@@ -187,7 +208,11 @@ class DownloadMutation {
|
||||
val downloadStatus: DownloadStatus,
|
||||
)
|
||||
|
||||
fun dequeueChapterDownload(input: DequeueChapterDownloadInput): CompletableFuture<DataFetcherResult<DequeueChapterDownloadPayload?>> {
|
||||
fun dequeueChapterDownload(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: DequeueChapterDownloadInput,
|
||||
): CompletableFuture<DataFetcherResult<DequeueChapterDownloadPayload?>> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, chapter) = input
|
||||
|
||||
return future {
|
||||
@@ -221,9 +246,13 @@ class DownloadMutation {
|
||||
val downloadStatus: DownloadStatus,
|
||||
)
|
||||
|
||||
fun startDownloader(input: StartDownloaderInput): CompletableFuture<DataFetcherResult<StartDownloaderPayload?>> =
|
||||
fun startDownloader(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: StartDownloaderInput,
|
||||
): CompletableFuture<DataFetcherResult<StartDownloaderPayload?>> =
|
||||
future {
|
||||
asDataFetcherResult {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
DownloadManager.start()
|
||||
|
||||
StartDownloaderPayload(
|
||||
@@ -249,9 +278,13 @@ class DownloadMutation {
|
||||
val downloadStatus: DownloadStatus,
|
||||
)
|
||||
|
||||
fun stopDownloader(input: StopDownloaderInput): CompletableFuture<DataFetcherResult<StopDownloaderPayload?>> =
|
||||
fun stopDownloader(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: StopDownloaderInput,
|
||||
): CompletableFuture<DataFetcherResult<StopDownloaderPayload?>> =
|
||||
future {
|
||||
asDataFetcherResult {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
DownloadManager.stop()
|
||||
|
||||
StopDownloaderPayload(
|
||||
@@ -277,9 +310,13 @@ class DownloadMutation {
|
||||
val downloadStatus: DownloadStatus,
|
||||
)
|
||||
|
||||
fun clearDownloader(input: ClearDownloaderInput): CompletableFuture<DataFetcherResult<ClearDownloaderPayload?>> =
|
||||
fun clearDownloader(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: ClearDownloaderInput,
|
||||
): CompletableFuture<DataFetcherResult<ClearDownloaderPayload?>> =
|
||||
future {
|
||||
asDataFetcherResult {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
DownloadManager.clear()
|
||||
|
||||
ClearDownloaderPayload(
|
||||
@@ -307,7 +344,11 @@ class DownloadMutation {
|
||||
val downloadStatus: DownloadStatus,
|
||||
)
|
||||
|
||||
fun reorderChapterDownload(input: ReorderChapterDownloadInput): CompletableFuture<DataFetcherResult<ReorderChapterDownloadPayload?>> {
|
||||
fun reorderChapterDownload(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: ReorderChapterDownloadInput,
|
||||
): CompletableFuture<DataFetcherResult<ReorderChapterDownloadPayload?>> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, chapter, to) = input
|
||||
|
||||
return future {
|
||||
|
||||
@@ -2,15 +2,20 @@ 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.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 {
|
||||
@@ -73,7 +78,11 @@ class ExtensionMutation {
|
||||
}
|
||||
}
|
||||
|
||||
fun updateExtension(input: UpdateExtensionInput): CompletableFuture<DataFetcherResult<UpdateExtensionPayload?>> {
|
||||
fun updateExtension(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UpdateExtensionInput,
|
||||
): CompletableFuture<DataFetcherResult<UpdateExtensionPayload?>> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, id, patch) = input
|
||||
|
||||
return future {
|
||||
@@ -97,7 +106,11 @@ class ExtensionMutation {
|
||||
}
|
||||
}
|
||||
|
||||
fun updateExtensions(input: UpdateExtensionsInput): CompletableFuture<DataFetcherResult<UpdateExtensionsPayload?>> {
|
||||
fun updateExtensions(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UpdateExtensionsInput,
|
||||
): CompletableFuture<DataFetcherResult<UpdateExtensionsPayload?>> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, ids, patch) = input
|
||||
|
||||
return future {
|
||||
@@ -129,7 +142,11 @@ class ExtensionMutation {
|
||||
val extensions: List<ExtensionType>,
|
||||
)
|
||||
|
||||
fun fetchExtensions(input: FetchExtensionsInput): CompletableFuture<DataFetcherResult<FetchExtensionsPayload?>> {
|
||||
fun fetchExtensions(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: FetchExtensionsInput,
|
||||
): CompletableFuture<DataFetcherResult<FetchExtensionsPayload?>> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId) = input
|
||||
|
||||
return future {
|
||||
@@ -163,8 +180,10 @@ class ExtensionMutation {
|
||||
)
|
||||
|
||||
fun installExternalExtension(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: InstallExternalExtensionInput,
|
||||
): CompletableFuture<DataFetcherResult<InstallExternalExtensionPayload?>> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, extensionFile) = input
|
||||
|
||||
return future {
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
package suwayomi.tachidesk.graphql.mutations
|
||||
|
||||
import graphql.schema.DataFetchingEnvironment
|
||||
import suwayomi.tachidesk.graphql.server.getAttribute
|
||||
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()
|
||||
@@ -21,7 +26,11 @@ class ImageMutation {
|
||||
val cachedPages: Boolean?,
|
||||
)
|
||||
|
||||
fun clearCachedImages(input: ClearCachedImagesInput): ClearCachedImagesPayload {
|
||||
fun clearCachedImages(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: ClearCachedImagesInput,
|
||||
): ClearCachedImagesPayload {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, downloadedThumbnails, cachedThumbnails, cachedPages) = input
|
||||
|
||||
val downloadedThumbnailsResult =
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
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.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
|
||||
@@ -24,9 +29,13 @@ class InfoMutation {
|
||||
val updateStatus: WebUIUpdateStatus,
|
||||
)
|
||||
|
||||
fun updateWebUI(input: WebUIUpdateInput): CompletableFuture<DataFetcherResult<WebUIUpdatePayload?>> {
|
||||
fun updateWebUI(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
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)
|
||||
@@ -59,9 +68,10 @@ class InfoMutation {
|
||||
}
|
||||
}
|
||||
|
||||
fun resetWebUIUpdateStatus(): CompletableFuture<DataFetcherResult<WebUIUpdateStatus?>> =
|
||||
fun resetWebUIUpdateStatus(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<DataFetcherResult<WebUIUpdateStatus?>> =
|
||||
future {
|
||||
asDataFetcherResult {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
withTimeout(30.seconds) {
|
||||
val isUpdateFinished = WebInterfaceManager.status.value.state != DOWNLOADING
|
||||
if (!isUpdateFinished) {
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
package suwayomi.tachidesk.graphql.mutations
|
||||
|
||||
import graphql.schema.DataFetchingEnvironment
|
||||
import suwayomi.tachidesk.graphql.server.getAttribute
|
||||
import suwayomi.tachidesk.graphql.types.KoSyncConnectPayload
|
||||
import suwayomi.tachidesk.graphql.types.LogoutKoSyncAccountPayload
|
||||
import suwayomi.tachidesk.graphql.types.SettingsType
|
||||
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 KoreaderSyncMutation {
|
||||
@@ -14,8 +19,12 @@ class KoreaderSyncMutation {
|
||||
val password: String,
|
||||
)
|
||||
|
||||
fun connectKoSyncAccount(input: ConnectKoSyncAccountInput): CompletableFuture<KoSyncConnectPayload> =
|
||||
fun connectKoSyncAccount(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: ConnectKoSyncAccountInput,
|
||||
): CompletableFuture<KoSyncConnectPayload> =
|
||||
future {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val result = KoreaderSyncService.connect(input.username, input.password)
|
||||
|
||||
KoSyncConnectPayload(
|
||||
@@ -31,8 +40,12 @@ class KoreaderSyncMutation {
|
||||
val clientMutationId: String? = null,
|
||||
)
|
||||
|
||||
fun logoutKoSyncAccount(input: LogoutKoSyncAccountInput): CompletableFuture<LogoutKoSyncAccountPayload> =
|
||||
fun logoutKoSyncAccount(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: LogoutKoSyncAccountInput,
|
||||
): CompletableFuture<LogoutKoSyncAccountPayload> =
|
||||
future {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
KoreaderSyncService.logout()
|
||||
LogoutKoSyncAccountPayload(
|
||||
clientMutationId = input.clientMutationId,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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
|
||||
@@ -8,6 +9,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.types.MangaMetaType
|
||||
import suwayomi.tachidesk.graphql.types.MangaType
|
||||
import suwayomi.tachidesk.manga.impl.Library
|
||||
@@ -16,7 +18,10 @@ 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
|
||||
@@ -90,7 +95,11 @@ class MangaMutation {
|
||||
}
|
||||
}
|
||||
|
||||
fun updateManga(input: UpdateMangaInput): CompletableFuture<DataFetcherResult<UpdateMangaPayload?>> {
|
||||
fun updateManga(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UpdateMangaInput,
|
||||
): CompletableFuture<DataFetcherResult<UpdateMangaPayload?>> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, id, patch) = input
|
||||
|
||||
return future {
|
||||
@@ -110,7 +119,11 @@ class MangaMutation {
|
||||
}
|
||||
}
|
||||
|
||||
fun updateMangas(input: UpdateMangasInput): CompletableFuture<DataFetcherResult<UpdateMangasPayload?>> {
|
||||
fun updateMangas(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UpdateMangasInput,
|
||||
): CompletableFuture<DataFetcherResult<UpdateMangasPayload?>> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, ids, patch) = input
|
||||
|
||||
return future {
|
||||
@@ -140,7 +153,11 @@ class MangaMutation {
|
||||
val manga: MangaType,
|
||||
)
|
||||
|
||||
fun fetchManga(input: FetchMangaInput): CompletableFuture<DataFetcherResult<FetchMangaPayload?>> {
|
||||
fun fetchManga(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: FetchMangaInput,
|
||||
): CompletableFuture<DataFetcherResult<FetchMangaPayload?>> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, id) = input
|
||||
|
||||
return future {
|
||||
@@ -169,7 +186,11 @@ class MangaMutation {
|
||||
val meta: MangaMetaType,
|
||||
)
|
||||
|
||||
fun setMangaMeta(input: SetMangaMetaInput): DataFetcherResult<SetMangaMetaPayload?> {
|
||||
fun setMangaMeta(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: SetMangaMetaInput,
|
||||
): DataFetcherResult<SetMangaMetaPayload?> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, meta) = input
|
||||
|
||||
return asDataFetcherResult {
|
||||
@@ -191,7 +212,11 @@ class MangaMutation {
|
||||
val manga: MangaType,
|
||||
)
|
||||
|
||||
fun deleteMangaMeta(input: DeleteMangaMetaInput): DataFetcherResult<DeleteMangaMetaPayload?> {
|
||||
fun deleteMangaMeta(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: DeleteMangaMetaInput,
|
||||
): DataFetcherResult<DeleteMangaMetaPayload?> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, mangaId, key) = input
|
||||
|
||||
return asDataFetcherResult {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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
|
||||
@@ -8,7 +9,11 @@ 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.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(
|
||||
@@ -21,7 +26,11 @@ class MetaMutation {
|
||||
val meta: GlobalMetaType,
|
||||
)
|
||||
|
||||
fun setGlobalMeta(input: SetGlobalMetaInput): DataFetcherResult<SetGlobalMetaPayload?> {
|
||||
fun setGlobalMeta(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: SetGlobalMetaInput,
|
||||
): DataFetcherResult<SetGlobalMetaPayload?> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, meta) = input
|
||||
|
||||
return asDataFetcherResult {
|
||||
@@ -41,7 +50,11 @@ class MetaMutation {
|
||||
val meta: GlobalMetaType?,
|
||||
)
|
||||
|
||||
fun deleteGlobalMeta(input: DeleteGlobalMetaInput): DataFetcherResult<DeleteGlobalMetaPayload?> {
|
||||
fun deleteGlobalMeta(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: DeleteGlobalMetaInput,
|
||||
): DataFetcherResult<DeleteGlobalMetaPayload?> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, key) = input
|
||||
|
||||
return asDataFetcherResult {
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
package suwayomi.tachidesk.graphql.mutations
|
||||
|
||||
import com.expediagroup.graphql.generator.annotations.GraphQLIgnore
|
||||
import graphql.schema.DataFetchingEnvironment
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import suwayomi.tachidesk.graphql.server.getAttribute
|
||||
import suwayomi.tachidesk.graphql.types.PartialSettingsType
|
||||
import suwayomi.tachidesk.graphql.types.Settings
|
||||
import suwayomi.tachidesk.graphql.types.SettingsType
|
||||
import suwayomi.tachidesk.manga.impl.extension.ExtensionsList.repoMatchRegex
|
||||
import suwayomi.tachidesk.server.JavalinSetup.Attribute
|
||||
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
|
||||
import suwayomi.tachidesk.server.SERVER_CONFIG_MODULE_NAME
|
||||
import suwayomi.tachidesk.server.ServerConfig
|
||||
import suwayomi.tachidesk.server.serverConfig
|
||||
import suwayomi.tachidesk.server.user.requireUser
|
||||
import xyz.nulldev.ts.config.GlobalConfigManager
|
||||
import java.io.File
|
||||
|
||||
@@ -226,7 +231,11 @@ class SettingsMutation {
|
||||
updateSetting(settings.koreaderSyncPercentageTolerance, serverConfig.koreaderSyncPercentageTolerance)
|
||||
}
|
||||
|
||||
fun setSettings(input: SetSettingsInput): SetSettingsPayload {
|
||||
fun setSettings(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: SetSettingsInput,
|
||||
): SetSettingsPayload {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, settings) = input
|
||||
|
||||
validateSettings(settings)
|
||||
@@ -244,7 +253,11 @@ class SettingsMutation {
|
||||
val settings: SettingsType,
|
||||
)
|
||||
|
||||
fun resetSettings(input: ResetSettingsInput): ResetSettingsPayload {
|
||||
fun resetSettings(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: ResetSettingsInput,
|
||||
): ResetSettingsPayload {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId) = input
|
||||
|
||||
GlobalConfigManager.resetUserConfig()
|
||||
|
||||
@@ -6,12 +6,14 @@ 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.types.FilterChange
|
||||
import suwayomi.tachidesk.graphql.types.MangaType
|
||||
import suwayomi.tachidesk.graphql.types.Preference
|
||||
@@ -25,7 +27,10 @@ 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 {
|
||||
@@ -39,7 +44,11 @@ class SourceMutation {
|
||||
val meta: SourceMetaType,
|
||||
)
|
||||
|
||||
fun setSourceMeta(input: SetSourceMetaInput): DataFetcherResult<SetSourceMetaPayload?> {
|
||||
fun setSourceMeta(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: SetSourceMetaInput,
|
||||
): DataFetcherResult<SetSourceMetaPayload?> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, meta) = input
|
||||
|
||||
return asDataFetcherResult {
|
||||
@@ -61,7 +70,11 @@ class SourceMutation {
|
||||
val source: SourceType?,
|
||||
)
|
||||
|
||||
fun deleteSourceMeta(input: DeleteSourceMetaInput): DataFetcherResult<DeleteSourceMetaPayload?> {
|
||||
fun deleteSourceMeta(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: DeleteSourceMetaInput,
|
||||
): DataFetcherResult<DeleteSourceMetaPayload?> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, sourceId, key) = input
|
||||
|
||||
return asDataFetcherResult {
|
||||
@@ -116,7 +129,11 @@ class SourceMutation {
|
||||
val hasNextPage: Boolean,
|
||||
)
|
||||
|
||||
fun fetchSourceManga(input: FetchSourceMangaInput): CompletableFuture<DataFetcherResult<FetchSourceMangaPayload?>> {
|
||||
fun fetchSourceManga(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: FetchSourceMangaInput,
|
||||
): CompletableFuture<DataFetcherResult<FetchSourceMangaPayload?>> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, sourceId, type, page, query, filters) = input
|
||||
|
||||
return future {
|
||||
@@ -182,7 +199,11 @@ class SourceMutation {
|
||||
val source: SourceType,
|
||||
)
|
||||
|
||||
fun updateSourcePreference(input: UpdateSourcePreferenceInput): DataFetcherResult<UpdateSourcePreferencePayload?> {
|
||||
fun updateSourcePreference(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UpdateSourcePreferenceInput,
|
||||
): DataFetcherResult<UpdateSourcePreferencePayload?> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, sourceId, change) = input
|
||||
|
||||
return asDataFetcherResult {
|
||||
|
||||
@@ -3,16 +3,21 @@ 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.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 {
|
||||
@@ -28,7 +33,11 @@ class TrackMutation {
|
||||
val tracker: TrackerType,
|
||||
)
|
||||
|
||||
fun loginTrackerOAuth(input: LoginTrackerOAuthInput): CompletableFuture<LoginTrackerOAuthPayload> {
|
||||
fun loginTrackerOAuth(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: LoginTrackerOAuthInput,
|
||||
): CompletableFuture<LoginTrackerOAuthPayload> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val tracker =
|
||||
requireNotNull(TrackerManager.getTracker(input.trackerId)) {
|
||||
"Could not find tracker"
|
||||
@@ -57,7 +66,11 @@ class TrackMutation {
|
||||
val tracker: TrackerType,
|
||||
)
|
||||
|
||||
fun loginTrackerCredentials(input: LoginTrackerCredentialsInput): CompletableFuture<LoginTrackerCredentialsPayload> {
|
||||
fun loginTrackerCredentials(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: LoginTrackerCredentialsInput,
|
||||
): CompletableFuture<LoginTrackerCredentialsPayload> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val tracker =
|
||||
requireNotNull(TrackerManager.getTracker(input.trackerId)) {
|
||||
"Could not find tracker"
|
||||
@@ -84,7 +97,11 @@ class TrackMutation {
|
||||
val tracker: TrackerType,
|
||||
)
|
||||
|
||||
fun logoutTracker(input: LogoutTrackerInput): CompletableFuture<LogoutTrackerPayload> {
|
||||
fun logoutTracker(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: LogoutTrackerInput,
|
||||
): CompletableFuture<LogoutTrackerPayload> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val tracker =
|
||||
requireNotNull(TrackerManager.getTracker(input.trackerId)) {
|
||||
"Could not find tracker"
|
||||
@@ -117,7 +134,11 @@ class TrackMutation {
|
||||
val trackRecord: TrackRecordType,
|
||||
)
|
||||
|
||||
fun bindTrack(input: BindTrackInput): CompletableFuture<BindTrackPayload> {
|
||||
fun bindTrack(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: BindTrackInput,
|
||||
): CompletableFuture<BindTrackPayload> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, mangaId, trackerId, remoteId, private) = input
|
||||
|
||||
return future {
|
||||
@@ -152,7 +173,11 @@ class TrackMutation {
|
||||
val trackRecord: TrackRecordType,
|
||||
)
|
||||
|
||||
fun fetchTrack(input: FetchTrackInput): CompletableFuture<FetchTrackPayload> {
|
||||
fun fetchTrack(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: FetchTrackInput,
|
||||
): CompletableFuture<FetchTrackPayload> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, recordId) = input
|
||||
|
||||
return future {
|
||||
@@ -184,7 +209,11 @@ class TrackMutation {
|
||||
val trackRecord: TrackRecordType?,
|
||||
)
|
||||
|
||||
fun unbindTrack(input: UnbindTrackInput): CompletableFuture<UnbindTrackPayload> {
|
||||
fun unbindTrack(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UnbindTrackInput,
|
||||
): CompletableFuture<UnbindTrackPayload> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, recordId, deleteRemoteTrack) = input
|
||||
|
||||
return future {
|
||||
@@ -214,7 +243,11 @@ class TrackMutation {
|
||||
val trackRecords: List<TrackRecordType>,
|
||||
)
|
||||
|
||||
fun trackProgress(input: TrackProgressInput): CompletableFuture<DataFetcherResult<TrackProgressPayload?>> {
|
||||
fun trackProgress(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: TrackProgressInput,
|
||||
): CompletableFuture<DataFetcherResult<TrackProgressPayload?>> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (clientMutationId, mangaId) = input
|
||||
|
||||
return future {
|
||||
@@ -256,8 +289,12 @@ class TrackMutation {
|
||||
val trackRecord: TrackRecordType?,
|
||||
)
|
||||
|
||||
fun updateTrack(input: UpdateTrackInput): CompletableFuture<UpdateTrackPayload> =
|
||||
fun updateTrack(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UpdateTrackInput,
|
||||
): CompletableFuture<UpdateTrackPayload> =
|
||||
future {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
Track.update(
|
||||
Track.UpdateInput(
|
||||
input.recordId,
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
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.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
|
||||
@@ -26,7 +31,11 @@ class UpdateMutation {
|
||||
val updateStatus: LibraryUpdateStatus,
|
||||
)
|
||||
|
||||
fun updateLibrary(input: UpdateLibraryInput): CompletableFuture<DataFetcherResult<UpdateLibraryPayload?>> {
|
||||
fun updateLibrary(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UpdateLibraryInput,
|
||||
): CompletableFuture<DataFetcherResult<UpdateLibraryPayload?>> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
updater.addCategoriesToUpdateQueue(
|
||||
Category.getCategoryList().filter { input.categories?.contains(it.id) ?: true },
|
||||
clear = true,
|
||||
@@ -57,8 +66,12 @@ class UpdateMutation {
|
||||
val updateStatus: UpdateStatus,
|
||||
)
|
||||
|
||||
fun updateLibraryManga(input: UpdateLibraryMangaInput): CompletableFuture<DataFetcherResult<UpdateLibraryMangaPayload?>> {
|
||||
fun updateLibraryManga(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UpdateLibraryMangaInput,
|
||||
): CompletableFuture<DataFetcherResult<UpdateLibraryMangaPayload?>> {
|
||||
updateLibrary(
|
||||
dataFetchingEnvironment,
|
||||
UpdateLibraryInput(
|
||||
clientMutationId = input.clientMutationId,
|
||||
categories = null,
|
||||
@@ -88,8 +101,12 @@ class UpdateMutation {
|
||||
val updateStatus: UpdateStatus,
|
||||
)
|
||||
|
||||
fun updateCategoryManga(input: UpdateCategoryMangaInput): CompletableFuture<DataFetcherResult<UpdateCategoryMangaPayload?>> {
|
||||
fun updateCategoryManga(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UpdateCategoryMangaInput,
|
||||
): CompletableFuture<DataFetcherResult<UpdateCategoryMangaPayload?>> {
|
||||
updateLibrary(
|
||||
dataFetchingEnvironment,
|
||||
UpdateLibraryInput(
|
||||
clientMutationId = input.clientMutationId,
|
||||
categories = input.categories,
|
||||
@@ -117,7 +134,11 @@ class UpdateMutation {
|
||||
val clientMutationId: String?,
|
||||
)
|
||||
|
||||
fun updateStop(input: UpdateStopInput): UpdateStopPayload {
|
||||
fun updateStop(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: UpdateStopInput,
|
||||
): UpdateStopPayload {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
updater.reset()
|
||||
return UpdateStopPayload(input.clientMutationId)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package suwayomi.tachidesk.graphql.mutations
|
||||
|
||||
import graphql.schema.DataFetchingEnvironment
|
||||
import suwayomi.tachidesk.global.impl.util.Jwt
|
||||
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
|
||||
|
||||
class UserMutation {
|
||||
data class LoginInput(
|
||||
val clientMutationId: String? = null,
|
||||
val username: String,
|
||||
val password: String,
|
||||
)
|
||||
|
||||
data class LoginPayload(
|
||||
val clientMutationId: String?,
|
||||
val accessToken: String,
|
||||
val refreshToken: String,
|
||||
)
|
||||
|
||||
fun login(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: LoginInput,
|
||||
): LoginPayload {
|
||||
if (dataFetchingEnvironment.getAttribute(Attribute.TachideskUser) !is UserType.Visitor) {
|
||||
throw IllegalArgumentException("Cannot login while already logged-in")
|
||||
}
|
||||
val isValid =
|
||||
input.username == serverConfig.authUsername.value &&
|
||||
input.password == serverConfig.authPassword.value
|
||||
if (isValid) {
|
||||
val jwt = Jwt.generateJwt()
|
||||
return LoginPayload(
|
||||
clientMutationId = input.clientMutationId,
|
||||
accessToken = jwt.accessToken,
|
||||
refreshToken = jwt.refreshToken,
|
||||
)
|
||||
} else {
|
||||
throw Exception("Incorrect username or password.")
|
||||
}
|
||||
}
|
||||
|
||||
data class RefreshTokenInput(
|
||||
val clientMutationId: String? = null,
|
||||
val refreshToken: String,
|
||||
)
|
||||
|
||||
data class RefreshTokenPayload(
|
||||
val clientMutationId: String?,
|
||||
val accessToken: String,
|
||||
)
|
||||
|
||||
fun refreshToken(input: RefreshTokenInput): RefreshTokenPayload {
|
||||
val accessToken = Jwt.refreshJwt(input.refreshToken)
|
||||
|
||||
return RefreshTokenPayload(
|
||||
clientMutationId = input.clientMutationId,
|
||||
accessToken = accessToken,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
package suwayomi.tachidesk.graphql.queries
|
||||
|
||||
import graphql.schema.DataFetchingEnvironment
|
||||
import io.javalin.http.UploadedFile
|
||||
import suwayomi.tachidesk.graphql.server.getAttribute
|
||||
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(
|
||||
@@ -25,7 +30,11 @@ class BackupQuery {
|
||||
val missingTrackers: List<ValidateBackupTracker>,
|
||||
)
|
||||
|
||||
fun validateBackup(input: ValidateBackupInput): ValidateBackupResult {
|
||||
fun validateBackup(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: ValidateBackupInput,
|
||||
): ValidateBackupResult {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val result = ProtoBackupValidator.validate(input.backup.content())
|
||||
return ValidateBackupResult(
|
||||
result.missingSourceIds.map { ValidateBackupSource(it.first, it.second) },
|
||||
@@ -33,5 +42,11 @@ class BackupQuery {
|
||||
)
|
||||
}
|
||||
|
||||
fun restoreStatus(id: String): BackupRestoreStatus? = ProtoBackupImport.getRestoreState(id)?.toStatus()
|
||||
fun restoreStatus(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
id: String,
|
||||
): BackupRestoreStatus? {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
return ProtoBackupImport.getRestoreState(id)?.toStatus()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ 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
|
||||
@@ -39,13 +40,19 @@ 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 {
|
||||
fun category(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
id: Int,
|
||||
): CompletableFuture<CategoryType> = dataFetchingEnvironment.getValueFromDataLoader("CategoryDataLoader", id)
|
||||
): CompletableFuture<CategoryType> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
return dataFetchingEnvironment.getValueFromDataLoader("CategoryDataLoader", id)
|
||||
}
|
||||
|
||||
enum class CategoryOrderBy(
|
||||
override val column: Column<*>,
|
||||
@@ -121,6 +128,7 @@ class CategoryQuery {
|
||||
}
|
||||
|
||||
fun categories(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
condition: CategoryCondition? = null,
|
||||
filter: CategoryFilter? = null,
|
||||
@GraphQLDeprecated(
|
||||
@@ -140,6 +148,7 @@ class CategoryQuery {
|
||||
last: Int? = null,
|
||||
offset: Int? = null,
|
||||
): CategoryNodeList {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val queryResults =
|
||||
transaction {
|
||||
val res = CategoryTable.selectAll()
|
||||
|
||||
@@ -30,6 +30,7 @@ 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,6 +44,9 @@ 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
|
||||
|
||||
/**
|
||||
@@ -197,6 +201,7 @@ class ChapterQuery {
|
||||
}
|
||||
|
||||
fun chapters(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
condition: ChapterCondition? = null,
|
||||
filter: ChapterFilter? = null,
|
||||
@GraphQLDeprecated(
|
||||
@@ -216,6 +221,7 @@ class ChapterQuery {
|
||||
last: Int? = null,
|
||||
offset: Int? = null,
|
||||
): ChapterNodeList {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val queryResults =
|
||||
transaction {
|
||||
val res = ChapterTable.selectAll()
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
package suwayomi.tachidesk.graphql.queries
|
||||
|
||||
import graphql.schema.DataFetchingEnvironment
|
||||
import suwayomi.tachidesk.graphql.server.getAttribute
|
||||
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(): CompletableFuture<DownloadStatus> =
|
||||
fun downloadStatus(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<DownloadStatus> =
|
||||
future {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
DownloadStatus(DownloadManager.getStatus())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ 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
|
||||
@@ -40,13 +41,19 @@ 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 {
|
||||
fun extension(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
pkgName: String,
|
||||
): CompletableFuture<ExtensionType> = dataFetchingEnvironment.getValueFromDataLoader("ExtensionDataLoader", pkgName)
|
||||
): CompletableFuture<ExtensionType> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
return dataFetchingEnvironment.getValueFromDataLoader("ExtensionDataLoader", pkgName)
|
||||
}
|
||||
|
||||
enum class ExtensionOrderBy(
|
||||
override val column: Column<*>,
|
||||
@@ -153,6 +160,7 @@ class ExtensionQuery {
|
||||
}
|
||||
|
||||
fun extensions(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
condition: ExtensionCondition? = null,
|
||||
filter: ExtensionFilter? = null,
|
||||
@GraphQLDeprecated(
|
||||
@@ -172,6 +180,7 @@ class ExtensionQuery {
|
||||
last: Int? = null,
|
||||
offset: Int? = null,
|
||||
): ExtensionNodeList {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val queryResults =
|
||||
transaction {
|
||||
val res = ExtensionTable.selectAll()
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
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.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
|
||||
|
||||
@@ -42,8 +47,9 @@ class InfoQuery {
|
||||
val url: String,
|
||||
)
|
||||
|
||||
fun checkForServerUpdates(): CompletableFuture<List<CheckForServerUpdatesPayload>> =
|
||||
fun checkForServerUpdates(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<CheckForServerUpdatesPayload>> =
|
||||
future {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
AppUpdate.checkUpdate().map {
|
||||
CheckForServerUpdatesPayload(
|
||||
channel = it.channel,
|
||||
@@ -53,13 +59,15 @@ class InfoQuery {
|
||||
}
|
||||
}
|
||||
|
||||
fun aboutWebUI(): CompletableFuture<AboutWebUI> =
|
||||
fun aboutWebUI(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<AboutWebUI> =
|
||||
future {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
WebInterfaceManager.getAboutInfo()
|
||||
}
|
||||
|
||||
fun checkForWebUIUpdate(): CompletableFuture<WebUIUpdateCheck> =
|
||||
fun checkForWebUIUpdate(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<WebUIUpdateCheck> =
|
||||
future {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (version, updateAvailable) = WebInterfaceManager.isUpdateAvailable(WebUIFlavor.current, raiseError = true)
|
||||
WebUIUpdateCheck(
|
||||
channel = serverConfig.webUIChannel.value,
|
||||
@@ -68,5 +76,8 @@ class InfoQuery {
|
||||
)
|
||||
}
|
||||
|
||||
fun getWebUIUpdateStatus(): WebUIUpdateStatus = WebInterfaceManager.status.value
|
||||
fun getWebUIUpdateStatus(dataFetchingEnvironment: DataFetchingEnvironment): WebUIUpdateStatus {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
return WebInterfaceManager.status.value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
package suwayomi.tachidesk.graphql.queries
|
||||
|
||||
import graphql.schema.DataFetchingEnvironment
|
||||
import suwayomi.tachidesk.graphql.server.getAttribute
|
||||
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(): CompletableFuture<KoSyncStatusPayload> =
|
||||
fun koSyncStatus(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<KoSyncStatusPayload> =
|
||||
future {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
KoreaderSyncService.getStatus()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ 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
|
||||
@@ -42,13 +43,19 @@ 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 {
|
||||
fun manga(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
id: Int,
|
||||
): CompletableFuture<MangaType> = dataFetchingEnvironment.getValueFromDataLoader("MangaDataLoader", id)
|
||||
): CompletableFuture<MangaType> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
return dataFetchingEnvironment.getValueFromDataLoader("MangaDataLoader", id)
|
||||
}
|
||||
|
||||
enum class MangaOrderBy(
|
||||
override val column: Column<*>,
|
||||
@@ -216,6 +223,7 @@ class MangaQuery {
|
||||
}
|
||||
|
||||
fun mangas(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
condition: MangaCondition? = null,
|
||||
filter: MangaFilter? = null,
|
||||
@GraphQLDeprecated(
|
||||
@@ -235,6 +243,7 @@ class MangaQuery {
|
||||
last: Int? = null,
|
||||
offset: Int? = null,
|
||||
): MangaNodeList {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val queryResults =
|
||||
transaction {
|
||||
val res =
|
||||
|
||||
@@ -24,6 +24,7 @@ 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
|
||||
@@ -35,13 +36,19 @@ 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 {
|
||||
fun meta(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
key: String,
|
||||
): CompletableFuture<GlobalMetaType> = dataFetchingEnvironment.getValueFromDataLoader("GlobalMetaDataLoader", key)
|
||||
): CompletableFuture<GlobalMetaType> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
return dataFetchingEnvironment.getValueFromDataLoader("GlobalMetaDataLoader", key)
|
||||
}
|
||||
|
||||
enum class MetaOrderBy(
|
||||
override val column: Column<*>,
|
||||
@@ -105,6 +112,7 @@ class MetaQuery {
|
||||
}
|
||||
|
||||
fun metas(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
condition: MetaCondition? = null,
|
||||
filter: MetaFilter? = null,
|
||||
@GraphQLDeprecated(
|
||||
@@ -124,6 +132,7 @@ class MetaQuery {
|
||||
last: Int? = null,
|
||||
offset: Int? = null,
|
||||
): GlobalMetaNodeList {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val queryResults =
|
||||
transaction {
|
||||
val res = GlobalMetaTable.selectAll()
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
package suwayomi.tachidesk.graphql.queries
|
||||
|
||||
import graphql.schema.DataFetchingEnvironment
|
||||
import suwayomi.tachidesk.graphql.server.getAttribute
|
||||
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(): SettingsType = SettingsType()
|
||||
fun settings(dataFetchingEnvironment: DataFetchingEnvironment): SettingsType {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
return SettingsType()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ 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
|
||||
@@ -39,13 +40,19 @@ 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 {
|
||||
fun source(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
id: Long,
|
||||
): CompletableFuture<SourceType> = dataFetchingEnvironment.getValueFromDataLoader("SourceDataLoader", id)
|
||||
): CompletableFuture<SourceType> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
return dataFetchingEnvironment.getValueFromDataLoader("SourceDataLoader", id)
|
||||
}
|
||||
|
||||
enum class SourceOrderBy(
|
||||
override val column: Column<*>,
|
||||
@@ -121,6 +128,7 @@ class SourceQuery {
|
||||
}
|
||||
|
||||
fun sources(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
condition: SourceCondition? = null,
|
||||
filter: SourceFilter? = null,
|
||||
@GraphQLDeprecated(
|
||||
@@ -140,6 +148,7 @@ class SourceQuery {
|
||||
last: Int? = null,
|
||||
offset: Int? = null,
|
||||
): SourceNodeList {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val (queryResults, resultsAsType) =
|
||||
transaction {
|
||||
val res = SourceTable.selectAll()
|
||||
|
||||
@@ -22,6 +22,7 @@ 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
|
||||
@@ -39,14 +40,20 @@ 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 {
|
||||
fun tracker(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
id: Int,
|
||||
): CompletableFuture<TrackerType> = dataFetchingEnvironment.getValueFromDataLoader<Int, TrackerType>("TrackerDataLoader", id)
|
||||
): CompletableFuture<TrackerType> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
return dataFetchingEnvironment.getValueFromDataLoader<Int, TrackerType>("TrackerDataLoader", id)
|
||||
}
|
||||
|
||||
enum class TrackerOrderBy {
|
||||
ID,
|
||||
@@ -115,6 +122,7 @@ class TrackQuery {
|
||||
)
|
||||
|
||||
fun trackers(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
condition: TrackerCondition? = null,
|
||||
@GraphQLDeprecated(
|
||||
"Replaced with order",
|
||||
@@ -133,6 +141,7 @@ 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) }
|
||||
@@ -240,8 +249,10 @@ class TrackQuery {
|
||||
fun trackRecord(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
id: Int,
|
||||
): CompletableFuture<TrackRecordType> =
|
||||
dataFetchingEnvironment.getValueFromDataLoader<Int, TrackRecordType>("TrackRecordDataLoader", id)
|
||||
): CompletableFuture<TrackRecordType> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
return dataFetchingEnvironment.getValueFromDataLoader<Int, TrackRecordType>("TrackRecordDataLoader", id)
|
||||
}
|
||||
|
||||
enum class TrackRecordOrderBy(
|
||||
override val column: Column<*>,
|
||||
@@ -389,6 +400,7 @@ class TrackQuery {
|
||||
}
|
||||
|
||||
fun trackRecords(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
condition: TrackRecordCondition? = null,
|
||||
filter: TrackRecordFilter? = null,
|
||||
@GraphQLDeprecated(
|
||||
@@ -408,6 +420,7 @@ class TrackQuery {
|
||||
last: Int? = null,
|
||||
offset: Int? = null,
|
||||
): TrackRecordNodeList {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val queryResults =
|
||||
transaction {
|
||||
val res = TrackRecordTable.selectAll()
|
||||
@@ -490,8 +503,12 @@ class TrackQuery {
|
||||
val trackSearches: List<TrackSearchType>,
|
||||
)
|
||||
|
||||
fun searchTracker(input: SearchTrackerInput): CompletableFuture<SearchTrackerPayload> =
|
||||
fun searchTracker(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: SearchTrackerInput,
|
||||
): CompletableFuture<SearchTrackerPayload> =
|
||||
future {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val tracker =
|
||||
requireNotNull(TrackerManager.getTracker(input.trackerId)) {
|
||||
"Tracker not found"
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
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.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
|
||||
|
||||
@@ -13,13 +18,24 @@ class UpdateQuery {
|
||||
private val updater: IUpdater by injectLazy()
|
||||
|
||||
@GraphQLDeprecated("Replaced with libraryUpdateStatus", ReplaceWith("libraryUpdateStatus"))
|
||||
fun updateStatus(): CompletableFuture<UpdateStatus> = future { UpdateStatus(updater.status.first()) }
|
||||
fun updateStatus(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<UpdateStatus> =
|
||||
future {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
UpdateStatus(updater.status.first())
|
||||
}
|
||||
|
||||
fun libraryUpdateStatus(): CompletableFuture<LibraryUpdateStatus> = future { LibraryUpdateStatus(updater.getStatus()) }
|
||||
fun libraryUpdateStatus(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<LibraryUpdateStatus> =
|
||||
future {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
LibraryUpdateStatus(updater.getStatus())
|
||||
}
|
||||
|
||||
data class LastUpdateTimestampPayload(
|
||||
val timestamp: Long,
|
||||
)
|
||||
|
||||
fun lastUpdateTimestamp(): LastUpdateTimestampPayload = LastUpdateTimestampPayload(updater.getLastUpdateTimestamp())
|
||||
fun lastUpdateTimestamp(dataFetchingEnvironment: DataFetchingEnvironment): LastUpdateTimestampPayload {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
return LastUpdateTimestampPayload(updater.getLastUpdateTimestamp())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,34 +9,49 @@ package suwayomi.tachidesk.graphql.server
|
||||
|
||||
import com.expediagroup.graphql.server.execution.GraphQLContextFactory
|
||||
import graphql.GraphQLContext
|
||||
import graphql.schema.DataFetchingEnvironment
|
||||
import io.javalin.http.Context
|
||||
import io.javalin.websocket.WsContext
|
||||
import org.dataloader.BatchLoaderEnvironment
|
||||
import suwayomi.tachidesk.server.JavalinSetup.Attribute
|
||||
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
|
||||
import suwayomi.tachidesk.server.user.UserType
|
||||
|
||||
/**
|
||||
* Custom logic for how Suwayomi-Server should create its context given the [Context]
|
||||
*/
|
||||
class TachideskGraphQLContextFactory : GraphQLContextFactory<Context> {
|
||||
override suspend fun generateContext(request: Context): GraphQLContext = emptyMap<Any, Any>().toGraphQLContext()
|
||||
// mutableMapOf<Any, Any>(
|
||||
// "user" to User(
|
||||
// email = "fake@site.com",
|
||||
// firstName = "Someone",
|
||||
// lastName = "You Don't know",
|
||||
// universityId = 4
|
||||
// )
|
||||
// ).also { map ->
|
||||
// request.headers["my-custom-header"]?.let { customHeader ->
|
||||
// map["customHeader"] = customHeader
|
||||
// }
|
||||
// }.toGraphQLContext()
|
||||
override suspend fun generateContext(request: Context): GraphQLContext =
|
||||
mapOf(
|
||||
Context::class to request,
|
||||
request.getPair(Attribute.TachideskUser),
|
||||
).toGraphQLContext()
|
||||
|
||||
fun generateContextMap(
|
||||
@Suppress("UNUSED_PARAMETER") request: WsContext,
|
||||
): Map<*, Any> = emptyMap<Any, Any>()
|
||||
user: UserType,
|
||||
request: WsContext,
|
||||
): Map<*, Any> =
|
||||
mapOf(
|
||||
Context::class to request,
|
||||
Attribute.TachideskUser to user,
|
||||
)
|
||||
|
||||
private fun <T : Any> Context.getPair(attribute: Attribute<T>) = attribute to getAttribute(attribute)
|
||||
|
||||
private fun <T : Any> WsContext.getPair(attribute: Attribute<T>) = attribute to getAttribute(attribute)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a [GraphQLContext] from [this] map
|
||||
* @return a new [GraphQLContext]
|
||||
*/
|
||||
fun Map<*, Any?>.toGraphQLContext(): graphql.GraphQLContext = graphql.GraphQLContext.of(this)
|
||||
fun Map<*, Any?>.toGraphQLContext(): GraphQLContext = GraphQLContext.of(this)
|
||||
|
||||
fun <T : Any> GraphQLContext.getAttribute(attribute: Attribute<T>): T = get(attribute)
|
||||
|
||||
fun <T : Any> DataFetchingEnvironment.getAttribute(attribute: Attribute<T>): T = graphQlContext.get(attribute)
|
||||
|
||||
val BatchLoaderEnvironment.graphQlContext: GraphQLContext
|
||||
get() = keyContextsList.filterIsInstance<GraphQLContext>().first()
|
||||
|
||||
fun <T : Any> BatchLoaderEnvironment.getAttribute(attribute: Attribute<T>): T = graphQlContext.getAttribute(attribute)
|
||||
|
||||
@@ -27,6 +27,7 @@ import suwayomi.tachidesk.graphql.mutations.SettingsMutation
|
||||
import suwayomi.tachidesk.graphql.mutations.SourceMutation
|
||||
import suwayomi.tachidesk.graphql.mutations.TrackMutation
|
||||
import suwayomi.tachidesk.graphql.mutations.UpdateMutation
|
||||
import suwayomi.tachidesk.graphql.mutations.UserMutation
|
||||
import suwayomi.tachidesk.graphql.queries.BackupQuery
|
||||
import suwayomi.tachidesk.graphql.queries.CategoryQuery
|
||||
import suwayomi.tachidesk.graphql.queries.ChapterQuery
|
||||
@@ -100,6 +101,7 @@ val schema =
|
||||
TopLevelObject(SourceMutation()),
|
||||
TopLevelObject(TrackMutation()),
|
||||
TopLevelObject(UpdateMutation()),
|
||||
TopLevelObject(UserMutation()),
|
||||
),
|
||||
subscriptions =
|
||||
listOf(
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.convertValue
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import io.javalin.http.Header
|
||||
import io.javalin.websocket.WsContext
|
||||
import io.javalin.websocket.WsMessageContext
|
||||
import kotlinx.coroutines.currentCoroutineContext
|
||||
@@ -36,6 +37,8 @@ import suwayomi.tachidesk.graphql.server.subscriptions.SubscriptionOperationMess
|
||||
import suwayomi.tachidesk.graphql.server.subscriptions.SubscriptionOperationMessage.ServerMessages.GQL_ERROR
|
||||
import suwayomi.tachidesk.graphql.server.subscriptions.SubscriptionOperationMessage.ServerMessages.GQL_NEXT
|
||||
import suwayomi.tachidesk.graphql.server.toGraphQLContext
|
||||
import suwayomi.tachidesk.server.user.UserType
|
||||
import suwayomi.tachidesk.server.user.getUserFromToken
|
||||
|
||||
/**
|
||||
* Implementation of the `graphql-transport-ws` protocol defined by Denis Badurina
|
||||
@@ -77,7 +80,7 @@ class ApolloSubscriptionProtocolHandler(
|
||||
|
||||
return try {
|
||||
when (operationMessage.type) {
|
||||
GQL_CONNECTION_INIT.type -> onInit(context)
|
||||
GQL_CONNECTION_INIT.type -> onInit(operationMessage, context)
|
||||
GQL_SUBSCRIBE.type -> startSubscription(operationMessage, context)
|
||||
GQL_COMPLETE.type -> onComplete(operationMessage)
|
||||
GQL_PING.type -> onPing()
|
||||
@@ -144,17 +147,27 @@ class ApolloSubscriptionProtocolHandler(
|
||||
}
|
||||
}
|
||||
|
||||
private fun onInit(context: WsContext): Flow<SubscriptionOperationMessage> {
|
||||
saveContext(context)
|
||||
private fun onInit(
|
||||
operationMessage: SubscriptionOperationMessage,
|
||||
context: WsContext,
|
||||
): Flow<SubscriptionOperationMessage> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val payload = operationMessage.payload as? Map<String, Any?>
|
||||
val token = payload?.let { it[Header.AUTHORIZATION] as? String }
|
||||
|
||||
saveContext(getUserFromToken(token), context)
|
||||
return flowOf(acknowledgeMessage)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the context and save it for all future messages.
|
||||
*/
|
||||
private fun saveContext(context: WsContext) {
|
||||
private fun saveContext(
|
||||
user: UserType,
|
||||
context: WsContext,
|
||||
) {
|
||||
runBlocking {
|
||||
val graphQLContext = contextFactory.generateContextMap(context).toGraphQLContext()
|
||||
val graphQLContext = contextFactory.generateContextMap(user, context).toGraphQLContext()
|
||||
sessionState.saveContext(context, graphQLContext)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,18 +9,25 @@ 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.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(): Flow<DownloadStatus> =
|
||||
DownloadManager.status.map { downloadStatus ->
|
||||
fun downloadChanged(dataFetchingEnvironment: DataFetchingEnvironment): Flow<DownloadStatus> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
return DownloadManager.status.map { downloadStatus ->
|
||||
DownloadStatus(downloadStatus)
|
||||
}
|
||||
}
|
||||
|
||||
data class DownloadChangedInput(
|
||||
@GraphQLDescription(
|
||||
@@ -33,7 +40,11 @@ class DownloadSubscription {
|
||||
val maxUpdates: Int?,
|
||||
)
|
||||
|
||||
fun downloadStatusChanged(input: DownloadChangedInput): Flow<DownloadUpdates> {
|
||||
fun downloadStatusChanged(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: DownloadChangedInput,
|
||||
): Flow<DownloadUpdates> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val omitUpdates = input.maxUpdates != null
|
||||
val maxUpdates = input.maxUpdates ?: 50
|
||||
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
package suwayomi.tachidesk.graphql.subscriptions
|
||||
|
||||
import graphql.schema.DataFetchingEnvironment
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import suwayomi.tachidesk.graphql.server.getAttribute
|
||||
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(): Flow<WebUIUpdateStatus> = WebInterfaceManager.status
|
||||
fun webUIUpdateStatusChange(dataFetchingEnvironment: DataFetchingEnvironment): Flow<WebUIUpdateStatus> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
return WebInterfaceManager.status
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,22 +9,29 @@ 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.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(): Flow<UpdateStatus> =
|
||||
updater.status.map { updateStatus ->
|
||||
fun updateStatusChanged(dataFetchingEnvironment: DataFetchingEnvironment): Flow<UpdateStatus> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
return updater.status.map { updateStatus ->
|
||||
UpdateStatus(updateStatus)
|
||||
}
|
||||
}
|
||||
|
||||
data class LibraryUpdateStatusChangedInput(
|
||||
@GraphQLDescription(
|
||||
@@ -37,7 +44,11 @@ class UpdateSubscription {
|
||||
val maxUpdates: Int?,
|
||||
)
|
||||
|
||||
fun libraryUpdateStatusChanged(input: LibraryUpdateStatusChangedInput): Flow<UpdaterUpdates> {
|
||||
fun libraryUpdateStatusChanged(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: LibraryUpdateStatusChangedInput,
|
||||
): Flow<UpdaterUpdates> {
|
||||
dataFetchingEnvironment.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val omitUpdates = input.maxUpdates != null
|
||||
val maxUpdates = input.maxUpdates ?: 50
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ enum class AuthMode {
|
||||
NONE,
|
||||
BASIC_AUTH,
|
||||
SIMPLE_LOGIN,
|
||||
UI_LOGIN,
|
||||
// TODO: ACCOUNT for #623
|
||||
;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user