add support of copy/forward/delete messages

This commit is contained in:
InsanusMokrassar 2024-01-03 16:06:54 +06:00
parent db2101d85c
commit c025a027c6
8 changed files with 525 additions and 0 deletions

View File

@ -0,0 +1,67 @@
package dev.inmo.tgbotapi.extensions.api
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.DeleteMessage
import dev.inmo.tgbotapi.requests.DeleteMessages
import dev.inmo.tgbotapi.requests.ForwardMessages
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.message.abstracts.Message
suspend fun TelegramBot.deleteMessages(
chatId: ChatIdentifier,
messageIds: List<MessageId>
) = messageIds.chunked(deleteMessagesLimit.last).map {
execute(
DeleteMessages(
chatId = chatId,
messageIds = it
)
)
}.all { it }
suspend fun TelegramBot.deleteMessages(
chatId: ChatIdentifier,
messageIds: Array<MessageId>
) = deleteMessages(
chatId = chatId,
messageIds = messageIds.toList()
)
suspend fun TelegramBot.deleteMessages(
chatId: ChatIdentifier,
firstMessageId: MessageId,
vararg messageIds: MessageId
) = deleteMessages(
chatId = chatId,
messageIds = (listOf(firstMessageId) + messageIds.toList())
)
suspend fun TelegramBot.deleteMessages(
messages: List<Message>
) = messages.groupBy { it.chat }.map { (chat, messages) ->
deleteMessages(
chatId = chat.id,
messageIds = messages.map { it.messageId }
)
}.all { it }
suspend fun TelegramBot.delete(
chatId: ChatIdentifier,
messageIds: List<MessageId>
) = deleteMessages(chatId = chatId, messageIds = messageIds)
suspend fun TelegramBot.delete(
chatId: ChatIdentifier,
messageIds: Array<MessageId>
) = deleteMessages(chatId = chatId, messageIds = messageIds)
suspend fun TelegramBot.delete(
chatId: ChatIdentifier,
firstMessageId: MessageId,
secondMessageId: MessageId,
vararg messageIds: MessageId
) = deleteMessages(chatId = chatId, messageIds = (listOf(firstMessageId, secondMessageId) + messageIds.toList()))
suspend fun TelegramBot.delete(
messages: List<Message>
) = deleteMessages(messages)

View File

