From 48b0e068d5c43b70f2413fd5f5670eea75f1ec74 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 8 Oct 2026 19:30:19 +0600 Subject: [PATCH] fix(examples): add bot selection and ephemeral photo captions Limit channel-rights selection to private chats, preserve full chat identifiers, offer bot selection, and use the replied-to sender ID. Supply a caption when replacing ephemeral photo media so the next caption edit starts from a captioned message. --- .../src/main/kotlin/EphemeralMessagesBot.kt | 5 +++- .../src/main/kotlin/RightsChanger.kt | 28 ++++++++++++------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/EphemeralMessagesBot/src/main/kotlin/EphemeralMessagesBot.kt b/EphemeralMessagesBot/src/main/kotlin/EphemeralMessagesBot.kt index 79bddda..dad1c59 100644 --- a/EphemeralMessagesBot/src/main/kotlin/EphemeralMessagesBot.kt +++ b/EphemeralMessagesBot/src/main/kotlin/EphemeralMessagesBot.kt @@ -152,7 +152,10 @@ suspend fun main(vararg args: String) { photoMessage.chat.id, receiverUserId, ephemeralMessageId, - TelegramMediaPhoto(photoBytes.asMultipartFile("ephemeral-photo.jpg")), + TelegramMediaPhoto( + photoBytes.asMultipartFile("ephemeral-photo.jpg"), + text = "sample" + ), ) editEphemeralMessageCaption( photoMessage.chat.id, diff --git a/RightsChangerBot/src/main/kotlin/RightsChanger.kt b/RightsChangerBot/src/main/kotlin/RightsChanger.kt index 6cfb6ff..9a3cb7b 100644 --- a/RightsChangerBot/src/main/kotlin/RightsChanger.kt +++ b/RightsChangerBot/src/main/kotlin/RightsChanger.kt @@ -3,6 +3,7 @@ import dev.inmo.kslog.common.LogLevel import dev.inmo.kslog.common.defaultMessageFormatter import dev.inmo.kslog.common.setDefaultKSLog import dev.inmo.micro_utils.coroutines.firstOf +import dev.inmo.micro_utils.coroutines.runCatchingLogging import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.micro_utils.fsm.common.State import dev.inmo.tgbotapi.bot.ktor.telegramBot @@ -22,6 +23,7 @@ import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitUserShare import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMessageDataCallbackQuery import dev.inmo.tgbotapi.extensions.utils.* +import dev.inmo.tgbotapi.extensions.utils.extensions.raw.from import dev.inmo.tgbotapi.extensions.utils.extensions.sameChat import dev.inmo.tgbotapi.extensions.utils.types.buttons.* import dev.inmo.tgbotapi.types.* @@ -32,30 +34,30 @@ import dev.inmo.tgbotapi.types.chat.PublicChat import dev.inmo.tgbotapi.types.chat.member.AdministratorChatMember import dev.inmo.tgbotapi.types.chat.member.ChatCommonAdministratorRights import dev.inmo.tgbotapi.types.commands.BotCommandScope -import dev.inmo.tgbotapi.types.message.abstracts.AccessibleMessage import dev.inmo.tgbotapi.types.message.abstracts.ChatMessage import dev.inmo.tgbotapi.types.request.RequestId import dev.inmo.tgbotapi.utils.* import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.merge /** States used by the private-chat flow that selects a channel and one of its users. */ sealed interface UserRetrievingStep : State { /** Waits for the user to share a channel in the private chat identified by [context]. */ data class RetrievingChannelChatState( - override val context: ChatId + override val context: IdChatIdentifier ) : UserRetrievingStep /** Waits for a user selection after [channelId] has been shared. */ data class RetrievingUserIdChatState( - override val context: ChatId, + override val context: IdChatIdentifier, val channelId: ChatId ) : UserRetrievingStep /** Carries the selected [channelId] and [userId] to the administrator-rights keyboard step. */ data class RetrievingChatInfoDoneState( - override val context: ChatId, + override val context: IdChatIdentifier, val channelId: ChatId, val userId: UserId ) : UserRetrievingStep @@ -247,13 +249,14 @@ suspend fun main(args: Array) { } ) { val replyMessage = it.replyTo - val userInReply = replyMessage?.fromUserMessageOrNull()?.user?.id ?: return@onCommand + val userInReply = replyMessage ?.from ?.id ?: return@onCommand if (replyMessage is ChatMessage) { + val keyboard = buildGranularKeyboard(it.chat.id.toChatId(), userInReply) reply( replyMessage, "Manage keyboard:", - replyMarkup = buildGranularKeyboard(it.chat.id.toChatId(), userInReply) ?: return@onCommand + replyMarkup = keyboard ?: return@onCommand ) } else { reply(it) { @@ -485,7 +488,8 @@ suspend fun main(args: Array) { } } strictlyOn { state -> - val requestId = RequestId.random() + val userRequestId = RequestId.random() + val botRequestId = RequestId.random() send( state.context, replyMarkup = replyKeyboard( @@ -495,7 +499,11 @@ suspend fun main(args: Array) { row { requestUserButton( "Choose user", - requestId = requestId + requestId = userRequestId + ) + requestBotButton( + "Choose bot", + requestId = botRequestId ) } } @@ -543,8 +551,8 @@ suspend fun main(args: Array) { null } - onCommand("rights_in_channel") { - startChain(UserRetrievingStep.RetrievingChannelChatState(it.chat.id.toChatId())) + onCommand("rights_in_channel", initialFilter = { it.chat.privateChatOrNull() != null }) { + startChain(UserRetrievingStep.RetrievingChannelChatState(it.chat.id)) } setMyCommands(