From 323d58717ec61a065e0ac928e6d99b7c5473ef14 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Mon, 29 Jun 2026 20:59:53 +0200 Subject: [PATCH] Add mutation to bind existing track record (#2045) Makes it possible to copy a bound track record to another manga. This is necessary during a migration to prevent spamming the actual tracker and causing 429 errors closes #2033 --- .../graphql/mutations/TrackMutation.kt | 30 ++++++++++++ .../tachidesk/manga/impl/track/Track.kt | 48 ++++++++++++++++++- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/TrackMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/TrackMutation.kt index b1bf2e7ba..f15a154db 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/TrackMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/TrackMutation.kt @@ -148,6 +148,36 @@ class TrackMutation { } } + data class BindTrackRecordInput( + val clientMutationId: String? = null, + val mangaId: Int, + val trackRecordId: Int, + ) + + data class BindTrackRecordPayload( + val clientMutationId: String?, + val trackRecord: TrackRecordType, + ) + + @RequireAuth + fun bindTrackRecord(input: BindTrackRecordInput): CompletableFuture { + val (clientMutationId, mangaId, trackRecordId) = input + + return future { + val boundTrackRecordId = Track.bindTrackRecord(mangaId, trackRecordId) + + val trackRecord = + transaction { + TrackRecordTable.selectAll().where { TrackRecordTable.id eq boundTrackRecordId }.first() + } + + BindTrackRecordPayload( + clientMutationId, + TrackRecordType(trackRecord), + ) + } + } + data class FetchTrackInput( val clientMutationId: String? = null, val recordId: Int, diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/track/Track.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/track/Track.kt index a08e86056..cc2e2fe85 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/track/Track.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/track/Track.kt @@ -222,6 +222,48 @@ object Track { } } + fun bindTrackRecord( + mangaId: Int, + trackRecordId: Int, + ): Int { + val (trackRecord, existingTrackRecord) = + transaction { + val trackRecord = + TrackRecordTable + .selectAll() + .where { + (TrackRecordTable.id eq trackRecordId) + }.first() + .toTrackRecordDataClass() + + val existingTrackRecord = + TrackRecordTable + .selectAll() + .where { + (TrackRecordTable.mangaId eq mangaId) and (TrackRecordTable.trackerId eq trackRecord.trackerId) + }.firstOrNull() + ?.toTrackRecordDataClass() + + trackRecord to existingTrackRecord + } + + val isAlreadyBoundToManga = trackRecord.mangaId == mangaId + if (isAlreadyBoundToManga) { + return trackRecordId + } + + val hasRecordForTracker = existingTrackRecord != null + if (hasRecordForTracker) { + val updatedTrack = trackRecord.copy(id = existingTrackRecord.id, mangaId = mangaId).toTrack() + + return updateTrackRecord(updatedTrack) + } + + val newTrack = trackRecord.copy(mangaId = mangaId).toTrack() + + return insertTrackRecord(newTrack) + } + suspend fun refresh(recordId: Int) { val recordDb = transaction { @@ -423,9 +465,9 @@ object Track { } } - fun updateTrackRecord(track: Track) = updateTrackRecords(listOf(track)) + fun updateTrackRecord(track: Track): Int = updateTrackRecords(listOf(track)).first() - fun updateTrackRecords(tracks: List) = + fun updateTrackRecords(tracks: List): List = transaction { if (tracks.isNotEmpty()) { BatchUpdateStatement(TrackRecordTable) @@ -447,6 +489,8 @@ object Track { }.toExecutable() .execute(this@transaction) } + + tracks.map { it.id!! } } fun insertTrackRecord(track: Track): Int = insertTrackRecords(listOf(track)).first()