serialization of ChatMember and changing of id type in User

This commit is contained in:
InsanusMokrassar 2020-11-14 14:38:54 +06:00
parent ed87c0ad95
commit 3b08bc6dd2
16 changed files with 179 additions and 149 deletions

View File

@ -2,6 +2,12 @@
## 0.30.5 ## 0.30.5
* `Core`:
* Mechanism of `ChatMember` serialization has been changed
* Since this version any `ChatMember` can be serialized (even outside in case it marked by `@Serializable`)
* Since this version any `ChatMember` (included in this project) can be deserialized in common way
* `User` property `id` has changed its type: now it is `UserId` (under the hood it is the same as `ChatId`)
## 0.30.4 ## 0.30.4
* `Common`: * `Common`:

View File

@ -4,13 +4,13 @@ import dev.inmo.tgbotapi.CommonAbstracts.types.ChatRequest
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember
import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMemberSerializerWithoutDeserialization import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMemberSerializer
import dev.inmo.tgbotapi.types.chatIdField import dev.inmo.tgbotapi.types.chatIdField
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.builtins.ListSerializer
private val chatMembersListSerializer = ListSerializer( private val chatMembersListSerializer = ListSerializer(
AdministratorChatMemberSerializerWithoutDeserialization AdministratorChatMemberSerializer
) )
@Serializable @Serializable

View File

@ -2,8 +2,8 @@ package dev.inmo.tgbotapi.requests.chat.members
import dev.inmo.tgbotapi.requests.chat.abstracts.ChatMemberRequest import dev.inmo.tgbotapi.requests.chat.abstracts.ChatMemberRequest
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.ChatMemberSerializer
import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember
import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMemberDeserializationStrategy
import kotlinx.serialization.* import kotlinx.serialization.*
@Serializable @Serializable
@ -15,7 +15,7 @@ data class GetChatMember(
) : ChatMemberRequest<ChatMember> { ) : ChatMemberRequest<ChatMember> {
override fun method(): String = "getChatMember" override fun method(): String = "getChatMember"
override val resultDeserializer: DeserializationStrategy<ChatMember> override val resultDeserializer: DeserializationStrategy<ChatMember>
get() = ChatMemberDeserializationStrategy get() = ChatMemberSerializer
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()
} }

View File

@ -1,19 +1,37 @@
package dev.inmo.tgbotapi.types.ChatMember package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember
import dev.inmo.tgbotapi.types.User import kotlinx.serialization.*
@Serializable
data class AdministratorChatMemberImpl( data class AdministratorChatMemberImpl(
@SerialName(userField)
override val user: User, override val user: User,
override val canBeEdited: Boolean, @SerialName(canBeEditedField)
override val canChangeInfo: Boolean, override val canBeEdited: Boolean = false,
override val canPostMessages: Boolean, @SerialName(canChangeInfoField)
override val canEditMessages: Boolean, override val canChangeInfo: Boolean = false,
override val canRemoveMessages: Boolean, @SerialName(canPostMessagesField)
override val canInviteUsers: Boolean, override val canPostMessages: Boolean = false,
override val canRestrictMembers: Boolean, @SerialName(canEditMessagesField)
override val canPinMessages: Boolean, override val canEditMessages: Boolean = false,
override val canPromoteMembers: Boolean, @SerialName(canDeleteMessagesField)
override val isAnonymous: Boolean, override val canRemoveMessages: Boolean = false,
override val customTitle: String? @SerialName(canInviteUsersField)
) : AdministratorChatMember override val canInviteUsers: Boolean = false,
@SerialName(canRestrictMembersField)
override val canRestrictMembers: Boolean = false,
@SerialName(canPinMessagesField)
override val canPinMessages: Boolean = false,
@SerialName(canPromoteMembersField)
override val canPromoteMembers: Boolean = false,
@SerialName(isAnonymousField)
override val isAnonymous: Boolean = false,
@SerialName(customTitleField)
override val customTitle: String? = null
) : AdministratorChatMember {
@SerialName(statusField)
@Required
private val type: String = "administrator"
}

View File

