1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-09-16 13:49:26 +00:00

add support of forum chats

This commit is contained in:
2022-11-06 12:51:53 +06:00
parent 8f4eb74e39
commit 867a46d397
10 changed files with 432 additions and 43 deletions

View File

@@ -11,6 +11,7 @@ import kotlin.jvm.JvmInline
typealias Identifier = Long
typealias MessageId = Long
typealias MessageThreadId = Long
typealias MessageIdentifier = MessageId
typealias InlineQueryIdentifier = String
typealias UpdateIdentifier = Long
@@ -148,6 +149,7 @@ const val tgWebAppStartParamField = "tgWebAppStartParam"
const val chatIdField = "chat_id"
const val senderChatIdField = "sender_chat_id"
const val messageIdField = "message_id"
const val messageThreadIdField = "message_thread_id"
const val updateIdField = "update_id"
const val fromChatIdField = "from_chat_id"
const val disableWebPagePreviewField = "disable_web_page_preview"
@@ -313,6 +315,7 @@ const val botCommandsField = "commands"
const val scopeField = "scope"
const val isMemberField = "is_member"
const val isForumField = "is_forum"
const val canSendMessagesField = "can_send_messages"
const val canSendMediaMessagesField = "can_send_media_messages"
const val canSendOtherMessagesField = "can_send_other_messages"

View File

