diff --git a/CommunitiesBot/README.md b/CommunitiesBot/README.md new file mode 100644 index 0000000..dc72d56 --- /dev/null +++ b/CommunitiesBot/README.md @@ -0,0 +1,12 @@ +# CommunitiesBot + +Demonstrates Communities support introduced in Telegram Bot API 10.2. + +Add the bot to a chat that belongs to a community. It reports when the chat is added to or removed from a +community, and `/community` prints the chat's current community (read from `getChat().community`). + +## Launch + +```bash +../gradlew :CommunitiesBot:run --args="BOT_TOKEN" +``` diff --git a/CommunitiesBot/build.gradle b/CommunitiesBot/build.gradle new file mode 100644 index 0000000..92b3341 --- /dev/null +++ b/CommunitiesBot/build.gradle @@ -0,0 +1,21 @@ +buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +apply plugin: 'kotlin' +apply plugin: 'application' + +mainClassName="CommunitiesBotKt" + + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + + implementation "dev.inmo:tgbotapi:$telegram_bot_api_version" +} diff --git a/CommunitiesBot/src/main/kotlin/CommunitiesBot.kt b/CommunitiesBot/src/main/kotlin/CommunitiesBot.kt new file mode 100644 index 0000000..722aa80 --- /dev/null +++ b/CommunitiesBot/src/main/kotlin/CommunitiesBot.kt @@ -0,0 +1,98 @@ +import dev.inmo.kslog.common.KSLog +import dev.inmo.kslog.common.LogLevel +import dev.inmo.kslog.common.defaultMessageFormatter +import dev.inmo.kslog.common.setDefaultKSLog +import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions +import dev.inmo.tgbotapi.extensions.api.bot.getMe +import dev.inmo.tgbotapi.extensions.api.chat.get.getChat +import dev.inmo.tgbotapi.extensions.api.send.reply +import dev.inmo.tgbotapi.extensions.api.send.send +import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitCommunityChatAdded +import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommunityChatAdded +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommunityChatRemoved +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.first + +/** + * This bot demonstrates Communities support introduced in Telegram Bot API 10.2. + * + * A community groups several chats together. When a chat is added to (or removed from) a community, the bot + * receives a service event in that chat. + * + * Key concepts demonstrated: + * - [onCommunityChatAdded] — trigger for the `community_chat_added` service event. The handler receives a + * [dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage] carrying a + * [dev.inmo.tgbotapi.types.communities.CommunityChatAdded] whose `community` is the + * [dev.inmo.tgbotapi.types.communities.Community] (`id`: [dev.inmo.tgbotapi.types.communities.CommunityId], + * `name`) the chat was added to + * - [onCommunityChatRemoved] — trigger for the fieldless `community_chat_removed` service event + * - [waitCommunityChatAdded] — expectation returning a flow of [dev.inmo.tgbotapi.types.communities.CommunityChatAdded] + * - [dev.inmo.tgbotapi.types.chat.ExtendedChat.community] — the community a chat belongs to + * (`ChatFullInfo.community`), available directly from [getChat] without any cast + */ +suspend fun main(vararg args: String) { + val botToken = args.first() + val isDebug = args.any { it == "debug" } + val isTestServer = args.any { it == "testServer" } + + if (isDebug) { + setDefaultKSLog( + KSLog { level: LogLevel, tag: String?, message: Any, throwable: Throwable? -> + println(defaultMessageFormatter(level, tag, message, throwable)) + } + ) + } + + telegramBotWithBehaviourAndLongPolling( + botToken, + CoroutineScope(Dispatchers.IO), + testServer = isTestServer, + ) { + val me = getMe() + println("Bot info: $me") + + // community_chat_added: the chat was added to a community + onCommunityChatAdded { message -> + val community = message.chatEvent.community + println("Chat ${message.chat.id} was added to community '${community.name}' (id=${community.id.long})") + send(message.chat.id, "This chat has joined the community: ${community.name}") + + // community is exposed on ExtendedChat itself (ChatFullInfo.community) — no cast needed + val extended = getChat(message.chat.id) + println("getChat().community = ${extended.community?.name} / ${extended.community?.id?.long}") + } + + // community_chat_removed: a fieldless event — the chat left its community + onCommunityChatRemoved { message -> + println("Chat ${message.chat.id} was removed from its community") + send(message.chat.id, "This chat has left its community") + } + + // Inspect the current chat's community on demand + onCommand("community") { + val community = getChat(it.chat.id).community + reply( + it, + if (community != null) { + "Community: ${community.name} (id=${community.id.long})" + } else { + "This chat is not part of any community" + } + ) + } + + // waitCommunityChatAdded expectation: suspend until this chat is added to a community + onCommand("wait_community") { + reply(it, "Waiting for this chat to be added to a community...") + val event = waitCommunityChatAdded().first() + reply(it, "Chat added to community: ${event.community.name} (id=${event.community.id.long})") + } + + allUpdatesFlow.subscribeSafelyWithoutExceptions(this) { + println(it) + } + }.second.join() +} diff --git a/settings.gradle b/settings.gradle index 2ed261a..9fa26c5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -83,3 +83,5 @@ include ":RichMessagesBot" include ":JoinRequestQueriesBot" include ":EphemeralMessagesBot" + +include ":CommunitiesBot"