@ -1,20 +1,36 @@
package dev.inmo.tgbotapi.types.ChatMember package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember
import dev.inmo.tgbotapi.types.User import kotlinx.serialization.*
@Serializable
data class CreatorChatMember( data class CreatorChatMember(
override val user: User, override val user: User,
override val isAnonymous: Boolean, @SerialName(isAnonymousField)
override val customTitle: String? override val isAnonymous: Boolean = false,
@SerialName(customTitleField)
override val customTitle: String? = null
) : AdministratorChatMember { ) : AdministratorChatMember {
@Transient
override val canBeEdited: Boolean = true override val canBeEdited: Boolean = true
@Transient
override val canChangeInfo: Boolean = true override val canChangeInfo: Boolean = true
@Transient
override val canPostMessages: Boolean = true override val canPostMessages: Boolean = true
@Transient
override val canEditMessages: Boolean = true override val canEditMessages: Boolean = true
@Transient
override val canRemoveMessages: Boolean = true override val canRemoveMessages: Boolean = true
@Transient
override val canInviteUsers: Boolean = true override val canInviteUsers: Boolean = true
@Transient
override val canRestrictMembers: Boolean = true override val canRestrictMembers: Boolean = true
@Transient
override val canPinMessages: Boolean = true override val canPinMessages: Boolean = true
@Transient
override val canPromoteMembers: Boolean = true override val canPromoteMembers: Boolean = true
@SerialName(statusField)
@Required
private val type: String = "creator"
} }

View File

@ -1,10 +1,17 @@
package dev.inmo.tgbotapi.types.ChatMember package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.BannedChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.BannedChatMember
import dev.inmo.tgbotapi.types.TelegramDate import kotlinx.serialization.*
import dev.inmo.tgbotapi.types.User
@Serializable
data class KickedChatMember( data class KickedChatMember(
@SerialName(userField)
override val user: User, override val user: User,
override val untilDate: TelegramDate? @SerialName(untilDateField)
) : BannedChatMember override val untilDate: TelegramDate? = null
) : BannedChatMember {
@SerialName(statusField)
@Required
private val type: String = "kicked"
}

View File

@ -1,7 +1,12 @@
package dev.inmo.tgbotapi.types.ChatMember package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember
import dev.inmo.tgbotapi.types.User import kotlinx.serialization.*
data class LeftChatMember(override val user: User) : @Serializable
ChatMember data class LeftChatMember(@SerialName(userField) override val user: User) : ChatMember {
@SerialName(statusField)
@Required
private val type: String = "left"
}

View File

@ -1,7 +1,12 @@
package dev.inmo.tgbotapi.types.ChatMember package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember
import dev.inmo.tgbotapi.types.User import kotlinx.serialization.*
data class MemberChatMember(override val user: User) : @Serializable
ChatMember data class MemberChatMember(@SerialName(userField) override val user: User) : ChatMember {
@SerialName(statusField)
@Required
private val type: String = "member"
}

View File

@ -1,87 +0,0 @@
package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
internal data class RawChatMember(
val user: User,
private val status: String,
private val until_date: TelegramDate? = null,
@SerialName(canBeEditedField)
private val canBeEdited: Boolean = false,
@SerialName(canChangeInfoField)
private val canChangeInfo: Boolean = false,
@SerialName(canPostMessagesField)
private val canPostMessages: Boolean = false,
@SerialName(canEditMessagesField)
private val canEditMessages: Boolean = false,
@SerialName(canDeleteMessagesField)
private val canDeleteMessages: Boolean = false,
@SerialName(canInviteUsersField)
private val canInviteUsers: Boolean = false,
@SerialName(canRestrictMembersField)
private val canRestrictMembers: Boolean = false,
@SerialName(canPinMessagesField)
private val canPinMessages: Boolean = false,
@SerialName(canPromoteMembersField)
private val canPromoteMembers: Boolean = false,
@SerialName(isMemberField)
private val isMember: Boolean = false,
@SerialName(canSendMessagesField)
private val canSendMessages: Boolean = false,
@SerialName(canSendMediaMessagesField)
private val canSendMediaMessages: Boolean = false,
@SerialName(canSendPollsField)
private val canSendPolls: Boolean = false,
@SerialName(canSendOtherMessagesField)
private val canSendOtherMessages: Boolean = false,
@SerialName(canAddWebPagePreviewsField)
private val canAddWebPagePreviews: Boolean = false,
@SerialName(isAnonymousField)
private val isAnonymous: Boolean = false,
@SerialName(customTitleField)
private val customTitle: String? = null
) {
val asChatMember: ChatMember by lazy {
when (status) {
"creator" -> CreatorChatMember(user, isAnonymous, customTitle)
"administrator" -> AdministratorChatMemberImpl(
user,
canBeEdited,
canChangeInfo,
canPostMessages,
canEditMessages,
canDeleteMessages,
canInviteUsers,
canRestrictMembers,
canPinMessages,
canPromoteMembers,
isAnonymous,
customTitle
)
"member" -> MemberChatMember(user)
"restricted" -> RestrictedChatMember(
user,
until_date,
isMember,
canSendMessages,
canSendMediaMessages,
canSendPolls,
canSendOtherMessages,
canAddWebPagePreviews,
canChangeInfo,
canInviteUsers,
canPinMessages
)
"left" -> LeftChatMember(user)
"kicked" -> KickedChatMember(
user,
until_date
)
else -> throw IllegalStateException("Can't understand type of user: $status")
}
}
}

View File

