use custom JsonAdapter to be compatible with instances that have a custom subscribing feature (#2298)

This commit is contained in:
Konrad Pozniak 2022-01-21 07:34:26 +01:00 committed by GitHub
parent 1586817c3d
commit 2fd01f7e2d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 170 additions and 1 deletions

View file

@ -15,7 +15,9 @@
package com.keylesspalace.tusky.entity
import com.google.gson.annotations.JsonAdapter
import com.google.gson.annotations.SerializedName
import com.keylesspalace.tusky.json.GuardedBooleanAdapter
data class Relationship(
val id: String,
@ -26,7 +28,11 @@ data class Relationship(
@SerializedName("muting_notifications") val mutingNotifications: Boolean,
val requested: Boolean,
@SerializedName("showing_reblogs") val showingReblogs: Boolean,
val subscribing: Boolean? = null, // Pleroma extension
/* Pleroma extension, same as 'notifying' on Mastodon.
* Some instances like qoto.org have a custom subscription feature where 'subscribing' is a json object,
* so we use the custom GuardedBooleanAdapter to ignore the field if it is not a boolean.
*/
@JsonAdapter(GuardedBooleanAdapter::class) val subscribing: Boolean? = null,
@SerializedName("domain_blocking") val blockingDomain: Boolean,
val note: String?, // nullable for backward compatibility / feature detection
val notifying: Boolean? // since 3.3.0rc

View file

@ -0,0 +1,33 @@
/* Copyright 2022 Tusky Contributors
*
* This file is a part of Tusky.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.json
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonParseException
import java.lang.reflect.Type
class GuardedBooleanAdapter : JsonDeserializer<Boolean?> {
@Throws(JsonParseException::class)
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Boolean? {
return if (json.isJsonObject) {
null
} else {
json.asBoolean
}
}
}

View file

@ -0,0 +1,130 @@
package com.keylesspalace.tusky.json
import com.google.gson.Gson
import com.keylesspalace.tusky.entity.Relationship
import org.junit.Assert.assertEquals
import org.junit.Test
class GuardedBooleanAdapterTest {
private val gson = Gson()
@Test
fun `should deserialize Relationship when attribute 'subscribing' is a boolean`() {
val jsonInput = """
{
"id": "1",
"following": true,
"showing_reblogs": true,
"notifying": false,
"followed_by": true,
"blocking": false,
"blocked_by": false,
"muting": false,
"muting_notifications": false,
"requested": false,
"domain_blocking": false,
"endorsed": false,
"note": "Hi",
"subscribing": true
}
""".trimIndent()
assertEquals(
Relationship(
id = "1",
following = true,
followedBy = true,
blocking = false,
muting = false,
mutingNotifications = false,
requested = false,
showingReblogs = true,
subscribing = true,
blockingDomain = false,
note = "Hi",
notifying = false
),
gson.fromJson(jsonInput, Relationship::class.java)
)
}
@Test
fun `should deserialize Relationship when attribute 'subscribing' is an object`() {
val jsonInput = """
{
"id": "2",
"following": true,
"showing_reblogs": true,
"notifying": false,
"followed_by": true,
"blocking": false,
"blocked_by": false,
"muting": false,
"muting_notifications": false,
"requested": false,
"domain_blocking": false,
"endorsed": false,
"note": "Hi",
"subscribing": { }
}
""".trimIndent()
assertEquals(
Relationship(
id = "2",
following = true,
followedBy = true,
blocking = false,
muting = false,
mutingNotifications = false,
requested = false,
showingReblogs = true,
subscribing = null,
blockingDomain = false,
note = "Hi",
notifying = false
),
gson.fromJson(jsonInput, Relationship::class.java)
)
}
@Test
fun `should deserialize Relationship when attribute 'subscribing' does not exist`() {
val jsonInput = """
{
"id": "3",
"following": true,
"showing_reblogs": true,
"notifying": false,
"followed_by": true,
"blocking": false,
"blocked_by": false,
"muting": false,
"muting_notifications": false,
"requested": false,
"domain_blocking": false,
"endorsed": false,
"note": "Hi"
}
""".trimIndent()
assertEquals(
Relationship(
id = "3",
following = true,
followedBy = true,
blocking = false,
muting = false,
mutingNotifications = false,
requested = false,
showingReblogs = true,
subscribing = null,
blockingDomain = false,
note = "Hi",
notifying = false
),
gson.fromJson(jsonInput, Relationship::class.java)
)
}
}