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.setMyCommands import dev.inmo.tgbotapi.extensions.api.send.polls.sendQuizPoll import dev.inmo.tgbotapi.extensions.api.send.polls.sendRegularPoll import dev.inmo.tgbotapi.extensions.api.send.reply import dev.inmo.tgbotapi.extensions.api.send.send 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.onContentMessage import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPollAnswer import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPollOptionAdded import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPollOptionDeleted import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPollUpdates import dev.inmo.tgbotapi.extensions.utils.accessibleMessageOrNull import dev.inmo.tgbotapi.extensions.utils.customEmojiTextSourceOrNull import dev.inmo.tgbotapi.extensions.utils.extensions.parseCommandsWithArgsSources import dev.inmo.tgbotapi.types.BotCommand import dev.inmo.tgbotapi.types.IdChatIdentifier import dev.inmo.tgbotapi.types.PollId import dev.inmo.tgbotapi.types.ReplyParameters import dev.inmo.tgbotapi.types.polls.InputPollOption import dev.inmo.tgbotapi.types.polls.PollAnswer import dev.inmo.tgbotapi.utils.buildEntities import dev.inmo.tgbotapi.utils.customEmoji import dev.inmo.tgbotapi.utils.regular import dev.inmo.tgbotapi.utils.underline import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlin.random.Random /** * This bot will answer with anonymous or public poll and send message on * any update. * * * Use `/anonymous` to take anonymous regular poll * * Use `/public` to take public regular poll */ suspend fun main(vararg args: String) { val botToken = args.first() val isDebug = args.any { it == "debug" } if (isDebug) { setDefaultKSLog( KSLog { level: LogLevel, tag: String?, message: Any, throwable: Throwable? -> println(defaultMessageFormatter(level, tag, message, throwable)) } ) } telegramBotWithBehaviourAndLongPolling(botToken, CoroutineScope(Dispatchers.IO)) { val pollToChat = mutableMapOf() val pollToChatMutex = Mutex() onCommand("anonymous", requireOnlyCommandInMessage = false) { val customEmoji = it.content.parseCommandsWithArgsSources() .toList() .firstOrNull { it.first.command == "anonymous" } ?.second ?.firstNotNullOfOrNull { it.customEmojiTextSourceOrNull() } val sentPoll = sendRegularPoll( it.chat.id, buildEntities { regular("Test regular anonymous poll") if (customEmoji != null) { customEmoji(customEmoji.customEmojiId, customEmoji.subsources) } }, (1 .. 10).map { InputPollOption { regular(it.toString()) + " " if (customEmoji != null) { customEmoji(customEmoji.customEmojiId, customEmoji.subsources) } } }, isAnonymous = true, replyParameters = ReplyParameters(it) ) pollToChatMutex.withLock { pollToChat[sentPoll.content.poll.id] = sentPoll.chat.id } } onCommand("public", requireOnlyCommandInMessage = false) { val customEmoji = it.content.parseCommandsWithArgsSources() .toList() .firstOrNull { it.first.command == "public" } ?.second ?.firstNotNullOfOrNull { it.customEmojiTextSourceOrNull() } val sentPoll = sendRegularPoll( it.chat.id, buildEntities { regular("Test regular non anonymous poll") if (customEmoji != null) { customEmoji(customEmoji.customEmojiId, customEmoji.subsources) } }, (1 .. 10).map { InputPollOption { regular(it.toString()) + " " if (customEmoji != null) { customEmoji(customEmoji.customEmojiId, customEmoji.subsources) } } }, isAnonymous = false, replyParameters = ReplyParameters(it), allowAddingOptions = true, hideResultsUntilCloses = true, ) pollToChatMutex.withLock { pollToChat[sentPoll.content.poll.id] = sentPoll.chat.id } } onCommand("quiz", requireOnlyCommandInMessage = false) { val customEmoji = it.content.parseCommandsWithArgsSources() .toList() .firstOrNull { it.first.command == "quiz" } ?.second ?.firstNotNullOfOrNull { it.customEmojiTextSourceOrNull() } val correctAnswer = mutableListOf() (1 until Random.nextInt(9)).forEach { val option = Random.nextInt(10) if (correctAnswer.contains(option)) return@forEach correctAnswer.add(option) } val sentPoll = sendQuizPoll( it.chat.id, questionEntities = buildEntities { regular("Test quiz poll") if (customEmoji != null) { customEmoji(customEmoji.customEmojiId, customEmoji.subsources) } }, descriptionTextSources = buildEntities { regular("Test quiz poll description:") if (customEmoji != null) { customEmoji(customEmoji.customEmojiId, customEmoji.subsources) } }, options = (1 .. 10).map { InputPollOption { regular(it.toString()) + " " if (customEmoji != null) { customEmoji(customEmoji.customEmojiId, customEmoji.subsources) } } }, isAnonymous = false, replyParameters = ReplyParameters(it), correctOptionIds = correctAnswer.sorted(), allowsMultipleAnswers = correctAnswer.size > 1, allowsRevoting = true, shuffleOptions = true, hideResultsUntilCloses = true, explanationTextSources = buildEntities { regular("Random solved it to be ") + underline((correctAnswer + 1).toString()) + " " if (customEmoji != null) { customEmoji(customEmoji.customEmojiId, customEmoji.subsources) } } ) println("Sent poll data: $sentPoll") pollToChatMutex.withLock { pollToChat[sentPoll.content.poll.id] = sentPoll.chat.id } } onPollAnswer { val chatId = pollToChat[it.pollId] ?: return@onPollAnswer when(it) { is PollAnswer.Public -> send(chatId, "[onPollAnswer] User ${it.user} have answered") is PollAnswer.Anonymous -> send(chatId, "[onPollAnswer] Chat ${it.voterChat} have answered") } } onPollUpdates { val chatId = pollToChat[it.id] ?: return@onPollUpdates when(it.isAnonymous) { false -> send(chatId, "[onPollUpdates] Public poll updated: ${it.options.joinToString()}") true -> send(chatId, "[onPollUpdates] Anonymous poll updated: ${it.options.joinToString()}") } } onPollOptionAdded { it.chatEvent.pollMessage ?.accessibleMessageOrNull() ?.let { pollMessage -> reply(pollMessage) { +"Poll option added: \n" +it.chatEvent.optionTextSources } } } onPollOptionDeleted { it.chatEvent.pollMessage ?.accessibleMessageOrNull() ?.let { pollMessage -> reply(pollMessage) { +"Poll option deleted: \n" +it.chatEvent.optionTextSources } } } onContentMessage { val replyPollOptionId = it.replyInfo ?.pollOptionId ?: return@onContentMessage it.replyTo ?.accessibleMessageOrNull() ?.let { replied -> reply(replied, pollOptionId = replyPollOptionId) { +"Reply to poll option" } } } setMyCommands( BotCommand("anonymous", "Create anonymous regular poll"), BotCommand("public", "Create non anonymous regular poll"), BotCommand("quiz", "Create quiz poll with random right answer"), ) allUpdatesFlow.subscribeSafelyWithoutExceptions(this) { println(it) } }.second.join() }