@@ -5,10 +5,9 @@ import dev.inmo.tgbotapi.types.*
import kotlinx.serialization.Serializable
@Serializable(PreviewChatSerializer::class)
sealed interface ChannelChat : SuperPublicChat
@Serializable(PreviewChatSerializer::class)
sealed interface GroupChat : PublicChat
sealed interface UsernameChat : Chat {
val username: Username?
}
@Serializable(PreviewChatSerializer::class)
sealed interface PrivateChat : Chat, UsernameChat {
@@ -22,16 +21,20 @@ sealed interface PublicChat : Chat {
val title: String
}
@Serializable(PreviewChatSerializer::class)
sealed interface SupergroupChat : GroupChat, SuperPublicChat
@Serializable(PreviewChatSerializer::class)
sealed interface SuperPublicChat : PublicChat, UsernameChat
@Serializable(PreviewChatSerializer::class)
sealed interface UsernameChat : Chat {
val username: Username?
}
sealed interface ChannelChat : SuperPublicChat
@Serializable(PreviewChatSerializer::class)
sealed interface GroupChat : PublicChat
@Serializable(PreviewChatSerializer::class)
sealed interface SupergroupChat : GroupChat, SuperPublicChat
@Serializable(PreviewChatSerializer::class)
sealed interface ForumChat : SupergroupChat
@Serializable(PreviewChatSerializer::class)
sealed interface PossiblyPremiumChat : Chat {

View File

@@ -57,11 +57,16 @@ object PreviewChatSerializer : KSerializer<Chat> {
val decodedJson = JsonObject.serializer().deserialize(decoder)
val type = decodedJson[typeField] ?.jsonPrimitive ?.content ?.asChatType ?: error("Field $typeField must be presented, but absent in $decodedJson")
val isForum = decodedJson[isForumField] ?.jsonPrimitive ?.booleanOrNull == true
return when (type) {
ChatType.PrivateChatType -> formatter.decodeFromJsonElement(PrivateChatImpl.serializer(), decodedJson)
ChatType.GroupChatType -> formatter.decodeFromJsonElement(GroupChatImpl.serializer(), decodedJson)
ChatType.SupergroupChatType -> formatter.decodeFromJsonElement(SupergroupChatImpl.serializer(), decodedJson)
ChatType.SupergroupChatType -> if (isForum) {
formatter.decodeFromJsonElement(ForumChatImpl.serializer(), decodedJson)
} else {
formatter.decodeFromJsonElement(SupergroupChatImpl.serializer(), decodedJson)
}
ChatType.ChannelChatType -> formatter.decodeFromJsonElement(ChannelChatImpl.serializer(), decodedJson)
is ChatType.UnknownChatType -> UnknownChatType(
formatter.decodeFromJsonElement(Long.serializer(), decodedJson[chatIdField] ?: JsonPrimitive(-1)).toChatId(),
@@ -77,6 +82,7 @@ object PreviewChatSerializer : KSerializer<Chat> {
is PrivateChatImpl -> PrivateChatImpl.serializer().serialize(encoder, value)
is GroupChatImpl -> GroupChatImpl.serializer().serialize(encoder, value)
is SupergroupChatImpl -> SupergroupChatImpl.serializer().serialize(encoder, value)
is ForumChatImpl -> ForumChatImpl.serializer().serialize(encoder, value)
is ChannelChatImpl -> ChannelChatImpl.serializer().serialize(encoder, value)
is CommonBot -> CommonBot.serializer().serialize(encoder, value)
is ExtendedBot -> ExtendedBot.serializer().serialize(encoder, value)
@@ -95,12 +101,17 @@ object ExtendedChatSerializer : KSerializer<ExtendedChat> {
val decodedJson = JsonObject.serializer().deserialize(decoder)
val type = decodedJson[typeField] ?.jsonPrimitive ?.content ?.asChatType ?: error("Field $typeField must be presented, but absent in $decodedJson")
val isForum = decodedJson[isForumField] ?.jsonPrimitive ?.booleanOrNull == true
return when (type) {
// else -> throw IllegalArgumentException("Unknown type of chat")
ChatType.PrivateChatType -> formatter.decodeFromJsonElement(ExtendedPrivateChatImpl.serializer(), decodedJson)
ChatType.GroupChatType -> formatter.decodeFromJsonElement(ExtendedGroupChatImpl.serializer(), decodedJson)
ChatType.SupergroupChatType -> formatter.decodeFromJsonElement(ExtendedSupergroupChatImpl.serializer(), decodedJson)
ChatType.SupergroupChatType -> if (isForum) {
formatter.decodeFromJsonElement(ExtendedForumChatImpl.serializer(), decodedJson)
} else {
formatter.decodeFromJsonElement(ExtendedSupergroupChatImpl.serializer(), decodedJson)
}
ChatType.ChannelChatType -> formatter.decodeFromJsonElement(ExtendedChannelChatImpl.serializer(), decodedJson)
is ChatType.UnknownChatType -> UnknownExtendedChat(
formatter.decodeFromJsonElement(Long.serializer(), decodedJson[chatIdField] ?: JsonPrimitive(-1)).toChatId(),
@@ -115,6 +126,7 @@ object ExtendedChatSerializer : KSerializer<ExtendedChat> {
is ExtendedPrivateChatImpl -> ExtendedPrivateChatImpl.serializer().serialize(encoder, value)
is ExtendedGroupChatImpl -> ExtendedGroupChatImpl.serializer().serialize(encoder, value)
is ExtendedSupergroupChatImpl -> ExtendedSupergroupChatImpl.serializer().serialize(encoder, value)
is ExtendedForumChatImpl -> ExtendedForumChatImpl.serializer().serialize(encoder, value)
is ExtendedChannelChatImpl -> ExtendedChannelChatImpl.serializer().serialize(encoder, value)
is UnknownExtendedChat -> JsonObject.serializer().serialize(encoder, value.rawJson)
}

View File

@@ -104,6 +104,41 @@ data class ExtendedSupergroupChatImpl(
override val requireAdminApproveToJoin: Boolean = false
) : ExtendedSupergroupChat
@Serializable
data class ExtendedForumChatImpl(
@SerialName(idField)
override val id: ChatId,
@SerialName(titleField)
override val title: String,
@SerialName(usernameField)
override val username: Username? = null,
@SerialName(photoField)
override val chatPhoto: ChatPhoto? = null,
@SerialName(permissionsField)
override val permissions: ChatPermissions,
@SerialName(descriptionField)
override val description: String = "",
@SerialName(inviteLinkField)
override val inviteLink: String? = null,
@SerialName(pinnedMessageField)
@Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class)
override val pinnedMessage: Message? = null,
@SerialName(stickerSetNameFullField)
override val stickerSetName: StickerSetName? = null,
@SerialName(slowModeDelayField)
override val slowModeDelay: Long? = null,
@SerialName(canSetStickerSetField)
override val canSetStickerSet: Boolean = false,
@SerialName(linkedChatIdField)
override val linkedChannelChatId: ChatId? = null,
@SerialName(locationField)
override val location: ChatLocation? = null,
@SerialName(joinToSendMessagesField)
override val requiresJoinForMessaging: Boolean = false,
@SerialName(joinByRequestField)
override val requireAdminApproveToJoin: Boolean = false
) : ExtendedForumChat
@Serializable
data class ExtendedBot(
override val id: UserId,

View File

@@ -51,6 +51,9 @@ sealed interface ExtendedSupergroupChat : SupergroupChat, ExtendedGroupChat {
val requireAdminApproveToJoin: Boolean
}
@Serializable(ExtendedChatSerializer::class)
sealed interface ExtendedForumChat : ExtendedSupergroupChat
@Serializable(ExtendedChatSerializer::class)
sealed interface ExtendedChat : Chat {
val chatPhoto: ChatPhoto?

View File

@@ -37,6 +37,16 @@ data class SupergroupChatImpl(
override val username: Username? = null
) : SupergroupChat
@Serializable
data class ForumChatImpl(
@SerialName(idField)
override val id: ChatId,
@SerialName(titleField)
override val title: String,
@SerialName(usernameField)
override val username: Username? = null
) : ForumChat
@Serializable
data class ChannelChatImpl(
@SerialName(idField)

View File

@@ -66,3 +66,49 @@ data class CommonGroupContentMessageImpl<T : MessageContent>(
override val content: T,
override val senderBot: CommonBot?
) : CommonGroupContentMessage<T>
data class FromChannelForumContentMessageImpl<T: MessageContent>(
override val chat: ForumChat,
override val channel: ChannelChat,
override val messageId: MessageId,
override val threadId: MessageThreadId,
override val date: DateTime,
override val forwardInfo: ForwardInfo?,
override val editDate: DateTime?,
override val hasProtectedContent: Boolean,
override val replyTo: Message?,
override val replyMarkup: InlineKeyboardMarkup?,
override val content: T,
override val senderBot: CommonBot?,
override val authorSignature: AuthorSignature?
) : FromChannelForumContentMessage<T>
data class AnonymousForumContentMessageImpl<T : MessageContent>(
override val chat: ForumChat,
override val messageId: MessageId,
override val threadId: MessageThreadId,
override val date: DateTime,
override val forwardInfo: ForwardInfo?,
override val editDate: DateTime?,
override val hasProtectedContent: Boolean,
override val replyTo: Message?,
override val replyMarkup: InlineKeyboardMarkup?,
override val content: T,
override val senderBot: CommonBot?,
override val authorSignature: AuthorSignature?
) : AnonymousForumContentMessage<T>
data class CommonForumContentMessageImpl<T : MessageContent>(
override val chat: ForumChat,
override val messageId: MessageId,
override val threadId: MessageThreadId,
override val from: User,
override val date: DateTime,
override val forwardInfo: ForwardInfo?,
override val editDate: DateTime?,
override val hasProtectedContent: Boolean,
override val replyTo: Message?,
override val replyMarkup: InlineKeyboardMarkup?,
override val content: T,
override val senderBot: CommonBot?
) : CommonForumContentMessage<T>

View File

@@ -34,6 +34,8 @@ internal data class RawMessage(
val messageId: MessageId,
val date: TelegramDate,
private val chat: Chat,
@SerialName(messageThreadIdField)
private val messageThreadId: MessageThreadId? = null,
private val from: User? = null,
private val sender_chat: PublicChat? = null,
private val forward_from: User? = null,
@@ -307,6 +309,113 @@ internal data class RawMessage(
via_bot,
author_signature
)
is ForumChat -> if (messageThreadId != null) {
when (sender_chat) {
is ChannelChat -> FromChannelForumContentMessageImpl(
chat,
sender_chat,
messageId,
messageThreadId,
date.asDate,
forwarded,
edit_date ?.asDate,
has_protected_content == true,
reply_to_message ?.asMessage,
reply_markup,
content,
via_bot,
author_signature
)
is GroupChat -> AnonymousForumContentMessageImpl(
chat,
messageId,
messageThreadId,
date.asDate,
forwarded,
edit_date ?.asDate,
has_protected_content == true,
reply_to_message ?.asMessage,
reply_markup,
content,
via_bot,
author_signature
)
null -> CommonForumContentMessageImpl(
chat,
messageId,
messageThreadId,
from ?: error("It is expected that in messages from non anonymous users and channels user must be specified"),
date.asDate,
forwarded,
edit_date ?.asDate,
has_protected_content == true,
reply_to_message ?.asMessage,
reply_markup,
content,
via_bot
)
}
} else {
when (sender_chat) {
is ChannelChat -> if (is_automatic_forward == true) {
ConnectedFromChannelGroupContentMessageImpl(
chat,
sender_chat,
messageId,
date.asDate,
forwarded,
edit_date ?.asDate,
has_protected_content == true,
reply_to_message ?.asMessage,
reply_markup,
content,
via_bot,
author_signature
)
} else {
UnconnectedFromChannelGroupContentMessageImpl(
chat,
sender_chat,
messageId,
date.asDate,
forwarded,
edit_date ?.asDate,
has_protected_content == true,
reply_to_message ?.asMessage,
reply_markup,
content,
via_bot,
author_signature
)
}
is GroupChat -> AnonymousGroupContentMessageImpl(
chat,
messageId,
date.asDate,
forwarded,
edit_date ?.asDate,
has_protected_content == true,
reply_to_message ?.asMessage,
reply_markup,
content,
via_bot,
author_signature
)
null -> CommonGroupContentMessageImpl(
chat,
messageId,
from ?: error("It is expected that in messages from non anonymous users and channels user must be specified"),
date.asDate,
forwarded,
edit_date ?.asDate,
has_protected_content == true,
reply_to_message ?.asMessage,
reply_markup,
content,
via_bot
)
}
}
is GroupChat -> when (sender_chat) {
is ChannelChat -> if (is_automatic_forward == true) {
ConnectedFromChannelGroupContentMessageImpl(
@@ -365,9 +474,7 @@ internal data class RawMessage(
content,
via_bot
)
else -> error("Currently in groups supported only fields \"sender_chat\" with channel, group or null, but was $sender_chat")
}
else -> error("Unknown type of public chat: $chat")
}
is PrivateChat -> PrivateContentMessageImpl(
messageId,

View File

@@ -1,15 +1,22 @@
package dev.inmo.tgbotapi.types.message.abstracts
import dev.inmo.tgbotapi.types.MessageThreadId
import dev.inmo.tgbotapi.types.chat.ChannelChat
import dev.inmo.tgbotapi.types.chat.ForumChat
import dev.inmo.tgbotapi.types.chat.GroupChat
import dev.inmo.tgbotapi.types.message.content.MessageContent
interface GroupContentMessage<T : MessageContent> : PublicContentMessage<T> {
sealed interface GroupContentMessage<T : MessageContent> : PublicContentMessage<T> {
override val chat: GroupChat
}
sealed interface ForumContentMessage<T : MessageContent> : GroupContentMessage<T> {
override val chat: ForumChat
val threadId: MessageThreadId
}
interface FromChannelGroupContentMessage<T : MessageContent> : GroupContentMessage<T>, SignedMessage, WithSenderChatMessage {
sealed interface FromChannelGroupContentMessage<T : MessageContent> : GroupContentMessage<T>, SignedMessage, WithSenderChatMessage {
val channel: ChannelChat
override val senderChat: ChannelChat
get() = channel
@@ -24,3 +31,12 @@ interface AnonymousGroupContentMessage<T : MessageContent> : GroupContentMessage
}
interface CommonGroupContentMessage<T : MessageContent> : GroupContentMessage<T>, FromUserMessage
interface FromChannelForumContentMessage<T: MessageContent> : FromChannelGroupContentMessage<T>, ForumContentMessage<T>
interface AnonymousForumContentMessage<T : MessageContent> : ForumContentMessage<T>, SignedMessage, WithSenderChatMessage {
override val senderChat: GroupChat
get() = chat
}
interface CommonForumContentMessage<T : MessageContent> : ForumContentMessage<T>, FromUserMessage