diff --git a/CustomBot/src/main/kotlin/CustomBot.kt b/CustomBot/src/main/kotlin/CustomBot.kt index d75ace7..bf493d3 100644 --- a/CustomBot/src/main/kotlin/CustomBot.kt +++ b/CustomBot/src/main/kotlin/CustomBot.kt @@ -6,12 +6,22 @@ import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.tgbotapi.extensions.api.bot.getMe import dev.inmo.tgbotapi.extensions.api.bot.getMyStarBalance import dev.inmo.tgbotapi.extensions.api.chat.get.getChat +import dev.inmo.tgbotapi.extensions.api.get.getUserProfileAudios +import dev.inmo.tgbotapi.extensions.api.send.media.sendPaidMedia import dev.inmo.tgbotapi.extensions.api.send.reply +import dev.inmo.tgbotapi.extensions.api.send.replyWithAudio +import dev.inmo.tgbotapi.extensions.api.send.replyWithPlaylist import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextData import dev.inmo.tgbotapi.extensions.behaviour_builder.buildSubcontextInitialAction import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChannelDirectMessagesConfigurationChanged +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatOwnerChanged +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatOwnerLeft import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPhoto +import dev.inmo.tgbotapi.types.media.AudioMediaGroupMemberTelegramMedia +import dev.inmo.tgbotapi.types.media.toTelegramMediaAudio +import dev.inmo.tgbotapi.types.media.toTelegramPaidMediaPhoto import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage import dev.inmo.tgbotapi.types.update.abstracts.Update import kotlinx.coroutines.CoroutineScope @@ -70,6 +80,32 @@ suspend fun main(vararg args: String) { println(data.update) println(data.commonMessage) println(getChat(it.chat)) + var currentOffset = 0 + val pageSize = 2 + do { + val userAudios = getUserProfileAudios(userId = it.chat.id, offset = currentOffset, limit = pageSize) + currentOffset += pageSize + println(userAudios) + when (userAudios.audios.size) { + 1 -> { + replyWithAudio( + it, + userAudios.audios.first().fileId + ) + } + 0 -> { + // do nothing + } + else -> { + replyWithPlaylist( + it, + userAudios.audios.map { + it.toTelegramMediaAudio() + } + ) + } + } + } while (currentOffset < userAudios.totalCount && userAudios.audios.isNotEmpty()) } onCommand( diff --git a/DraftsBot/README.md b/DraftsBot/README.md new file mode 100644 index 0000000..c49f1d8 --- /dev/null +++ b/DraftsBot/README.md @@ -0,0 +1,9 @@ +# Drafts bot + +The main purpose of this bot is just to answer "Oh, hi, " and add user mention here + +## Launch + +```bash +../gradlew run --args="BOT_TOKEN" +``` diff --git a/DraftsBot/build.gradle b/DraftsBot/build.gradle new file mode 100644 index 0000000..2006fb3 --- /dev/null +++ b/DraftsBot/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="TopicsHandlingKt" + + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + + implementation "dev.inmo:tgbotapi:$telegram_bot_api_version" +} diff --git a/DraftsBot/src/main/kotlin/DraftsBot.kt b/DraftsBot/src/main/kotlin/DraftsBot.kt new file mode 100644 index 0000000..8da1208 --- /dev/null +++ b/DraftsBot/src/main/kotlin/DraftsBot.kt @@ -0,0 +1,86 @@ +import com.benasher44.uuid.uuid4 +import dev.inmo.kslog.common.w +import dev.inmo.micro_utils.coroutines.runCatchingLogging +import dev.inmo.micro_utils.coroutines.runCatchingSafely +import dev.inmo.micro_utils.coroutines.subscribeLoggingDropExceptions +import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.extensions.api.bot.getMe +import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands +import dev.inmo.tgbotapi.extensions.api.chat.forum.* +import dev.inmo.tgbotapi.extensions.api.send.reply +import dev.inmo.tgbotapi.extensions.api.send.send +import dev.inmo.tgbotapi.extensions.api.send.sendMessageDraftFlow +import dev.inmo.tgbotapi.extensions.api.send.sendMessageDraftFlowWithTexts +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.onForumTopicClosed +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onForumTopicCreated +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onForumTopicEdited +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onForumTopicReopened +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onGeneralForumTopicHidden +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onGeneralForumTopicUnhidden +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPrivateForumTopicCreated +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPrivateForumTopicEdited +import dev.inmo.tgbotapi.extensions.utils.forumChatOrNull +import dev.inmo.tgbotapi.extensions.utils.forumContentMessageOrNull +import dev.inmo.tgbotapi.extensions.utils.privateChatOrNull +import dev.inmo.tgbotapi.extensions.utils.privateForumChatOrNull +import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.flushAccumulatedUpdates +import dev.inmo.tgbotapi.types.BotCommand +import dev.inmo.tgbotapi.types.ForumTopic +import dev.inmo.tgbotapi.types.chat.PrivateChat +import dev.inmo.tgbotapi.types.commands.BotCommandScope +import io.ktor.client.plugins.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.isActive + +const val testText = """ + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +""" + +suspend fun main(vararg args: String) { + telegramBotWithBehaviourAndLongPolling( + args.first(), + CoroutineScope(Dispatchers.Default), + defaultExceptionsHandler = { + it.printStackTrace() + }, + builder = { + client = client.config { + install(HttpTimeout) { + requestTimeoutMillis = 30000 + socketTimeoutMillis = 30000 + connectTimeoutMillis = 30000 + } + } + } + ) { + onCommand("test_draft_flow") { + sendMessageDraftFlowWithTexts( + it.chat.id, + flow { + val step = 50 + var currentLength = step + while (isActive && testText.length > currentLength) { + delay(500L) + emit(testText.take(currentLength)) + currentLength += step + } + }, + ) + send(it.chat, testText) + } + + setMyCommands( + BotCommand("test_draft_flow", "Start draft testing with flow"), + scope = BotCommandScope.AllGroupChats + ) + allUpdatesFlow.subscribeLoggingDropExceptions(this) { + println(it) + } + }.second.join() +} diff --git a/GetMeBot/src/main/kotlin/GetMeBot.kt b/GetMeBot/src/main/kotlin/GetMeBot.kt deleted file mode 100644 index eec6881..0000000 --- a/GetMeBot/src/main/kotlin/GetMeBot.kt +++ /dev/null @@ -1,29 +0,0 @@ -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.tgbotapi.bot.ktor.telegramBot -import dev.inmo.tgbotapi.extensions.api.bot.getMe -import dev.inmo.tgbotapi.extensions.api.chat.get.getChat - -/** - * This is one of the easiest bots - it will just print information about itself - */ -suspend fun main(vararg args: String) { - val botToken = args.first() - val isDebug = args.getOrNull(1) == "debug" - - if (isDebug) { - setDefaultKSLog( - KSLog { level: LogLevel, tag: String?, message: Any, throwable: Throwable? -> - println(defaultMessageFormatter(level, tag, message, throwable)) - } - ) - } - - val bot = telegramBot(botToken) - - val me = bot.getMe() - println(me) - println(bot.getChat(me)) -} diff --git a/GiftsBot/build.gradle b/GiftsBot/build.gradle new file mode 100644 index 0000000..ccb78a7 --- /dev/null +++ b/GiftsBot/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="GiftsBotKt" + + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + + implementation "dev.inmo:tgbotapi:$telegram_bot_api_version" +} diff --git a/GiftsBot/src/main/kotlin/GiftsBot.kt b/GiftsBot/src/main/kotlin/GiftsBot.kt new file mode 100644 index 0000000..efb3678 --- /dev/null +++ b/GiftsBot/src/main/kotlin/GiftsBot.kt @@ -0,0 +1,112 @@ +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.business.getBusinessAccountGiftsFlow +import dev.inmo.tgbotapi.extensions.api.gifts.getChatGiftsFlow +import dev.inmo.tgbotapi.extensions.api.gifts.getUserGiftsFlow +import dev.inmo.tgbotapi.extensions.api.send.reply +import dev.inmo.tgbotapi.extensions.api.send.withTypingAction +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.onGiveawayCompleted +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onGiveawayContent +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onGiveawayCreated +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onGiveawayWinners +import dev.inmo.tgbotapi.types.chat.BusinessChat +import dev.inmo.tgbotapi.types.chat.PrivateChat +import dev.inmo.tgbotapi.types.chat.PublicChat +import dev.inmo.tgbotapi.types.chat.UnknownChatType +import dev.inmo.tgbotapi.types.gifts.OwnedGift +import dev.inmo.tgbotapi.types.message.textsources.splitForText +import dev.inmo.tgbotapi.utils.bold +import dev.inmo.tgbotapi.utils.buildEntities +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers + +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, testServer = isTestServer) { + // start here!! + val me = getMe() + println(me) + + onCommand("start") { + val giftsFlow = when (val chat = it.chat) { + is BusinessChat -> { + getBusinessAccountGiftsFlow( + chat.id.businessConnectionId + ) + } + is PrivateChat -> { + getUserGiftsFlow(it.chat.id) + } + is UnknownChatType, + is PublicChat -> { + getChatGiftsFlow(it.chat.id) + } + } + + withTypingAction(it.chat) { + val texts = buildEntities { + giftsFlow.collect { ownedGifts -> + ownedGifts.gifts.forEach { + when (it) { + is OwnedGift.Regular.Common -> { + bold("Type") + ": Regular common\n" + bold("Id") + ": ${it.gift.id.string}\n" + bold("Text") + ": ${it.text ?: "(None)"}\n" + bold("Stars cost") + ": ${it.gift.starCount}\n" + } + is OwnedGift.Unique.Common -> { + bold("Type") + ": Unique common\n" + bold("Id") + ": ${it.gift.id ?.string ?: "(None)"}\n" + bold("Name") + ": ${it.gift.name.value}\n" + bold("Model") + ": ${it.gift.model.name}\n" + bold("Number") + ": ${it.gift.number}\n" + } + is OwnedGift.Regular.OwnedByBusinessAccount -> { + bold("Type") + ": Regular owned by business\n" + bold("Id") + ": ${it.gift.id.string}\n" + bold("Text") + ": ${it.text ?: "(None)"}\n" + bold("Stars cost") + ": ${it.gift.starCount}\n" + } + is OwnedGift.Unique.OwnedByBusinessAccount -> { + bold("Type") + ": Unique owned by business\n" + bold("Id") + ": ${it.gift.id ?.string ?: "(None)"}\n" + bold("Name") + ": ${it.gift.name.value}\n" + bold("Model") + ": ${it.gift.model.name}\n" + bold("Number") + ": ${it.gift.number}\n" + } + } + } + } + } + val preparedTexts = texts.splitForText() + if (preparedTexts.isEmpty()) { + reply(it, "This chat have no any gifts") + } else { + preparedTexts.forEach { preparedText -> reply(it, preparedText) } + } + } + } + +// allUpdatesFlow.subscribeSafelyWithoutExceptions(this) { +// println(it) +// } + }.second.join() +} diff --git a/KeyboardsBot/KeyboardsBotLib/src/commonMain/kotlin/KeyboardsBot.kt b/KeyboardsBot/KeyboardsBotLib/src/commonMain/kotlin/KeyboardsBot.kt index 1be39cf..77d75d3 100644 --- a/KeyboardsBot/KeyboardsBotLib/src/commonMain/kotlin/KeyboardsBot.kt +++ b/KeyboardsBot/KeyboardsBotLib/src/commonMain/kotlin/KeyboardsBot.kt @@ -11,9 +11,11 @@ import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.* import dev.inmo.tgbotapi.extensions.utils.types.buttons.* import dev.inmo.tgbotapi.extensions.utils.withContent import dev.inmo.tgbotapi.types.BotCommand +import dev.inmo.tgbotapi.types.CustomEmojiId import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.InlineQueryResultArticle import dev.inmo.tgbotapi.types.InlineQueries.InputMessageContent.InputTextMessageContent import dev.inmo.tgbotapi.types.InlineQueryId +import dev.inmo.tgbotapi.types.buttons.KeyboardButtonStyle import dev.inmo.tgbotapi.types.message.content.TextContent import dev.inmo.tgbotapi.utils.PreviewFeature import dev.inmo.tgbotapi.utils.botCommand @@ -51,17 +53,17 @@ fun InlineKeyboardBuilder.includePageButtons(page: Int, count: Int) { row { if (page - 1 > 2) { - dataButton("<<", "1 $count") + dataButton("<<", "1 $count", style = KeyboardButtonStyle.Danger) } if (page - 1 > 1) { - dataButton("<", "${page - 2} $count") + dataButton("<", "${page - 2} $count", style = KeyboardButtonStyle.Primary) } if (page + 1 < count) { - dataButton(">", "${page + 2} $count") + dataButton(">", "${page + 2} $count", style = KeyboardButtonStyle.Success) } if (page + 2 < count) { - dataButton(">>", "$count $count") + dataButton(">>", "$count $count", style = KeyboardButtonStyle.Danger) } } row { @@ -161,7 +163,7 @@ suspend fun activateKeyboardsBot( it, replyMarkup = replyKeyboard(resizeKeyboard = true, oneTimeKeyboard = true) { row { - simpleButton("/inline") + simpleButton("/inline", style = KeyboardButtonStyle.Primary) } } ) { diff --git a/GetMeBot/README.md b/MyBot/README.md similarity index 100% rename from GetMeBot/README.md rename to MyBot/README.md diff --git a/GetMeBot/build.gradle b/MyBot/build.gradle similarity index 100% rename from GetMeBot/build.gradle rename to MyBot/build.gradle diff --git a/MyBot/src/main/kotlin/MyBot.kt b/MyBot/src/main/kotlin/MyBot.kt new file mode 100644 index 0000000..a6f5150 --- /dev/null +++ b/MyBot/src/main/kotlin/MyBot.kt @@ -0,0 +1,94 @@ +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.launchLoggingDropExceptions +import dev.inmo.micro_utils.coroutines.runCatchingLogging +import dev.inmo.tgbotapi.bot.ktor.telegramBot +import dev.inmo.tgbotapi.extensions.api.bot.getMe +import dev.inmo.tgbotapi.extensions.api.bot.removeMyProfilePhoto +import dev.inmo.tgbotapi.extensions.api.bot.setMyProfilePhoto +import dev.inmo.tgbotapi.extensions.api.chat.get.getChat +import dev.inmo.tgbotapi.extensions.api.files.downloadFileToTemp +import dev.inmo.tgbotapi.extensions.api.send.reply +import dev.inmo.tgbotapi.extensions.api.send.sendMessageDraftFlowWithTexts +import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitPhotoMessage +import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand +import dev.inmo.tgbotapi.extensions.utils.extensions.sameChat +import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile +import dev.inmo.tgbotapi.requests.business_connection.InputProfilePhoto +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.consumeAsFlow +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.first + +/** + * This is one of the easiest bots - it will just print information about itself + */ +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)) + } + ) + } + + val bot = telegramBot(botToken) + + telegramBotWithBehaviourAndLongPolling( + botToken, + CoroutineScope(Dispatchers.Default), + testServer = isTestServer, + ) { + val me = bot.getMe() + println(me) + println(bot.getChat(me)) + + onCommand("setMyProfilePhoto") { commandMessage -> + reply(commandMessage, "ok, send me new photo") + val newPhotoMessage = waitPhotoMessage().filter { potentialPhotoMessage -> + potentialPhotoMessage.sameChat(commandMessage) + }.first() + val draftMessagesChannel = Channel(capacity = 1) + + launchLoggingDropExceptions { + sendMessageDraftFlowWithTexts(commandMessage.chat.id, draftMessagesChannel.consumeAsFlow()) + }.invokeOnCompletion { + draftMessagesChannel.close(it) + } + + draftMessagesChannel.send("Start downloading photo") + val photoFile = downloadFileToTemp(newPhotoMessage.content) + + draftMessagesChannel.send("Photo file have been downloaded. Start set my profile photo") + + val setResult = setMyProfilePhoto( + InputProfilePhoto.Static( + photoFile.asMultipartFile() + ) + ) + if (setResult) { + reply(commandMessage, "New photo have been set") + } + } + + onCommand("removeMyProfilePhoto") { + runCatchingLogging { + if (removeMyProfilePhoto()) { + reply(it, "Photo have been removed") + } + }.onFailure { e -> + e.printStackTrace() + reply(it, "Something web wrong. See logs for details.") + } + } + }.second.join() +} diff --git a/ResenderBot/ResenderBotLib/src/commonMain/kotlin/ResenderBot.kt b/ResenderBot/ResenderBotLib/src/commonMain/kotlin/ResenderBot.kt index e5ebe67..a4e3177 100644 --- a/ResenderBot/ResenderBotLib/src/commonMain/kotlin/ResenderBot.kt +++ b/ResenderBot/ResenderBotLib/src/commonMain/kotlin/ResenderBot.kt @@ -38,7 +38,6 @@ suspend fun activateResenderBot( executeUnsafe( it.content.createResend( chat.id, - messageThreadId = it.threadIdOrNull, replyParameters = it.replyInfo?.messageMeta?.let { meta -> val quote = it.withContentOrNull()?.content?.quote ReplyParameters( diff --git a/StarTransactionsBot/src/main/kotlin/StarTransactionsBot.kt b/StarTransactionsBot/src/main/kotlin/StarTransactionsBot.kt index e964cc3..1258851 100644 --- a/StarTransactionsBot/src/main/kotlin/StarTransactionsBot.kt +++ b/StarTransactionsBot/src/main/kotlin/StarTransactionsBot.kt @@ -15,6 +15,7 @@ import dev.inmo.tgbotapi.extensions.utils.extensions.sameChat import dev.inmo.tgbotapi.extensions.utils.types.buttons.* import dev.inmo.tgbotapi.extensions.utils.withContentOrNull import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile +import dev.inmo.tgbotapi.types.ChatId import dev.inmo.tgbotapi.types.RawChatId import dev.inmo.tgbotapi.types.UserId import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup @@ -40,7 +41,7 @@ import kotlinx.coroutines.Dispatchers */ suspend fun main(vararg args: String) { val botToken = args.first() - val adminUserId = args.getOrNull(1) ?.toLongOrNull() ?.let(::RawChatId) ?.let(::UserId) ?: error("Pass user-admin for full access to the bot") + val adminUserId = args.getOrNull(1) ?.toLongOrNull() ?.let(::RawChatId) ?.let(::ChatId) ?: error("Pass user-admin for full access to the bot") val isDebug = args.any { it == "debug" } val isTestServer = args.any { it == "testServer" } diff --git a/TopicsHandling/src/main/kotlin/TopicsHandling.kt b/TopicsHandling/src/main/kotlin/TopicsHandling.kt index 5b04a82..e31f406 100644 --- a/TopicsHandling/src/main/kotlin/TopicsHandling.kt +++ b/TopicsHandling/src/main/kotlin/TopicsHandling.kt @@ -1,15 +1,34 @@ import com.benasher44.uuid.uuid4 +import dev.inmo.kslog.common.w +import dev.inmo.micro_utils.coroutines.runCatchingLogging import dev.inmo.micro_utils.coroutines.runCatchingSafely +import dev.inmo.micro_utils.coroutines.subscribeLoggingDropExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.extensions.api.bot.getMe import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands import dev.inmo.tgbotapi.extensions.api.chat.forum.* import dev.inmo.tgbotapi.extensions.api.send.reply 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.onForumTopicClosed +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onForumTopicCreated +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onForumTopicEdited +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onForumTopicReopened +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onGeneralForumTopicHidden +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onGeneralForumTopicUnhidden +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPrivateForumTopicCreated +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPrivateForumTopicEdited +import dev.inmo.tgbotapi.extensions.utils.forumChatOrNull +import dev.inmo.tgbotapi.extensions.utils.forumContentMessageOrNull +import dev.inmo.tgbotapi.extensions.utils.privateChatOrNull +import dev.inmo.tgbotapi.extensions.utils.privateForumChatOrNull import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.flushAccumulatedUpdates import dev.inmo.tgbotapi.types.BotCommand import dev.inmo.tgbotapi.types.ForumTopic +import dev.inmo.tgbotapi.types.chat.PrivateChat import dev.inmo.tgbotapi.types.commands.BotCommandScope +import io.ktor.client.plugins.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay @@ -20,13 +39,33 @@ suspend fun main(vararg args: String) { CoroutineScope(Dispatchers.Default), defaultExceptionsHandler = { it.printStackTrace() + }, + builder = { + client = client.config { + install(HttpTimeout) { + requestTimeoutMillis = 30000 + socketTimeoutMillis = 30000 + connectTimeoutMillis = 30000 + } + } } ) { + suspend fun TelegramBot.isPrivateForumsEnabled(): Boolean { + val me = getMe() + if (me.hasTopicsEnabled == false) { + Log.w("private forums are disabled. That means that they will not work in private chats") + } + return me.hasTopicsEnabled + } + println() flushAccumulatedUpdates() - allUpdatesFlow.subscribeSafelyWithoutExceptions(this) { + allUpdatesFlow.subscribeLoggingDropExceptions(this) { println(it) } onCommand("start_test_topics") { + if (it.chat is PrivateChat && isPrivateForumsEnabled() == false) { + return@onCommand + } val forumTopic = createForumTopic( it.chat, "Test", @@ -44,21 +83,23 @@ suspend fun main(vararg args: String) { reply(it, "Test topic has changed its name to Test 01") - delay(1000L) - closeForumTopic( - it.chat.id, - forumTopic.messageThreadId, - ) + if (it.chat.privateChatOrNull() == null) { // For private forums it is prohibited to close or reopen topics + delay(1000L) + closeForumTopic( + it.chat.id, + forumTopic.messageThreadId, + ) - reply(it, "Test topic has been closed") + reply(it, "Test topic has been closed") - delay(1000L) - reopenForumTopic( - it.chat.id, - forumTopic.messageThreadId, - ) + delay(1000L) + reopenForumTopic( + it.chat.id, + forumTopic.messageThreadId, + ) - reply(it, "Test topic has been reopened") + reply(it, "Test topic has been reopened") + } delay(1000L) deleteForumTopic( @@ -68,68 +109,111 @@ suspend fun main(vararg args: String) { reply(it, "Test topic has been deleted") - delay(1000L) - hideGeneralForumTopic( - it.chat.id, - ) + if (it.chat.privateChatOrNull() == null) { // For private forums it is prohibited to close or reopen topics + delay(1000L) + hideGeneralForumTopic( + it.chat.id, + ) - reply(it, "General topic has been hidden") + reply(it, "General topic has been hidden") - delay(1000L) - unhideGeneralForumTopic( - it.chat.id - ) + delay(1000L) + unhideGeneralForumTopic( + it.chat.id + ) - reply(it, "General topic has been shown") + reply(it, "General topic has been shown") - delay(1000L) - runCatchingSafely( - { _ -> - reopenGeneralForumTopic( - it.chat.id - ) + delay(1000L) + runCatchingSafely( + { _ -> + reopenGeneralForumTopic( + it.chat.id + ) + closeGeneralForumTopic( + it.chat.id + ) + } + ) { closeGeneralForumTopic( it.chat.id ) } - ) { - closeGeneralForumTopic( + + reply(it, "General topic has been closed") + + delay(1000L) + reopenGeneralForumTopic( it.chat.id ) + + reply(it, "General topic has been opened") + + delay(1000L) + editGeneralForumTopic( + it.chat.id, + uuid4().toString().take(10) + ) + + reply(it, "General topic has been renamed") + + delay(1000L) + editGeneralForumTopic( + it.chat.id, + "Main topic" + ) + + reply(it, "General topic has been renamed") } - reply(it, "General topic has been closed") - - delay(1000L) - reopenGeneralForumTopic( - it.chat.id - ) - - reply(it, "General topic has been opened") - - delay(1000L) - editGeneralForumTopic( - it.chat.id, - uuid4().toString().take(10) - ) - - reply(it, "General topic has been renamed") - - delay(1000L) - editGeneralForumTopic( - it.chat.id, - "Main topic" - ) - - reply(it, "General topic has been renamed") - delay(1000L) } + onCommand("delete_topic") { + val chat = it.chat.forumChatOrNull() ?: return@onCommand + + deleteForumTopic(chat, chat.id.threadId ?: return@onCommand) + } + + onCommand("unpin_all_forum_topic_messages") { + val chat = it.chat.forumChatOrNull() ?: return@onCommand + + unpinAllForumTopicMessages(chat, chat.id.threadId ?: return@onCommand) + } + + onForumTopicCreated { + reply(it, "Topic has been created") + } + onPrivateForumTopicCreated { + reply(it, "Private topic has been created") + } + + onForumTopicEdited { + reply(it, "Topic has been edited") + } + onPrivateForumTopicEdited { + reply(it, "Private topic has been edited") + } + + onForumTopicReopened { + reply(it, "Topic has been reopened") + } + onGeneralForumTopicHidden { + reply(it, "General topic has been hidden") + } + onGeneralForumTopicUnhidden { + reply(it, "General topic has been unhidden") + } + setMyCommands( BotCommand("start_test_topics", "start test topics"), + BotCommand("delete_topic", "delete topic where message have been sent"), + BotCommand("unpin_all_forum_topic_messages", "delete topic where message have been sent"), scope = BotCommandScope.AllGroupChats ) + allUpdatesFlow.subscribeLoggingDropExceptions(this) { + println(it) + } }.second.join() } diff --git a/gradle.properties b/gradle.properties index 9982181..ef92a94 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,9 +5,9 @@ org.gradle.jvmargs=-Xmx3148m kotlin.daemon.jvmargs=-Xmx3g -Xms500m -kotlin_version=2.2.10 -telegram_bot_api_version=29.0.0 -micro_utils_version=0.26.3 +kotlin_version=2.2.21 +telegram_bot_api_version=31.0.0 +micro_utils_version=0.26.9 serialization_version=1.9.0 -ktor_version=3.2.3 +ktor_version=3.3.2 compose_version=1.8.2 diff --git a/settings.gradle b/settings.gradle index 63cf651..0589ba6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,7 +6,7 @@ include ":HelloBot" include ":PollsBot" -include ":GetMeBot" +include ":MyBot" include ":DeepLinksBot" @@ -63,3 +63,7 @@ include ":WebHooks" include ":SuggestedPosts" include ":ChecklistsBot" + +include ":DraftsBot" + +include ":GiftsBot"