@ -0,0 +1,156 @@
package dev.inmo.tgbotapi.extensions.api
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.ForwardMessages
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.message.abstracts.Message
suspend fun TelegramBot.forwardMessages(
toChatId: ChatIdentifier,
fromChatId: ChatIdentifier,
messageIds: List<MessageId>,
threadId: MessageThreadId? = toChatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
removeCaption: Boolean = false
) = messageIds.chunked(forwardMessagesLimit.last).flatMap {
execute(
ForwardMessages(
toChatId = toChatId,
fromChatId = fromChatId,
messageIds = it,
threadId = threadId,
disableNotification = disableNotification,
protectContent = protectContent,
removeCaption = removeCaption
)
)
}
suspend fun TelegramBot.forwardMessages(
toChatId: ChatIdentifier,
fromChatId: ChatIdentifier,
messageIds: Array<MessageId>,
threadId: MessageThreadId? = toChatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
removeCaption: Boolean = false
) = forwardMessages(
toChatId = toChatId,
fromChatId = fromChatId,
messageIds = messageIds.toList(),
threadId = threadId,
disableNotification = disableNotification,
protectContent = protectContent,
removeCaption = removeCaption
)
suspend fun TelegramBot.forwardMessages(
toChatId: ChatIdentifier,
fromChatId: ChatIdentifier,
firstMessageId: MessageId,
vararg messageIds: MessageId,
threadId: MessageThreadId? = toChatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
removeCaption: Boolean = false
) = forwardMessages(
toChatId = toChatId,
fromChatId = fromChatId,
messageIds = (listOf(firstMessageId) + messageIds.toList()),
threadId = threadId,
disableNotification = disableNotification,
protectContent = protectContent,
removeCaption = removeCaption
)
suspend fun TelegramBot.forwardMessages(
toChatId: ChatIdentifier,
messages: List<Message>,
threadId: MessageThreadId? = toChatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
removeCaption: Boolean = false
) = messages.groupBy { it.chat }.flatMap { (chat, messages) ->
forwardMessages(
toChatId = toChatId,
fromChatId = chat.id,
messageIds = messages.map { it.messageId },
threadId = threadId,
disableNotification = disableNotification,
protectContent = protectContent,
removeCaption = removeCaption
)
}
suspend fun TelegramBot.forward(
toChatId: ChatIdentifier,
fromChatId: ChatIdentifier,
messageIds: List<MessageId>,
threadId: MessageThreadId? = toChatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
removeCaption: Boolean = false
) = forwardMessages(
toChatId = toChatId,
fromChatId = fromChatId,
messageIds = messageIds,
threadId = threadId,
disableNotification = disableNotification,
protectContent = protectContent,
removeCaption = removeCaption
)
suspend fun TelegramBot.forward(
toChatId: ChatIdentifier,
fromChatId: ChatIdentifier,
messageIds: Array<MessageId>,
threadId: MessageThreadId? = toChatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
removeCaption: Boolean = false
) = forwardMessages(
toChatId = toChatId,
fromChatId = fromChatId,
messageIds = messageIds,
threadId = threadId,
disableNotification = disableNotification,
protectContent = protectContent,
removeCaption = removeCaption
)
suspend fun TelegramBot.forward(
toChatId: ChatIdentifier,
fromChatId: ChatIdentifier,
firstMessageId: MessageId,
vararg messageIds: MessageId,
threadId: MessageThreadId? = toChatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
removeCaption: Boolean = false
) = forwardMessages(
toChatId = toChatId,
fromChatId = fromChatId,
firstMessageId = firstMessageId,
messageIds = *messageIds,
threadId = threadId,
disableNotification = disableNotification,
protectContent = protectContent,
removeCaption = removeCaption
)
suspend fun TelegramBot.forward(
toChatId: ChatIdentifier,
messages: List<Message>,
threadId: MessageThreadId? = toChatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
removeCaption: Boolean = false
) = forwardMessages(
toChatId = toChatId,
messages = messages,
threadId = threadId,
disableNotification = disableNotification,
protectContent = protectContent,
removeCaption = removeCaption
)

View File

@ -0,0 +1,84 @@
package dev.inmo.tgbotapi.extensions.api.send
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.send.CopyMessages
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.message.abstracts.Message
suspend fun TelegramBot.copyMessages(
toChatId: ChatIdentifier,
fromChatId: ChatIdentifier,
messageIds: List<MessageId>,
threadId: MessageThreadId? = toChatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
removeCaption: Boolean = false
) = messageIds.chunked(copyMessagesLimit.last).flatMap {
execute(
CopyMessages(
toChatId = toChatId,
fromChatId = fromChatId,
messageIds = it,
threadId = threadId,
disableNotification = disableNotification,
protectContent = protectContent,
removeCaption = removeCaption
)
)
}
suspend fun TelegramBot.copyMessages(
toChatId: ChatIdentifier,
fromChatId: ChatIdentifier,
messageIds: Array<MessageId>,
threadId: MessageThreadId? = toChatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
removeCaption: Boolean = false
) = copyMessages(
toChatId = toChatId,
fromChatId = fromChatId,
messageIds = messageIds.toList(),
threadId = threadId,
disableNotification = disableNotification,
protectContent = protectContent,
removeCaption = removeCaption
)
suspend fun TelegramBot.copyMessages(
toChatId: ChatIdentifier,
fromChatId: ChatIdentifier,
firstMessageId: MessageId,
vararg messageIds: MessageId,
threadId: MessageThreadId? = toChatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
removeCaption: Boolean = false
) = copyMessages(
toChatId = toChatId,
fromChatId = fromChatId,
messageIds = (listOf(firstMessageId) + messageIds.toList()),
threadId = threadId,
disableNotification = disableNotification,
protectContent = protectContent,
removeCaption = removeCaption
)
suspend fun TelegramBot.copyMessages(
toChatId: ChatIdentifier,
messages: List<Message>,
threadId: MessageThreadId? = toChatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
removeCaption: Boolean = false
) = messages.groupBy { it.chat }.flatMap { (chat, messages) ->
copyMessages(
toChatId = toChatId,
fromChatId = chat.id,
messageIds = messages.map { it.messageId },
threadId = threadId,
disableNotification = disableNotification,
protectContent = protectContent,
removeCaption = removeCaption
)
}

