diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/RepliesWithEphemeral.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/RepliesWithEphemeral.kt index f2801956f1..971590fc36 100644 --- a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/RepliesWithEphemeral.kt +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/RepliesWithEphemeral.kt @@ -20,6 +20,7 @@ import dev.inmo.tgbotapi.types.message.abstracts.ChatContentMessage import dev.inmo.tgbotapi.types.message.content.* import dev.inmo.tgbotapi.types.message.textsources.TextSource import dev.inmo.tgbotapi.types.polls.PollOptionPersistentId +import dev.inmo.tgbotapi.types.rich.InputRichMessage import dev.inmo.tgbotapi.types.venue.Venue import dev.inmo.tgbotapi.utils.* import kotlin.jvm.JvmMultifileClass @@ -27,9 +28,83 @@ import kotlin.jvm.JvmName // Ephemeral-only replies // -// Every overload requires replyInChatId, ephemeralMessageParameters.receiverUserId, and replyToEphemeralMessageId because no +// Every overload requires replyInChatId, an EphemeralMessageParameters object, and replyToEphemeralMessageId because no // source message supplies ephemeral reply routing. +public suspend inline fun TelegramBot.replyRichMessage( + replyInChatId: IdChatIdentifier, + ephemeralMessageParameters: EphemeralMessageParameters, + replyToEphemeralMessageId: EphemeralMessageId, + richMessage: InputRichMessage, + replyInThreadId: MessageThreadId? = replyInChatId.threadId, + replyInDirectMessageThreadId: DirectMessageThreadId? = replyInChatId.directMessageThreadId, + replyInBusinessConnectionId: BusinessConnectionId? = replyInChatId.businessConnectionId, + disableNotification: Boolean = false, + protectContent: Boolean = false, + allowPaidBroadcast: Boolean = false, + effectId: EffectId? = null, + suggestedPostParameters: SuggestedPostParameters? = null, + allowSendingWithoutReply: Boolean? = null, + checklistTaskId: ChecklistTaskId? = null, + pollOptionId: PollOptionPersistentId? = null, + replyMarkup: KeyboardMarkup? = null +): ChatContentMessage = sendRichMessage( + chatId = replyInChatId, + richMessage = richMessage, + threadId = replyInThreadId, + directMessageThreadId = replyInDirectMessageThreadId, + businessConnectionId = replyInBusinessConnectionId, + ephemeralMessageParameters = ephemeralMessageParameters, + disableNotification = disableNotification, + protectContent = protectContent, + allowPaidBroadcast = allowPaidBroadcast, + effectId = effectId, + suggestedPostParameters = suggestedPostParameters, + replyParameters = ReplyParameters( + ephemeralMessageId = replyToEphemeralMessageId, + allowSendingWithoutReply = allowSendingWithoutReply, + checklistTaskId = checklistTaskId, + pollOptionId = pollOptionId + ), + replyMarkup = replyMarkup +) + +public suspend inline fun TelegramBot.reply( + replyInChatId: IdChatIdentifier, + ephemeralMessageParameters: EphemeralMessageParameters, + replyToEphemeralMessageId: EphemeralMessageId, + richMessage: InputRichMessage, + replyInThreadId: MessageThreadId? = replyInChatId.threadId, + replyInDirectMessageThreadId: DirectMessageThreadId? = replyInChatId.directMessageThreadId, + replyInBusinessConnectionId: BusinessConnectionId? = replyInChatId.businessConnectionId, + disableNotification: Boolean = false, + protectContent: Boolean = false, + allowPaidBroadcast: Boolean = false, + effectId: EffectId? = null, + suggestedPostParameters: SuggestedPostParameters? = null, + allowSendingWithoutReply: Boolean? = null, + checklistTaskId: ChecklistTaskId? = null, + pollOptionId: PollOptionPersistentId? = null, + replyMarkup: KeyboardMarkup? = null +): ChatContentMessage = replyRichMessage( + replyInChatId = replyInChatId, + ephemeralMessageParameters = ephemeralMessageParameters, + replyToEphemeralMessageId = replyToEphemeralMessageId, + richMessage = richMessage, + replyInThreadId = replyInThreadId, + replyInDirectMessageThreadId = replyInDirectMessageThreadId, + replyInBusinessConnectionId = replyInBusinessConnectionId, + disableNotification = disableNotification, + protectContent = protectContent, + allowPaidBroadcast = allowPaidBroadcast, + effectId = effectId, + suggestedPostParameters = suggestedPostParameters, + allowSendingWithoutReply = allowSendingWithoutReply, + checklistTaskId = checklistTaskId, + pollOptionId = pollOptionId, + replyMarkup = replyMarkup +) + public suspend inline fun TelegramBot.reply( replyInChatId: IdChatIdentifier, ephemeralMessageParameters: EphemeralMessageParameters, diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/ReplyToEphemeral.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/ReplyToEphemeral.kt index 9dce0d0d08..11d3142d8b 100644 --- a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/ReplyToEphemeral.kt +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/ReplyToEphemeral.kt @@ -8,22 +8,167 @@ import dev.inmo.tgbotapi.requests.abstracts.InputFile import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.message.ParseMode +import dev.inmo.tgbotapi.types.message.SuggestedPostParameters import dev.inmo.tgbotapi.types.message.abstracts.ChatContentMessage import dev.inmo.tgbotapi.types.message.content.* +import dev.inmo.tgbotapi.types.business_connection.BusinessConnectionId +import dev.inmo.tgbotapi.types.checklists.ChecklistTaskId +import dev.inmo.tgbotapi.types.polls.PollOptionPersistentId +import dev.inmo.tgbotapi.types.rich.InputRichMessage /** * Explicit helpers replying directly to an incoming ephemeral message identified by [chatId]/[ephemeralMessageId] * (as opposed to the `reply(to = someMessage, ...)` smart-branch overloads, which detect an ephemeral * [dev.inmo.tgbotapi.types.message.abstracts.PossiblyEphemeralMessage] target automatically). The outgoing message - * is itself sent as ephemeral, addressed to the same [ephemeralMessageParameters.receiverUserId] as the message being replied to. + * is itself sent as ephemeral according to [ephemeralMessageParameters] and replies to [ephemeralMessageId]. * - * Each helper has two forms: one taking explicit `ephemeralMessageParameters.receiverUserId`/`ephemeralMessageId`, and a convenience overload - * taking an [dev.inmo.tgbotapi.types.EphemeralChatId] which sources both from the identifier (throwing + * Each helper has two forms: one taking an explicit [EphemeralMessageParameters] object plus [EphemeralMessageId], and a convenience overload + * taking an [dev.inmo.tgbotapi.types.EphemeralChatId] which sources the parameter object plus message identifier (throwing * [IllegalArgumentException] if it does not carry an `ephemeralMessageId`). * * @see dev.inmo.tgbotapi.types.ephemeralReplyParametersOrNull */ +public suspend fun TelegramBot.replyToEphemeralRichMessage( + chatId: ChatIdentifier, + ephemeralMessageParameters: EphemeralMessageParameters, + ephemeralMessageId: EphemeralMessageId, + richMessage: InputRichMessage, + threadId: MessageThreadId? = chatId.threadId, + directMessageThreadId: DirectMessageThreadId? = chatId.directMessageThreadId, + businessConnectionId: BusinessConnectionId? = chatId.businessConnectionId, + disableNotification: Boolean = false, + protectContent: Boolean = false, + allowPaidBroadcast: Boolean = false, + effectId: EffectId? = null, + suggestedPostParameters: SuggestedPostParameters? = null, + allowSendingWithoutReply: Boolean? = null, + checklistTaskId: ChecklistTaskId? = null, + pollOptionId: PollOptionPersistentId? = null, + replyMarkup: KeyboardMarkup? = null +): ChatContentMessage = sendRichMessage( + chatId = chatId, + richMessage = richMessage, + threadId = threadId, + directMessageThreadId = directMessageThreadId, + businessConnectionId = businessConnectionId, + ephemeralMessageParameters = ephemeralMessageParameters, + disableNotification = disableNotification, + protectContent = protectContent, + allowPaidBroadcast = allowPaidBroadcast, + effectId = effectId, + suggestedPostParameters = suggestedPostParameters, + replyParameters = ReplyParameters( + ephemeralMessageId = ephemeralMessageId, + allowSendingWithoutReply = allowSendingWithoutReply, + checklistTaskId = checklistTaskId, + pollOptionId = pollOptionId + ), + replyMarkup = replyMarkup +) + +public suspend fun TelegramBot.replyToEphemeralRichMessage( + chatId: EphemeralChatId, + richMessage: InputRichMessage, + threadId: MessageThreadId? = chatId.threadId, + directMessageThreadId: DirectMessageThreadId? = chatId.directMessageThreadId, + businessConnectionId: BusinessConnectionId? = chatId.businessConnectionId, + disableNotification: Boolean = false, + protectContent: Boolean = false, + allowPaidBroadcast: Boolean = false, + effectId: EffectId? = null, + suggestedPostParameters: SuggestedPostParameters? = null, + allowSendingWithoutReply: Boolean? = null, + checklistTaskId: ChecklistTaskId? = null, + pollOptionId: PollOptionPersistentId? = null, + replyMarkup: KeyboardMarkup? = null +): ChatContentMessage = replyToEphemeralRichMessage( + chatId = chatId, + ephemeralMessageParameters = EphemeralMessageParameters(chatId.receiverUser), + ephemeralMessageId = requireNotNull(chatId.ephemeralMessageId) { "chatId ($chatId) does not carry an ephemeralMessageId" }, + richMessage = richMessage, + threadId = threadId, + directMessageThreadId = directMessageThreadId, + businessConnectionId = businessConnectionId, + disableNotification = disableNotification, + protectContent = protectContent, + allowPaidBroadcast = allowPaidBroadcast, + effectId = effectId, + suggestedPostParameters = suggestedPostParameters, + allowSendingWithoutReply = allowSendingWithoutReply, + checklistTaskId = checklistTaskId, + pollOptionId = pollOptionId, + replyMarkup = replyMarkup +) + +public suspend fun TelegramBot.replyToEphemeral( + chatId: ChatIdentifier, + ephemeralMessageParameters: EphemeralMessageParameters, + ephemeralMessageId: EphemeralMessageId, + richMessage: InputRichMessage, + threadId: MessageThreadId? = chatId.threadId, + directMessageThreadId: DirectMessageThreadId? = chatId.directMessageThreadId, + businessConnectionId: BusinessConnectionId? = chatId.businessConnectionId, + disableNotification: Boolean = false, + protectContent: Boolean = false, + allowPaidBroadcast: Boolean = false, + effectId: EffectId? = null, + suggestedPostParameters: SuggestedPostParameters? = null, + allowSendingWithoutReply: Boolean? = null, + checklistTaskId: ChecklistTaskId? = null, + pollOptionId: PollOptionPersistentId? = null, + replyMarkup: KeyboardMarkup? = null +): ChatContentMessage = replyToEphemeralRichMessage( + chatId = chatId, + ephemeralMessageParameters = ephemeralMessageParameters, + ephemeralMessageId = ephemeralMessageId, + richMessage = richMessage, + threadId = threadId, + directMessageThreadId = directMessageThreadId, + businessConnectionId = businessConnectionId, + disableNotification = disableNotification, + protectContent = protectContent, + allowPaidBroadcast = allowPaidBroadcast, + effectId = effectId, + suggestedPostParameters = suggestedPostParameters, + allowSendingWithoutReply = allowSendingWithoutReply, + checklistTaskId = checklistTaskId, + pollOptionId = pollOptionId, + replyMarkup = replyMarkup +) + +public suspend fun TelegramBot.replyToEphemeral( + chatId: EphemeralChatId, + richMessage: InputRichMessage, + threadId: MessageThreadId? = chatId.threadId, + directMessageThreadId: DirectMessageThreadId? = chatId.directMessageThreadId, + businessConnectionId: BusinessConnectionId? = chatId.businessConnectionId, + disableNotification: Boolean = false, + protectContent: Boolean = false, + allowPaidBroadcast: Boolean = false, + effectId: EffectId? = null, + suggestedPostParameters: SuggestedPostParameters? = null, + allowSendingWithoutReply: Boolean? = null, + checklistTaskId: ChecklistTaskId? = null, + pollOptionId: PollOptionPersistentId? = null, + replyMarkup: KeyboardMarkup? = null +): ChatContentMessage = replyToEphemeralRichMessage( + chatId = chatId, + richMessage = richMessage, + threadId = threadId, + directMessageThreadId = directMessageThreadId, + businessConnectionId = businessConnectionId, + disableNotification = disableNotification, + protectContent = protectContent, + allowPaidBroadcast = allowPaidBroadcast, + effectId = effectId, + suggestedPostParameters = suggestedPostParameters, + allowSendingWithoutReply = allowSendingWithoutReply, + checklistTaskId = checklistTaskId, + pollOptionId = pollOptionId, + replyMarkup = replyMarkup +) + /** * @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or * [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard] as a builders for that param @@ -46,7 +191,7 @@ public suspend fun TelegramBot.replyToEphemeral( ) /** - * Convenience overload sourcing `ephemeralMessageParameters.receiverUserId`/`ephemeralMessageId` from [chatId]. Throws + * Convenience overload sourcing an [EphemeralMessageParameters] object plus [EphemeralMessageId] from [chatId]. Throws * [IllegalArgumentException] if [chatId] does not carry an ephemeralMessageId * * @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or @@ -88,7 +233,7 @@ public suspend fun TelegramBot.replyToEphemeralWithPhoto( ) /** - * Convenience overload sourcing `ephemeralMessageParameters.receiverUserId`/`ephemeralMessageId` from [chatId]. Throws + * Convenience overload sourcing an [EphemeralMessageParameters] object plus [EphemeralMessageId] from [chatId]. Throws * [IllegalArgumentException] if [chatId] does not carry an ephemeralMessageId */ public suspend fun TelegramBot.replyToEphemeralWithPhoto( @@ -131,7 +276,7 @@ public suspend fun TelegramBot.replyToEphemeralWithLivePhoto( ) /** - * Convenience overload sourcing `ephemeralMessageParameters.receiverUserId`/`ephemeralMessageId` from [chatId]. Throws + * Convenience overload sourcing an [EphemeralMessageParameters] object plus [EphemeralMessageId] from [chatId]. Throws * [IllegalArgumentException] if [chatId] does not carry an ephemeralMessageId */ public suspend fun TelegramBot.replyToEphemeralWithLivePhoto( @@ -174,7 +319,7 @@ public suspend fun TelegramBot.replyToEphemeralWithAudio( ) /** - * Convenience overload sourcing `ephemeralMessageParameters.receiverUserId`/`ephemeralMessageId` from [chatId]. Throws + * Convenience overload sourcing an [EphemeralMessageParameters] object plus [EphemeralMessageId] from [chatId]. Throws * [IllegalArgumentException] if [chatId] does not carry an ephemeralMessageId */ public suspend fun TelegramBot.replyToEphemeralWithAudio( @@ -215,7 +360,7 @@ public suspend fun TelegramBot.replyToEphemeralWithDocument( ) /** - * Convenience overload sourcing `ephemeralMessageParameters.receiverUserId`/`ephemeralMessageId` from [chatId]. Throws + * Convenience overload sourcing an [EphemeralMessageParameters] object plus [EphemeralMessageId] from [chatId]. Throws * [IllegalArgumentException] if [chatId] does not carry an ephemeralMessageId */ public suspend fun TelegramBot.replyToEphemeralWithDocument( @@ -256,7 +401,7 @@ public suspend fun TelegramBot.replyToEphemeralWithVideo( ) /** - * Convenience overload sourcing `ephemeralMessageParameters.receiverUserId`/`ephemeralMessageId` from [chatId]. Throws + * Convenience overload sourcing an [EphemeralMessageParameters] object plus [EphemeralMessageId] from [chatId]. Throws * [IllegalArgumentException] if [chatId] does not carry an ephemeralMessageId */ public suspend fun TelegramBot.replyToEphemeralWithVideo( @@ -297,7 +442,7 @@ public suspend fun TelegramBot.replyToEphemeralWithAnimation( ) /** - * Convenience overload sourcing `ephemeralMessageParameters.receiverUserId`/`ephemeralMessageId` from [chatId]. Throws + * Convenience overload sourcing an [EphemeralMessageParameters] object plus [EphemeralMessageId] from [chatId]. Throws * [IllegalArgumentException] if [chatId] does not carry an ephemeralMessageId */ public suspend fun TelegramBot.replyToEphemeralWithAnimation( @@ -338,7 +483,7 @@ public suspend fun TelegramBot.replyToEphemeralWithVoice( ) /** - * Convenience overload sourcing `ephemeralMessageParameters.receiverUserId`/`ephemeralMessageId` from [chatId]. Throws + * Convenience overload sourcing an [EphemeralMessageParameters] object plus [EphemeralMessageId] from [chatId]. Throws * [IllegalArgumentException] if [chatId] does not carry an ephemeralMessageId */ public suspend fun TelegramBot.replyToEphemeralWithVoice( @@ -375,7 +520,7 @@ public suspend fun TelegramBot.replyToEphemeralWithVideoNote( ) /** - * Convenience overload sourcing `ephemeralMessageParameters.receiverUserId`/`ephemeralMessageId` from [chatId]. Throws + * Convenience overload sourcing an [EphemeralMessageParameters] object plus [EphemeralMessageId] from [chatId]. Throws * [IllegalArgumentException] if [chatId] does not carry an ephemeralMessageId */ public suspend fun TelegramBot.replyToEphemeralWithVideoNote( @@ -408,7 +553,7 @@ public suspend fun TelegramBot.replyToEphemeralWithSticker( ) /** - * Convenience overload sourcing `ephemeralMessageParameters.receiverUserId`/`ephemeralMessageId` from [chatId]. Throws + * Convenience overload sourcing an [EphemeralMessageParameters] object plus [EphemeralMessageId] from [chatId]. Throws * [IllegalArgumentException] if [chatId] does not carry an ephemeralMessageId */ public suspend fun TelegramBot.replyToEphemeralWithSticker( @@ -447,7 +592,7 @@ public suspend fun TelegramBot.replyToEphemeralWithLocation( /** * Sends a static location (`live_period` is not supported for ephemeral messages, see [SendLocation.Live]). - * Convenience overload sourcing `ephemeralMessageParameters.receiverUserId`/`ephemeralMessageId` from [chatId]. Throws + * Convenience overload sourcing an [EphemeralMessageParameters] object plus [EphemeralMessageId] from [chatId]. Throws * [IllegalArgumentException] if [chatId] does not carry an ephemeralMessageId */ public suspend fun TelegramBot.replyToEphemeralWithLocation( @@ -488,7 +633,7 @@ public suspend fun TelegramBot.replyToEphemeralWithVenue( ) /** - * Convenience overload sourcing `ephemeralMessageParameters.receiverUserId`/`ephemeralMessageId` from [chatId]. Throws + * Convenience overload sourcing an [EphemeralMessageParameters] object plus [EphemeralMessageId] from [chatId]. Throws * [IllegalArgumentException] if [chatId] does not carry an ephemeralMessageId */ public suspend fun TelegramBot.replyToEphemeralWithVenue( @@ -531,7 +676,7 @@ public suspend fun TelegramBot.replyToEphemeralWithContact( ) /** - * Convenience overload sourcing `ephemeralMessageParameters.receiverUserId`/`ephemeralMessageId` from [chatId]. Throws + * Convenience overload sourcing an [EphemeralMessageParameters] object plus [EphemeralMessageId] from [chatId]. Throws * [IllegalArgumentException] if [chatId] does not carry an ephemeralMessageId */ public suspend fun TelegramBot.replyToEphemeralWithContact( diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/media/EditChatMessageMedia.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/media/EditChatMessageMedia.kt index d55f073b5f..55f54d31b9 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/media/EditChatMessageMedia.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/media/EditChatMessageMedia.kt @@ -6,7 +6,10 @@ import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest import dev.inmo.tgbotapi.requests.edit.abstracts.* import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.business_connection.BusinessConnectionId +import dev.inmo.tgbotapi.types.media.CoveredTelegramMedia +import dev.inmo.tgbotapi.types.media.PhotoedTelegramMedia import dev.inmo.tgbotapi.types.media.TelegramFreeMedia +import dev.inmo.tgbotapi.types.media.ThumbedTelegramMedia import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass @@ -34,9 +37,12 @@ data class EditChatMessageMedia( override val data: SimpleRequest> get() = this override val mediaMap: Map by lazy { - (media.file as? MultipartFile) ?.let { - mapOf(it.fileId to it) - } ?: emptyMap() + listOfNotNull( + media.file as? MultipartFile, + (media as? PhotoedTelegramMedia) ?.photo as? MultipartFile, + (media as? ThumbedTelegramMedia) ?.thumb as? MultipartFile, + (media as? CoveredTelegramMedia) ?.cover as? MultipartFile + ).associateBy { it.fileId } } // init { diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/media/EditEphemeralMessageMedia.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/media/EditEphemeralMessageMedia.kt index 89e027fedd..314ffdde18 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/media/EditEphemeralMessageMedia.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/media/EditEphemeralMessageMedia.kt @@ -6,6 +6,7 @@ import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest import dev.inmo.tgbotapi.requests.edit.abstracts.* import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.media.CoveredTelegramMedia +import dev.inmo.tgbotapi.types.media.PhotoedTelegramMedia import dev.inmo.tgbotapi.types.media.TelegramFreeMedia import dev.inmo.tgbotapi.types.media.ThumbedTelegramMedia import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup @@ -48,6 +49,7 @@ data class EditEphemeralMessageMedia( override val mediaMap: Map by lazy { listOfNotNull( media.file as? MultipartFile, + (media as? PhotoedTelegramMedia) ?.photo as? MultipartFile, (media as? ThumbedTelegramMedia) ?.thumb as? MultipartFile, (media as? CoveredTelegramMedia) ?.cover as? MultipartFile ).associateBy { it.fileId } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendMediaGroup.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendMediaGroup.kt index e825d5629f..dcafc821f2 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendMediaGroup.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendMediaGroup.kt @@ -53,6 +53,11 @@ fun SendMediaGroup( val files: List = media.flatMap { listOfNotNull( it.file as? MultipartFile, + if (it is PhotoedTelegramMedia) { + it.photo as? MultipartFile + } else { + null + }, if (it is ThumbedTelegramMedia) { it.thumb as? MultipartFile } else { diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendPaidMedia.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendPaidMedia.kt index 493cb81b46..80fa5c7321 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendPaidMedia.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendPaidMedia.kt @@ -15,6 +15,7 @@ import dev.inmo.tgbotapi.types.message.ParseMode import dev.inmo.tgbotapi.types.message.parseModeField import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.media.CoveredTelegramMedia +import dev.inmo.tgbotapi.types.media.PhotoedTelegramMedia import dev.inmo.tgbotapi.types.media.ThumbedTelegramMedia import dev.inmo.tgbotapi.types.message.* import dev.inmo.tgbotapi.types.message.RawMessageEntity @@ -67,6 +68,11 @@ fun SendPaidMedia( val files: List = media.flatMap { listOfNotNull( it.file as? MultipartFile, + if (it is PhotoedTelegramMedia) { + it.photo as? MultipartFile + } else { + null + }, if (it is ThumbedTelegramMedia) { it.thumb as? MultipartFile } else { @@ -130,6 +136,11 @@ fun SendPaidMedia( val files: List = media.flatMap { listOfNotNull( it.file as? MultipartFile, + if (it is PhotoedTelegramMedia) { + it.photo as? MultipartFile + } else { + null + }, if (it is ThumbedTelegramMedia) { it.thumb as? MultipartFile } else { diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/media/PhotoedTelegramMedia.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/media/PhotoedTelegramMedia.kt new file mode 100644 index 0000000000..401a319c1d --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/media/PhotoedTelegramMedia.kt @@ -0,0 +1,7 @@ +package dev.inmo.tgbotapi.types.media + +import dev.inmo.tgbotapi.requests.abstracts.InputFile + +sealed interface PhotoedTelegramMedia : TelegramMedia { + val photo: InputFile +} diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/media/TelegramMediaLivePhoto.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/media/TelegramMediaLivePhoto.kt index fcdd6ab98a..13f0885a12 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/media/TelegramMediaLivePhoto.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/media/TelegramMediaLivePhoto.kt @@ -50,7 +50,7 @@ fun TelegramMediaLivePhoto( data class TelegramMediaLivePhoto internal constructor( override val file: InputFile, @SerialName(photoField) - val photo: InputFile, + override val photo: InputFile, @SerialName(captionField) override val text: String? = null, @SerialName(parseModeField) @@ -64,7 +64,8 @@ data class TelegramMediaLivePhoto internal constructor( ) : TelegramFreeMedia, VisualMediaGroupMemberTelegramMedia, InputPollMedia, - InputPollOptionMedia { + InputPollOptionMedia, + PhotoedTelegramMedia { @EncodeDefault override val type: String = TYPE override val textSources: TextSourcesList? by lazy { diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/media/TelegramPaidMediaLivePhoto.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/media/TelegramPaidMediaLivePhoto.kt index d6d6679ad9..04505ebc4b 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/media/TelegramPaidMediaLivePhoto.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/media/TelegramPaidMediaLivePhoto.kt @@ -12,8 +12,8 @@ import kotlinx.serialization.* data class TelegramPaidMediaLivePhoto( override val file: InputFile, @SerialName(photoField) - val photo: InputFile, -) : VisualTelegramPaidMedia { + override val photo: InputFile, +) : VisualTelegramPaidMedia, PhotoedTelegramMedia { override val type: String = TYPE @SerialName(mediaField) diff --git a/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/EphemeralMessageParametersTest.kt b/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/EphemeralMessageParametersTest.kt index 4d91e1dd65..e80625f819 100644 --- a/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/EphemeralMessageParametersTest.kt +++ b/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/EphemeralMessageParametersTest.kt @@ -3,22 +3,30 @@ package dev.inmo.tgbotapi.types import dev.inmo.tgbotapi.requests.send.SendTextMessage import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile import dev.inmo.tgbotapi.requests.abstracts.json +import dev.inmo.tgbotapi.requests.abstracts.MultipartRequest import dev.inmo.tgbotapi.requests.chat.members.PromoteChatMember import dev.inmo.tgbotapi.requests.edit.caption.EditEphemeralMessageCaption +import dev.inmo.tgbotapi.requests.edit.media.EditChatMessageMedia import dev.inmo.tgbotapi.requests.edit.media.EditEphemeralMessageMedia import dev.inmo.tgbotapi.requests.edit.text.EditEphemeralMessageRichText import dev.inmo.tgbotapi.requests.edit.text.EditEphemeralMessageText +import dev.inmo.tgbotapi.requests.send.media.SendPaidMedia +import dev.inmo.tgbotapi.requests.send.media.SendVisualMediaGroup import dev.inmo.tgbotapi.types.chat.member.ChatCommonAdministratorRights import dev.inmo.tgbotapi.types.media.TelegramMediaPhoto +import dev.inmo.tgbotapi.types.media.TelegramMediaLivePhoto +import dev.inmo.tgbotapi.types.media.TelegramPaidMediaLivePhoto import dev.inmo.tgbotapi.types.media.TelegramMediaVideo import dev.inmo.tgbotapi.types.rich.InputRichMessageHTML import dev.inmo.tgbotapi.types.rich.InputRichMessageMedia +import dev.inmo.tgbotapi.utils.RiskFeature import kotlinx.serialization.json.Json import kotlinx.serialization.json.jsonObject import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertFalse +import kotlin.test.assertIs class EphemeralMessageParametersTest { private val json = Json { encodeDefaults = true } @@ -62,6 +70,51 @@ class EphemeralMessageParametersTest { assertEquals(setOf(media.file.fileId), request.mediaMap.keys) } + @Test + fun `EditEphemeralMessageMedia includes live photo and static photo multipart files`() { + val media = TelegramMediaLivePhoto( + file = "live photo".encodeToByteArray().asMultipartFile("live-photo.mov"), + photo = "static photo".encodeToByteArray().asMultipartFile("photo.jpg") + ) + val request = EditEphemeralMessageMedia(ChatId(RawChatId(1L)), ChatId(RawChatId(2L)), EphemeralMessageId(3L), media) + + assertEquals(setOf(media.file.fileId, media.photo.fileId), request.mediaMap.keys) + } + + @Test + fun `EditChatMessageMedia includes live photo and static photo multipart files`() { + val media = TelegramMediaLivePhoto( + file = "live photo".encodeToByteArray().asMultipartFile("live-photo.mov"), + photo = "static photo".encodeToByteArray().asMultipartFile("photo.jpg") + ) + val request = EditChatMessageMedia(ChatId(RawChatId(1L)), MessageId(3L), media) + + assertEquals(setOf(media.file.fileId, media.photo.fileId), request.mediaMap.keys) + } + + @OptIn(RiskFeature::class) + @Test + fun `SendVisualMediaGroup includes live photo and static photo multipart files`() { + val media = TelegramMediaLivePhoto( + file = "live photo".encodeToByteArray().asMultipartFile("live-photo.mov"), + photo = "static photo".encodeToByteArray().asMultipartFile("photo.jpg") + ) + val request = SendVisualMediaGroup(ChatId(RawChatId(1L)), listOf(media, media)) + + assertEquals(setOf(media.file.fileId, media.photo.fileId), assertIs>(request).mediaMap.keys) + } + + @Test + fun `SendPaidMedia includes live photo and static photo multipart files`() { + val media = TelegramPaidMediaLivePhoto( + file = "live photo".encodeToByteArray().asMultipartFile("live-photo.mov"), + photo = "static photo".encodeToByteArray().asMultipartFile("photo.jpg") + ) + val request = SendPaidMedia(ChatId(RawChatId(1L)), 1, listOf(media)) + + assertEquals(setOf(media.file.fileId, media.photo.fileId), assertIs>(request).mediaMap.keys) + } + @Test fun `EditEphemeralMessageMedia includes multipart thumbnail and cover`() { val video = TelegramMediaVideo(