mirror of
https://github.com/Suwayomi/Tachidesk.git
synced 2025-12-10 06:42:07 +01:00
Feature/tracking gql add option to delete remote binding on tracker (#919)
* Extract unbinding track into function * Introduce new unbind mutation * Add option to delete track binding on track service --------- Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
package suwayomi.tachidesk.graphql.mutations
|
package suwayomi.tachidesk.graphql.mutations
|
||||||
|
|
||||||
|
import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated
|
||||||
|
import com.expediagroup.graphql.generator.annotations.GraphQLDescription
|
||||||
import org.jetbrains.exposed.sql.and
|
import org.jetbrains.exposed.sql.and
|
||||||
import org.jetbrains.exposed.sql.select
|
import org.jetbrains.exposed.sql.select
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
@@ -133,6 +135,36 @@ class TrackMutation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class UnbindTrackInput(
|
||||||
|
val clientMutationId: String? = null,
|
||||||
|
val recordId: Int,
|
||||||
|
@GraphQLDescription("This will only work if the tracker of the track record supports deleting tracks")
|
||||||
|
val deleteRemoteTrack: Boolean? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class UnbindTrackPayload(
|
||||||
|
val clientMutationId: String?,
|
||||||
|
val trackRecord: TrackRecordType?,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun unbindTrack(input: UnbindTrackInput): CompletableFuture<UnbindTrackPayload> {
|
||||||
|
val (clientMutationId, recordId, deleteRemoteTrack) = input
|
||||||
|
|
||||||
|
return future {
|
||||||
|
Track.unbind(recordId, deleteRemoteTrack)
|
||||||
|
val trackRecord =
|
||||||
|
transaction {
|
||||||
|
TrackRecordTable.select {
|
||||||
|
TrackRecordTable.id eq recordId
|
||||||
|
}.firstOrNull()
|
||||||
|
}
|
||||||
|
UnbindTrackPayload(
|
||||||
|
clientMutationId,
|
||||||
|
trackRecord?.let { TrackRecordType(it) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data class TrackProgressInput(
|
data class TrackProgressInput(
|
||||||
val clientMutationId: String? = null,
|
val clientMutationId: String? = null,
|
||||||
val mangaId: Int,
|
val mangaId: Int,
|
||||||
@@ -168,6 +200,7 @@ class TrackMutation {
|
|||||||
val scoreString: String? = null,
|
val scoreString: String? = null,
|
||||||
val startDate: Long? = null,
|
val startDate: Long? = null,
|
||||||
val finishDate: Long? = null,
|
val finishDate: Long? = null,
|
||||||
|
@GraphQLDeprecated("Replaced with \"unbindTrack\" mutation", replaceWith = ReplaceWith("unbindTrack"))
|
||||||
val unbind: Boolean? = null,
|
val unbind: Boolean? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ class TrackerType(
|
|||||||
val icon: String,
|
val icon: String,
|
||||||
val isLoggedIn: Boolean,
|
val isLoggedIn: Boolean,
|
||||||
val authUrl: String?,
|
val authUrl: String?,
|
||||||
|
val supportsTrackDeletion: Boolean?,
|
||||||
) : Node {
|
) : Node {
|
||||||
constructor(tracker: Tracker) : this(
|
constructor(tracker: Tracker) : this(
|
||||||
tracker.isLoggedIn,
|
tracker.isLoggedIn,
|
||||||
@@ -36,6 +37,7 @@ class TrackerType(
|
|||||||
} else {
|
} else {
|
||||||
tracker.authUrl()
|
tracker.authUrl()
|
||||||
},
|
},
|
||||||
|
tracker.supportsTrackDeletion,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun statuses(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<TrackStatusType>> {
|
fun statuses(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<TrackStatusType>> {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import org.jetbrains.exposed.sql.insertAndGetId
|
|||||||
import org.jetbrains.exposed.sql.select
|
import org.jetbrains.exposed.sql.select
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import org.jetbrains.exposed.sql.update
|
import org.jetbrains.exposed.sql.update
|
||||||
|
import suwayomi.tachidesk.manga.impl.track.tracker.DeletableTrackService
|
||||||
import suwayomi.tachidesk.manga.impl.track.tracker.TrackerManager
|
import suwayomi.tachidesk.manga.impl.track.tracker.TrackerManager
|
||||||
import suwayomi.tachidesk.manga.impl.track.tracker.model.Track
|
import suwayomi.tachidesk.manga.impl.track.tracker.model.Track
|
||||||
import suwayomi.tachidesk.manga.impl.track.tracker.model.toTrack
|
import suwayomi.tachidesk.manga.impl.track.tracker.model.toTrack
|
||||||
@@ -186,11 +187,29 @@ object Track {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun unbind(
|
||||||
|
recordId: Int,
|
||||||
|
deleteRemoteTrack: Boolean? = false,
|
||||||
|
) {
|
||||||
|
val recordDb =
|
||||||
|
transaction {
|
||||||
|
TrackRecordTable.select { TrackRecordTable.id eq recordId }.first()
|
||||||
|
}
|
||||||
|
|
||||||
|
val tracker = TrackerManager.getTracker(recordDb[TrackRecordTable.trackerId])!!
|
||||||
|
|
||||||
|
if (deleteRemoteTrack == true && tracker is DeletableTrackService) {
|
||||||
|
tracker.delete(recordDb.toTrack())
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction {
|
||||||
|
TrackRecordTable.deleteWhere { TrackRecordTable.id eq recordId }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun update(input: UpdateInput) {
|
suspend fun update(input: UpdateInput) {
|
||||||
if (input.unbind == true) {
|
if (input.unbind == true) {
|
||||||
transaction {
|
unbind(input.recordId)
|
||||||
TrackRecordTable.deleteWhere { TrackRecordTable.id eq input.recordId }
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val recordDb =
|
val recordDb =
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ import suwayomi.tachidesk.manga.impl.track.tracker.model.Track
|
|||||||
* For track services api that support deleting a manga entry for a user's list
|
* For track services api that support deleting a manga entry for a user's list
|
||||||
*/
|
*/
|
||||||
interface DeletableTrackService {
|
interface DeletableTrackService {
|
||||||
suspend fun delete(track: Track): Track
|
suspend fun delete(track: Track)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ abstract class Tracker(val id: Int, val name: String) {
|
|||||||
// Application and remote support for reading dates
|
// Application and remote support for reading dates
|
||||||
open val supportsReadingDates: Boolean = false
|
open val supportsReadingDates: Boolean = false
|
||||||
|
|
||||||
|
abstract val supportsTrackDeletion: Boolean
|
||||||
|
|
||||||
override fun toString() = "$name ($id) (isLoggedIn= $isLoggedIn, isAuthExpired= ${getIfAuthExpired()})"
|
override fun toString() = "$name ($id) (isLoggedIn= $isLoggedIn, isAuthExpired= ${getIfAuthExpired()})"
|
||||||
|
|
||||||
abstract fun getLogo(): String
|
abstract fun getLogo(): String
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package suwayomi.tachidesk.manga.impl.track.tracker.anilist
|
package suwayomi.tachidesk.manga.impl.track.tracker.anilist
|
||||||
|
|
||||||
import android.annotation.StringRes
|
import android.annotation.StringRes
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
@@ -29,6 +28,8 @@ class Anilist(id: Int) : Tracker(id, "AniList"), DeletableTrackService {
|
|||||||
const val POINT_3 = "POINT_3"
|
const val POINT_3 = "POINT_3"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val supportsTrackDeletion: Boolean = true
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
private val interceptor by lazy { AnilistInterceptor(this) }
|
private val interceptor by lazy { AnilistInterceptor(this) }
|
||||||
@@ -157,13 +158,13 @@ class Anilist(id: Int) : Tracker(id, "AniList"), DeletableTrackService {
|
|||||||
return api.updateLibManga(track)
|
return api.updateLibManga(track)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun delete(track: Track): Track {
|
override suspend fun delete(track: Track) {
|
||||||
if (track.library_id == null || track.library_id!! == 0L) {
|
if (track.library_id == null || track.library_id!! == 0L) {
|
||||||
val libManga = api.findLibManga(track, getUsername().toInt()) ?: return track
|
val libManga = api.findLibManga(track, getUsername().toInt()) ?: return
|
||||||
track.library_id = libManga.library_id
|
track.library_id = libManga.library_id
|
||||||
}
|
}
|
||||||
|
|
||||||
return api.deleteLibManga(track)
|
api.deleteLibManga(track)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun bind(
|
override suspend fun bind(
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun deleteLibManga(track: Track): Track {
|
suspend fun deleteLibManga(track: Track) {
|
||||||
return withIOContext {
|
return withIOContext {
|
||||||
val query =
|
val query =
|
||||||
"""
|
"""
|
||||||
@@ -135,7 +135,6 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
}
|
}
|
||||||
authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
|
authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
|
||||||
.awaitSuccess()
|
.awaitSuccess()
|
||||||
track
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates
|
package suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates
|
||||||
|
|
||||||
|
import suwayomi.tachidesk.manga.impl.track.tracker.DeletableTrackService
|
||||||
import suwayomi.tachidesk.manga.impl.track.tracker.Tracker
|
import suwayomi.tachidesk.manga.impl.track.tracker.Tracker
|
||||||
import suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates.dto.ListItem
|
import suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates.dto.ListItem
|
||||||
import suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates.dto.Rating
|
import suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates.dto.Rating
|
||||||
@@ -8,8 +9,7 @@ import suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates.dto.toTrackSearc
|
|||||||
import suwayomi.tachidesk.manga.impl.track.tracker.model.Track
|
import suwayomi.tachidesk.manga.impl.track.tracker.model.Track
|
||||||
import suwayomi.tachidesk.manga.impl.track.tracker.model.TrackSearch
|
import suwayomi.tachidesk.manga.impl.track.tracker.model.TrackSearch
|
||||||
|
|
||||||
class MangaUpdates(id: Int) : Tracker(id, "MangaUpdates") {
|
class MangaUpdates(id: Int) : Tracker(id, "MangaUpdates"), DeletableTrackService {
|
||||||
// , DeletableTracker
|
|
||||||
companion object {
|
companion object {
|
||||||
const val READING_LIST = 0
|
const val READING_LIST = 0
|
||||||
const val WISH_LIST = 1
|
const val WISH_LIST = 1
|
||||||
@@ -31,6 +31,8 @@ class MangaUpdates(id: Int) : Tracker(id, "MangaUpdates") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val supportsTrackDeletion: Boolean = true
|
||||||
|
|
||||||
private val interceptor by lazy { MangaUpdatesInterceptor(this) }
|
private val interceptor by lazy { MangaUpdatesInterceptor(this) }
|
||||||
|
|
||||||
private val api by lazy { MangaUpdatesApi(interceptor, client) }
|
private val api by lazy { MangaUpdatesApi(interceptor, client) }
|
||||||
@@ -74,9 +76,9 @@ class MangaUpdates(id: Int) : Tracker(id, "MangaUpdates") {
|
|||||||
return track
|
return track
|
||||||
}
|
}
|
||||||
|
|
||||||
// override suspend fun delete(track: Track) {
|
override suspend fun delete(track: Track) {
|
||||||
// api.deleteSeriesFromList(track)
|
api.deleteSeriesFromList(track)
|
||||||
// }
|
}
|
||||||
|
|
||||||
override suspend fun bind(
|
override suspend fun bind(
|
||||||
track: Track,
|
track: Track,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package suwayomi.tachidesk.manga.impl.track.tracker.myanimelist
|
package suwayomi.tachidesk.manga.impl.track.tracker.myanimelist
|
||||||
|
|
||||||
import android.annotation.StringRes
|
import android.annotation.StringRes
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
@@ -26,6 +25,8 @@ class MyAnimeList(id: Int) : Tracker(id, "MyAnimeList"), DeletableTrackService {
|
|||||||
private const val SEARCH_LIST_PREFIX = "my:"
|
private const val SEARCH_LIST_PREFIX = "my:"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val supportsTrackDeletion: Boolean = true
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
private val interceptor by lazy { MyAnimeListInterceptor(this) }
|
private val interceptor by lazy { MyAnimeListInterceptor(this) }
|
||||||
@@ -94,8 +95,8 @@ class MyAnimeList(id: Int) : Tracker(id, "MyAnimeList"), DeletableTrackService {
|
|||||||
return api.updateItem(track)
|
return api.updateItem(track)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun delete(track: Track): Track {
|
override suspend fun delete(track: Track) {
|
||||||
return api.deleteItem(track)
|
api.deleteItem(track)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun bind(
|
override suspend fun bind(
|
||||||
|
|||||||
@@ -164,18 +164,15 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun deleteItem(track: Track): Track {
|
suspend fun deleteItem(track: Track) {
|
||||||
return withIOContext {
|
return withIOContext {
|
||||||
val request =
|
val request =
|
||||||
Request.Builder()
|
Request.Builder()
|
||||||
.url(mangaUrl(track.media_id).toString())
|
.url(mangaUrl(track.media_id).toString())
|
||||||
.delete()
|
.delete()
|
||||||
.build()
|
.build()
|
||||||
with(json) {
|
authClient.newCall(request)
|
||||||
authClient.newCall(request)
|
.awaitSuccess()
|
||||||
.awaitSuccess()
|
|
||||||
track
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user