View File

@ -0,0 +1,7 @@
package dev.inmo.tgbotapi.abstracts.types
import dev.inmo.tgbotapi.types.MessageId
interface MessagesAction: ChatRequest {
val messageIds: List<MessageId>
}

View File

@ -0,0 +1,29 @@
package dev.inmo.tgbotapi.requests
import dev.inmo.tgbotapi.abstracts.types.MessageAction
import dev.inmo.tgbotapi.abstracts.types.MessagesAction
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.*
import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer
@Serializable
data class DeleteMessages(
@SerialName(chatIdField)
override val chatId: ChatIdentifier,
@SerialName(messageIdsField)
override val messageIds: List<MessageId>
) : SimpleRequest<Boolean>, MessagesAction {
override fun method(): String = "deleteMessages"
init {
require(messageIds.size in deleteMessagesLimit) {
"Messages count for deleteMessages must be in $deleteMessagesLimit range"
}
}
override val resultDeserializer: DeserializationStrategy<Boolean>
get() = Boolean.serializer()
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@ -0,0 +1,85 @@
package dev.inmo.tgbotapi.requests
import dev.inmo.tgbotapi.abstracts.types.DisableNotification
import dev.inmo.tgbotapi.abstracts.types.MessagesAction
import dev.inmo.tgbotapi.abstracts.types.ProtectContent
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.requests.send.abstracts.OptionallyMessageThreadRequest
import dev.inmo.tgbotapi.types.*
import kotlinx.serialization.*
import kotlinx.serialization.builtins.ListSerializer
fun ForwardMessages(
toChatId: ChatIdentifier,
fromChatId: ChatIdentifier,
messageIds: Array<MessageId>,
threadId: MessageThreadId? = toChatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
removeCaption: Boolean = false
) = ForwardMessages(
toChatId = toChatId,
fromChatId = fromChatId,
messageIds = messageIds.toList(),
threadId = threadId,
disableNotification = disableNotification,
protectContent = protectContent,
removeCaption = removeCaption
)
fun ForwardMessages(
toChatId: ChatIdentifier,
fromChatId: ChatIdentifier,
messageId: MessageId,
vararg messageIds: MessageId,
threadId: MessageThreadId? = toChatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
removeCaption: Boolean = false
) = ForwardMessages(
toChatId = toChatId,
fromChatId = fromChatId,
messageIds = (listOf(messageId) + messageIds.toList()),
threadId = threadId,
disableNotification = disableNotification,
protectContent = protectContent,
removeCaption = removeCaption
)
@Serializable
data class ForwardMessages (
@SerialName(chatIdField)
val toChatId: ChatIdentifier,
@SerialName(fromChatIdField)
val fromChatId: ChatIdentifier,
@SerialName(messageIdsField)
override val messageIds: List<MessageId>,
@SerialName(messageThreadIdField)
override val threadId: MessageThreadId? = toChatId.threadId,
@SerialName(disableNotificationField)
override val disableNotification: Boolean = false,
@SerialName(protectContentField)
override val protectContent: Boolean = false,
@SerialName(removeCaptionField)
private val removeCaption: Boolean = false
): SimpleRequest<List<MessageId>>,
MessagesAction,
ProtectContent,
OptionallyMessageThreadRequest,
DisableNotification {
override val chatId: ChatIdentifier
get() = fromChatId
init {
require(messageIds.size in forwardMessagesLimit) {
"Messages count for forwardMessages must be in $forwardMessagesLimit range"
}
}
override fun method(): String = "forwardMessages"
override val resultDeserializer: DeserializationStrategy<List<MessageId>>
get() = ListSerializer(MessageIdSerializer)
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@ -0,0 +1,91 @@
package dev.inmo.tgbotapi.requests.send
import dev.inmo.tgbotapi.abstracts.types.DisableNotification
import dev.inmo.tgbotapi.abstracts.types.MessagesAction
import dev.inmo.tgbotapi.abstracts.types.ProtectContent
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.requests.send.abstracts.OptionallyMessageThreadRequest
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.message.textsources.TextSource
import dev.inmo.tgbotapi.types.message.ParseMode
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.message.*
import dev.inmo.tgbotapi.types.message.toRawMessageEntities
import dev.inmo.tgbotapi.utils.extensions.makeString
import kotlinx.serialization.*
import kotlinx.serialization.builtins.ListSerializer
fun CopyMessages(
toChatId: ChatIdentifier,
fromChatId: ChatIdentifier,
messageIds: Array<MessageId>,
threadId: MessageThreadId? = toChatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
removeCaption: Boolean = false
) = CopyMessages(
toChatId = toChatId,
fromChatId = fromChatId,
messageIds = messageIds.toList(),
threadId = threadId,
disableNotification = disableNotification,
protectContent = protectContent,
removeCaption = removeCaption
)
fun CopyMessages(
toChatId: ChatIdentifier,
fromChatId: ChatIdentifier,
messageId: MessageId,
vararg messageIds: MessageId,
threadId: MessageThreadId? = toChatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
removeCaption: Boolean = false
) = CopyMessages(
toChatId = toChatId,
fromChatId = fromChatId,
messageIds = (listOf(messageId) + messageIds.toList()),
threadId = threadId,
disableNotification = disableNotification,
protectContent = protectContent,
removeCaption = removeCaption
)
@Serializable
data class CopyMessages (
@SerialName(chatIdField)
val toChatId: ChatIdentifier,
@SerialName(fromChatIdField)
val fromChatId: ChatIdentifier,
@SerialName(messageIdsField)
override val messageIds: List<MessageId>,
@SerialName(messageThreadIdField)
override val threadId: MessageThreadId? = toChatId.threadId,
@SerialName(disableNotificationField)
override val disableNotification: Boolean = false,
@SerialName(protectContentField)
override val protectContent: Boolean = false,
@SerialName(removeCaptionField)
private val removeCaption: Boolean = false
): SimpleRequest<List<MessageId>>,
MessagesAction,
ProtectContent,
OptionallyMessageThreadRequest,
DisableNotification {
override val chatId: ChatIdentifier
get() = fromChatId
init {
require(messageIds.size in copyMessagesLimit) {
"Messages count for copyMessages must be in $copyMessagesLimit range"
}
}
override fun method(): String = "copyMessages"
override val resultDeserializer: DeserializationStrategy<List<MessageId>>
get() = ListSerializer(MessageIdSerializer)
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@ -175,6 +175,10 @@ val keywordsInStickerLimit = 0 .. 20
val stickerKeywordLengthLimit = 0 .. 64
val forwardMessagesLimit = 1 .. 100
val copyMessagesLimit = forwardMessagesLimit
val deleteMessagesLimit = forwardMessagesLimit
const val botActionActualityTime: Seconds = 5
val cloudStorageKeyLimit = 1 .. 128
@ -196,6 +200,7 @@ const val tgWebAppStartParamField = "tgWebAppStartParam"
const val chatIdField = "chat_id"
const val senderChatIdField = "sender_chat_id"
const val messageIdField = "message_id"
const val messageIdsField = "message_ids"
const val actorChatField = "actor_chat"
const val messageThreadIdField = "message_thread_id"
const val mediaGroupIdField = "media_group_id"
@ -205,6 +210,7 @@ const val disableWebPagePreviewField = "disable_web_page_preview"
const val linkPreviewOptionsField = "link_preview_options"
const val disableNotificationField = "disable_notification"
const val protectContentField = "protect_content"
const val removeCaptionField = "remove_caption"
const val replyToMessageIdField = "reply_to_message_id"
const val allowSendingWithoutReplyField = "allow_sending_without_reply"
const val replyMarkupField = "reply_markup"