@ -1,20 +1,36 @@
package dev.inmo.tgbotapi.types.ChatMember package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.BannedChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.BannedChatMember
import dev.inmo.tgbotapi.types.ChatMember.abstracts.SpecialRightsChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.SpecialRightsChatMember
import dev.inmo.tgbotapi.types.TelegramDate import kotlinx.serialization.*
import dev.inmo.tgbotapi.types.User
@Serializable
data class RestrictedChatMember( data class RestrictedChatMember(
@SerialName(userField)
override val user: User, override val user: User,
override val untilDate: TelegramDate?, @SerialName(untilDateField)
val isMember: Boolean, override val untilDate: TelegramDate? = null,
val canSendMessages: Boolean, @SerialName(isMemberField)
val canSendMediaMessages: Boolean, val isMember: Boolean = false,
val canSendPolls: Boolean, @SerialName(canSendMessagesField)
val canSendOtherMessages: Boolean, val canSendMessages: Boolean = false,
val canAddWebpagePreviews: Boolean, @SerialName(canSendMediaMessagesField)
override val canChangeInfo: Boolean, val canSendMediaMessages: Boolean = false,
override val canInviteUsers: Boolean, @SerialName(canSendPollsField)
override val canPinMessages: Boolean val canSendPolls: Boolean = false,
) : BannedChatMember, SpecialRightsChatMember @SerialName(canSendOtherMessagesField)
val canSendOtherMessages: Boolean = false,
@SerialName(canAddWebPagePreviewsField)
val canAddWebpagePreviews: Boolean = false,
@SerialName(canChangeInfoField)
override val canChangeInfo: Boolean = false,
@SerialName(canInviteUsersField)
override val canInviteUsers: Boolean = false,
@SerialName(canPinMessagesField)
override val canPinMessages: Boolean = false
) : BannedChatMember, SpecialRightsChatMember {
@SerialName(statusField)
@Required
private val type: String = "restricted"
}

View File

