mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-07 21:04:34 -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user