@ -1,5 +1,12 @@
package dev.inmo.tgbotapi.types.ChatMember.abstracts package dev.inmo.tgbotapi.types.ChatMember.abstracts
import dev.inmo.tgbotapi.types.ChatMember.ChatMemberSerializer
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
@Serializable(AdministratorChatMemberSerializer::class)
interface AdministratorChatMember : SpecialRightsChatMember { interface AdministratorChatMember : SpecialRightsChatMember {
val canBeEdited: Boolean val canBeEdited: Boolean
val canPostMessages: Boolean val canPostMessages: Boolean
@ -9,4 +16,12 @@ interface AdministratorChatMember : SpecialRightsChatMember {
val canPromoteMembers: Boolean val canPromoteMembers: Boolean
val isAnonymous: Boolean val isAnonymous: Boolean
val customTitle: String? val customTitle: String?
} }
@Serializer(AdministratorChatMember::class)
internal object AdministratorChatMemberSerializer : KSerializer<AdministratorChatMember> {
override val descriptor: SerialDescriptor = ChatMemberSerializer.descriptor
override fun deserialize(decoder: Decoder): AdministratorChatMember = ChatMemberSerializer.deserialize(decoder) as AdministratorChatMember
override fun serialize(encoder: Encoder, value: AdministratorChatMember) = ChatMemberSerializer.serialize(encoder, value)
}

View File

@ -1,5 +1,8 @@
package dev.inmo.tgbotapi.types.ChatMember.abstracts package dev.inmo.tgbotapi.types.ChatMember.abstracts
import dev.inmo.tgbotapi.CommonAbstracts.types.UntilDate import dev.inmo.tgbotapi.CommonAbstracts.types.UntilDate
import dev.inmo.tgbotapi.types.ChatMember.ChatMemberSerializer
import kotlinx.serialization.Serializable
@Serializable(ChatMemberSerializer::class)
interface BannedChatMember : ChatMember, UntilDate interface BannedChatMember : ChatMember, UntilDate

View File

@ -1,27 +1,46 @@
package dev.inmo.tgbotapi.types.ChatMember.abstracts package dev.inmo.tgbotapi.types.ChatMember.abstracts
import dev.inmo.tgbotapi.types.ChatMember.RawChatMember import dev.inmo.tgbotapi.types.ChatMember.*
import dev.inmo.tgbotapi.types.User import dev.inmo.tgbotapi.types.User
import kotlinx.serialization.DeserializationStrategy import dev.inmo.tgbotapi.types.statusField
import kotlinx.serialization.KSerializer import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonPrimitive
@Serializable(ChatMemberSerializer::class)
interface ChatMember { interface ChatMember {
val user: User val user: User
} }
internal object AdministratorChatMemberSerializerWithoutDeserialization : KSerializer<AdministratorChatMember> { @Serializer(ChatMember::class)
override val descriptor: SerialDescriptor = ChatMemberDeserializationStrategy.descriptor internal object ChatMemberSerializer : KSerializer<ChatMember> {
override val descriptor: SerialDescriptor = JsonObject.serializer().descriptor
override fun deserialize(decoder: Decoder): AdministratorChatMember override fun deserialize(decoder: Decoder): ChatMember {
= ChatMemberDeserializationStrategy.deserialize(decoder) as AdministratorChatMember val json = JsonObject.serializer().deserialize(decoder)
override fun serialize(encoder: Encoder, value: AdministratorChatMember) = throw UnsupportedOperationException() return when (json[statusField] ?.jsonPrimitive ?.content ?: error("Status field of chat member must be specified, but incoming json contains next: $json")) {
} "creator" -> nonstrictJsonFormat.decodeFromJsonElement(CreatorChatMember.serializer(), json)
"administrator" -> nonstrictJsonFormat.decodeFromJsonElement(AdministratorChatMemberImpl.serializer(), json)
internal object ChatMemberDeserializationStrategy : DeserializationStrategy<ChatMember> { "member" -> nonstrictJsonFormat.decodeFromJsonElement(MemberChatMember.serializer(), json)
override val descriptor: SerialDescriptor = RawChatMember.serializer().descriptor "restricted" -> nonstrictJsonFormat.decodeFromJsonElement(RestrictedChatMember.serializer(), json)
"left" -> nonstrictJsonFormat.decodeFromJsonElement(LeftChatMember.serializer(), json)
override fun deserialize(decoder: Decoder): ChatMember = RawChatMember.serializer().deserialize(decoder).asChatMember "kicked" -> nonstrictJsonFormat.decodeFromJsonElement(KickedChatMember.serializer(), json)
else -> error("Unknown type of chat member in json: $json")
}
}
override fun serialize(encoder: Encoder, value: ChatMember) {
when (value) {
is CreatorChatMember -> CreatorChatMember.serializer()
is AdministratorChatMemberImpl -> AdministratorChatMemberImpl.serializer()
is MemberChatMember -> MemberChatMember.serializer()
is RestrictedChatMember -> RestrictedChatMember.serializer()
is LeftChatMember -> LeftChatMember.serializer()
is KickedChatMember -> KickedChatMember.serializer()
}
}
} }

View File

@ -1,5 +1,9 @@
package dev.inmo.tgbotapi.types.ChatMember.abstracts package dev.inmo.tgbotapi.types.ChatMember.abstracts
import dev.inmo.tgbotapi.types.ChatMember.ChatMemberSerializer
import kotlinx.serialization.Serializable
@Serializable(ChatMemberSerializer::class)
interface SpecialRightsChatMember : ChatMember { interface SpecialRightsChatMember : ChatMember {
val canChangeInfo: Boolean val canChangeInfo: Boolean
val canInviteUsers: Boolean val canInviteUsers: Boolean

View File

@ -232,6 +232,7 @@ const val canSendPollsField = "can_send_polls"
const val canAddWebPagePreviewsField = "can_add_web_page_previews" const val canAddWebPagePreviewsField = "can_add_web_page_previews"
const val canSetStickerSetField = "can_set_sticker_set" const val canSetStickerSetField = "can_set_sticker_set"
const val statusField = "status"
const val canBeEditedField = "can_be_edited" const val canBeEditedField = "can_be_edited"
const val canChangeInfoField = "can_change_info" const val canChangeInfoField = "can_change_info"
const val canPostMessagesField = "can_post_messages" const val canPostMessagesField = "can_post_messages"

View File

@ -10,11 +10,13 @@ import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.* import kotlinx.serialization.json.*
@Serializable(UserSerializer::class) @Serializable(UserSerializer::class)
sealed class User : PrivateChat sealed class User : PrivateChat {
abstract override val id: UserId
}
@Serializable @Serializable
data class CommonUser( data class CommonUser(
override val id: ChatId, override val id: UserId,
@SerialName(firstNameField) @SerialName(firstNameField)
override val firstName: String, override val firstName: String,
@SerialName(lastNameField) @SerialName(lastNameField)
@ -35,7 +37,7 @@ sealed class Bot : User() {
@Serializable @Serializable
data class CommonBot( data class CommonBot(
override val id: ChatId, override val id: UserId,
@SerialName(usernameField) @SerialName(usernameField)
override val username: Username, override val username: Username,
@SerialName(firstNameField) @SerialName(firstNameField)
@ -49,7 +51,7 @@ data class CommonBot(
@Serializable @Serializable
data class ExtendedBot( data class ExtendedBot(
override val id: ChatId, override val id: UserId,
@SerialName(usernameField) @SerialName(usernameField)
override val username: Username, override val username: Username,
@SerialName(firstNameField) @SerialName(firstNameField)