Compare commits

..

1 Commits

Author SHA1 Message Date
renovate[bot]
c638543711 Update dependency gradle to v8.6 2024-02-02 18:43:01 +00:00
39 changed files with 507 additions and 985 deletions

View File

@@ -16,4 +16,4 @@ jobs:
with: with:
java-version: 17 java-version: 17
- name: Build with Gradle - name: Build with Gradle
run: ./gradlew build --no-daemon run: ./gradlew build

View File

@@ -4,13 +4,13 @@ import dev.inmo.kslog.common.defaultMessageFormatter
import dev.inmo.kslog.common.setDefaultKSLog import dev.inmo.kslog.common.setDefaultKSLog
import dev.inmo.tgbotapi.bot.ktor.telegramBot import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.get.getUserChatBoosts import dev.inmo.tgbotapi.extensions.api.get.getUserChatBoosts
import dev.inmo.tgbotapi.extensions.api.send.reply import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatBoostUpdated import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatBoostUpdated
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatShared import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatShared
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
import dev.inmo.tgbotapi.extensions.utils.types.buttons.flatReplyKeyboard import dev.inmo.tgbotapi.extensions.utils.types.buttons.*
import dev.inmo.tgbotapi.extensions.utils.types.buttons.requestChannelButton import dev.inmo.tgbotapi.types.chat.member.ChatCommonAdministratorRights
import dev.inmo.tgbotapi.types.request.RequestId import dev.inmo.tgbotapi.types.request.RequestId
import dev.inmo.tgbotapi.utils.regular import dev.inmo.tgbotapi.utils.regular
import korlibs.time.DateFormat import korlibs.time.DateFormat
@@ -52,19 +52,12 @@ suspend fun main(args: Array<String>) {
} }
onChatShared(initialFilter = { it.chatEvent.requestId == requestChatId }) { onChatShared(initialFilter = { it.chatEvent.requestId == requestChatId }) {
val boostsInfoContrainer = runCatching { val boosts = getUserChatBoosts(it.chatEvent.chatId, it.chat.id)
getUserChatBoosts(it.chatEvent.chatId, it.chat.id) reply(
}.getOrNull() it
) {
reply(it) { boosts.boosts.forEach {
when { regular("Boost added: ${DateFormat.FORMAT1.format(it.addDate.asDate)}; Boost expire: ${DateFormat.FORMAT1.format(it.expirationDate.asDate)}; Unformatted: $it") + "\n"
boostsInfoContrainer == null -> +"Unable to take info about boosts in shared chat"
boostsInfoContrainer.boosts.isEmpty() -> +"There is no any boosts in passed chat"
else -> {
boostsInfoContrainer.boosts.forEach {
regular("Boost added: ${DateFormat.FORMAT1.format(it.addDate.asDate)}; Boost expire: ${DateFormat.FORMAT1.format(it.expirationDate.asDate)}; Unformatted: $it") + "\n"
}
}
} }
} }
} }

View File

@@ -1,9 +0,0 @@
# BusinessConnectionBotBot
When bot connected or disconnected to the business chat, it will notify this chat
## Launch
```bash
../gradlew run --args="BOT_TOKEN"
```

View File

@@ -1,21 +0,0 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'kotlin'
apply plugin: 'application'
mainClassName="BusinessConnectionsBotKt"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
}

View File

@@ -1,85 +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.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.get.getBusinessConnection
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.*
import dev.inmo.tgbotapi.extensions.utils.ifBusinessContentMessage
import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.types.business_connection.BusinessConnectionId
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
suspend fun main(args: Array<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 businessConnectionsChats = mutableMapOf<BusinessConnectionId, ChatId>()
val businessConnectionsChatsMutex = Mutex()
telegramBotWithBehaviourAndLongPolling(botToken, CoroutineScope(Dispatchers.IO)) {
val me = getMe()
println(me)
onBusinessConnectionEnabled {
businessConnectionsChatsMutex.withLock {
businessConnectionsChats[it.id] = it.userChatId
}
send(it.userChatId, "Business connection ${it.businessConnectionId.string} has been enabled")
}
onBusinessConnectionDisabled {
businessConnectionsChatsMutex.withLock {
businessConnectionsChats.remove(it.id)
}
send(it.userChatId, "Business connection ${it.businessConnectionId.string} has been disabled")
}
onContentMessage {
it.ifBusinessContentMessage { businessContentMessage ->
val sent = execute(it.content.createResend(businessContentMessage.from.id))
if (businessContentMessage.sentByBusinessConnectionOwner) {
reply(sent, "You have sent this message to the ${businessContentMessage.businessConnectionId.string} related chat")
} else {
reply(sent, "User have sent this message to you in the ${businessContentMessage.businessConnectionId.string} related chat")
}
}
}
onEditedContentMessage {
it.ifBusinessContentMessage { businessContentMessage ->
val sent = execute(businessContentMessage.content.createResend(businessContentMessage.from.id))
if (businessContentMessage.sentByBusinessConnectionOwner) {
reply(sent, "You have edited this message in the ${businessContentMessage.businessConnectionId.string} related chat")
} else {
reply(sent, "User have edited this message to you in the ${businessContentMessage.businessConnectionId.string} related chat")
}
}
}
onBusinessMessagesDeleted {
var businessConnectionOwnerChat = businessConnectionsChatsMutex.withLock {
businessConnectionsChats[it.businessConnectionId]
}
if (businessConnectionOwnerChat == null) {
val businessConnection = getBusinessConnection(it.businessConnectionId)
businessConnectionsChatsMutex.withLock {
businessConnectionsChats[businessConnection.businessConnectionId] = businessConnection.userChatId
}
businessConnectionOwnerChat = businessConnection.userChatId
}
send(businessConnectionOwnerChat, "There are several removed messages in chat ${it.chat.id}: ${it.messageIds}")
}
}.second.join()
}

View File

@@ -5,9 +5,9 @@ import dev.inmo.tgbotapi.extensions.api.files.downloadFile
import dev.inmo.tgbotapi.extensions.api.send.reply import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPhoto import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPhoto
import dev.inmo.tgbotapi.extensions.utils.*
import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers
suspend fun main(args: Array<String>) { suspend fun main(args: Array<String>) {
val bot = telegramBot(args.first()) val bot = telegramBot(args.first())

View File

@@ -1,9 +0,0 @@
# CustomBot
This bot basically have no any useful behaviour, but you may customize it as a playground
## Launch
```bash
../gradlew run --args="BOT_TOKEN"
```

View File

@@ -1,21 +0,0 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'kotlin'
apply plugin: 'application'
mainClassName="CustomBotKt"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
}

View File

@@ -1,34 +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.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
/**
* This place can be the playground for your code.
*/
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)) {
// start here!!
val me = getMe()
println(me)
allUpdatesFlow.subscribeSafelyWithoutExceptions(this) { println(it) }
}.second.join()
}

View File

@@ -1,11 +1,11 @@
import dev.inmo.micro_utils.coroutines.subscribeSafelySkippingExceptions
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.bot.getMe import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.send.reply import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitDeepLinks import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitDeepLinks
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling 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.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onDeepLink
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onText
import dev.inmo.tgbotapi.extensions.utils.formatting.makeTelegramDeepLink import dev.inmo.tgbotapi.extensions.utils.formatting.makeTelegramDeepLink
import dev.inmo.tgbotapi.types.message.textsources.BotCommandTextSource import dev.inmo.tgbotapi.types.message.textsources.BotCommandTextSource

View File

@@ -1,20 +1,20 @@
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.micro_utils.coroutines.AccumulatorFlow
import dev.inmo.micro_utils.fsm.common.State import dev.inmo.micro_utils.fsm.common.State
import dev.inmo.tgbotapi.extensions.api.send.send import dev.inmo.tgbotapi.extensions.api.send.send
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitAnyContentMessage import dev.inmo.tgbotapi.extensions.api.send.sendMessage
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndFSMAndStartLongPolling import dev.inmo.tgbotapi.extensions.behaviour_builder.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.command import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.*
import dev.inmo.tgbotapi.extensions.utils.extensions.parseCommandsWithArgs import dev.inmo.tgbotapi.extensions.utils.extensions.parseCommandsWithParams
import dev.inmo.tgbotapi.extensions.utils.extensions.sameThread import dev.inmo.tgbotapi.extensions.utils.extensions.sameThread
import dev.inmo.tgbotapi.extensions.utils.textContentOrNull import dev.inmo.tgbotapi.extensions.utils.formatting.*
import dev.inmo.tgbotapi.extensions.utils.withContentOrNull
import dev.inmo.tgbotapi.types.IdChatIdentifier import dev.inmo.tgbotapi.types.IdChatIdentifier
import dev.inmo.tgbotapi.types.MessageThreadId
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
import dev.inmo.tgbotapi.types.message.content.TextContent import dev.inmo.tgbotapi.types.message.content.TextContent
import dev.inmo.tgbotapi.utils.botCommand import dev.inmo.tgbotapi.utils.botCommand
import kotlinx.coroutines.CoroutineScope import dev.inmo.tgbotapi.utils.extensions.threadIdOrNull
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.*
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
@@ -54,8 +54,7 @@ suspend fun main(args: Array<String>) {
val content = contentMessage.content val content = contentMessage.content
when { when {
content is TextContent && content.text == "/stop" content is TextContent && content.parseCommandsWithParams().keys.contains("stop") -> StopState(it.context)
|| content is TextContent && content.parseCommandsWithArgs().keys.contains("stop") -> StopState(it.context)
else -> { else -> {
execute(content.createResend(it.context)) execute(content.createResend(it.context))
it it
@@ -73,17 +72,5 @@ suspend fun main(args: Array<String>) {
) { ) {
startChain(ExpectContentOrStopState(it.chat.id, it)) startChain(ExpectContentOrStopState(it.chat.id, it))
} }
onContentMessage(
{
it.content.textContentOrNull() ?.text == "/start"
}
) {
startChain(ExpectContentOrStopState(it.chat.id, it.withContentOrNull() ?: return@onContentMessage))
}
allUpdatesFlow.subscribeSafelyWithoutExceptions(this) {
println(it)
}
}.second.join() }.second.join()
} }

View File

@@ -2,17 +2,38 @@ import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.files.downloadFile import dev.inmo.tgbotapi.extensions.api.files.downloadFile
import dev.inmo.tgbotapi.extensions.api.files.downloadFileToTemp import dev.inmo.tgbotapi.extensions.api.files.downloadFileToTemp
import dev.inmo.tgbotapi.extensions.api.get.getFileAdditionalInfo import dev.inmo.tgbotapi.extensions.api.get.getFileAdditionalInfo
import dev.inmo.tgbotapi.extensions.api.send.* import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.api.send.replyWithAnimation
import dev.inmo.tgbotapi.extensions.api.send.replyWithAudio
import dev.inmo.tgbotapi.extensions.api.send.replyWithDocument
import dev.inmo.tgbotapi.extensions.api.send.replyWithMediaGroup
import dev.inmo.tgbotapi.extensions.api.send.replyWithPhoto
import dev.inmo.tgbotapi.extensions.api.send.replyWithSticker
import dev.inmo.tgbotapi.extensions.api.send.replyWithVideo
import dev.inmo.tgbotapi.extensions.api.send.replyWithVideoNote
import dev.inmo.tgbotapi.extensions.api.send.replyWithVoice
import dev.inmo.tgbotapi.extensions.api.send.withAction
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling 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.onCommand
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMedia import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMedia
import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile
import dev.inmo.tgbotapi.requests.send.SendAction
import dev.inmo.tgbotapi.types.actions.BotAction
import dev.inmo.tgbotapi.types.actions.TypingAction import dev.inmo.tgbotapi.types.actions.TypingAction
import dev.inmo.tgbotapi.types.media.TelegramMediaAudio import dev.inmo.tgbotapi.types.media.TelegramMediaAudio
import dev.inmo.tgbotapi.types.media.TelegramMediaDocument import dev.inmo.tgbotapi.types.media.TelegramMediaDocument
import dev.inmo.tgbotapi.types.media.TelegramMediaPhoto import dev.inmo.tgbotapi.types.media.TelegramMediaPhoto
import dev.inmo.tgbotapi.types.media.TelegramMediaVideo import dev.inmo.tgbotapi.types.media.TelegramMediaVideo
import dev.inmo.tgbotapi.types.message.content.* import dev.inmo.tgbotapi.types.message.content.AnimationContent
import dev.inmo.tgbotapi.types.message.content.AudioContent
import dev.inmo.tgbotapi.types.message.content.DocumentContent
import dev.inmo.tgbotapi.types.message.content.MediaGroupContent
import dev.inmo.tgbotapi.types.message.content.PhotoContent
import dev.inmo.tgbotapi.types.message.content.StickerContent
import dev.inmo.tgbotapi.types.message.content.VideoContent
import dev.inmo.tgbotapi.types.message.content.VideoNoteContent
import dev.inmo.tgbotapi.types.message.content.VoiceContent
import dev.inmo.tgbotapi.utils.filenameFromUrl import dev.inmo.tgbotapi.utils.filenameFromUrl
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers

View File

@@ -1,13 +1,15 @@
import dev.inmo.kslog.common.KSLog import dev.inmo.kslog.common.KSLog
import dev.inmo.kslog.common.LogLevel import dev.inmo.kslog.common.LogLevel
import dev.inmo.kslog.common.defaultMessageFormatter import dev.inmo.kslog.common.defaultMessageFormatter
import dev.inmo.kslog.common.filter.filtered
import dev.inmo.kslog.common.setDefaultKSLog import dev.inmo.kslog.common.setDefaultKSLog
import dev.inmo.tgbotapi.bot.ktor.telegramBot import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.bot.getMe import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
import dev.inmo.tgbotapi.utils.DefaultKTgBotAPIKSLog
/** /**
* This is one of the easiest bots - it will just print information about itself * This is one of the most easiest bot - it will just print information about itself
*/ */
suspend fun main(vararg args: String) { suspend fun main(vararg args: String) {
val botToken = args.first() val botToken = args.first()

View File

@@ -1,18 +1,23 @@
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.bot.getMe import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
import dev.inmo.tgbotapi.extensions.api.send.reply import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMentionWithAnyContent import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMentionWithAnyContent
import dev.inmo.tgbotapi.extensions.utils.extensions.raw.sender_chat
import dev.inmo.tgbotapi.extensions.utils.formatting.linkMarkdownV2 import dev.inmo.tgbotapi.extensions.utils.formatting.linkMarkdownV2
import dev.inmo.tgbotapi.extensions.utils.formatting.textMentionMarkdownV2 import dev.inmo.tgbotapi.extensions.utils.formatting.textMentionMarkdownV2
import dev.inmo.tgbotapi.extensions.utils.ifChannelChat
import dev.inmo.tgbotapi.extensions.utils.ifFromChannelGroupContentMessage import dev.inmo.tgbotapi.extensions.utils.ifFromChannelGroupContentMessage
import dev.inmo.tgbotapi.types.chat.* import dev.inmo.tgbotapi.types.chat.*
import dev.inmo.tgbotapi.types.chat.GroupChat
import dev.inmo.tgbotapi.types.chat.PrivateChat
import dev.inmo.tgbotapi.types.chat.SupergroupChat
import dev.inmo.tgbotapi.types.message.MarkdownV2 import dev.inmo.tgbotapi.types.message.MarkdownV2
import dev.inmo.tgbotapi.utils.PreviewFeature import dev.inmo.tgbotapi.utils.PreviewFeature
import dev.inmo.tgbotapi.utils.extensions.escapeMarkdownV2Common import dev.inmo.tgbotapi.utils.extensions.escapeMarkdownV2Common
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers
/** /**
* The main purpose of this bot is just to answer "Oh, hi, " and add user mention here * The main purpose of this bot is just to answer "Oh, hi, " and add user mention here
@@ -24,6 +29,8 @@ suspend fun main(vararg args: String) {
telegramBotWithBehaviourAndLongPolling(botToken, CoroutineScope(Dispatchers.IO)) { telegramBotWithBehaviourAndLongPolling(botToken, CoroutineScope(Dispatchers.IO)) {
val me = getMe() val me = getMe()
onMentionWithAnyContent(me) { message -> onMentionWithAnyContent(me) { message ->
val chat = message.chat
val answerText = when (val chat = message.chat) { val answerText = when (val chat = message.chat) {
is PreviewChannelChat -> { is PreviewChannelChat -> {
val answer = "Hi everybody in this channel \"${chat.title}\"" val answer = "Hi everybody in this channel \"${chat.title}\""
@@ -35,7 +42,7 @@ suspend fun main(vararg args: String) {
return@onMentionWithAnyContent return@onMentionWithAnyContent
} }
is PreviewGroupChat -> { is PreviewGroupChat -> {
message.ifFromChannelGroupContentMessage<Unit> { message.ifFromChannelGroupContentMessage {
val answer = "Hi, ${it.senderChat.title}" val answer = "Hi, ${it.senderChat.title}"
reply(message, answer, MarkdownV2) reply(message, answer, MarkdownV2)
return@onMentionWithAnyContent return@onMentionWithAnyContent
@@ -49,10 +56,6 @@ suspend fun main(vararg args: String) {
} ?: chat.title } ?: chat.title
} }
} }
is PreviewBusinessChat -> {
reply(message, "Hi, " + "${chat.original.firstName} ${chat.original.lastName} (as business chat :) )".textMentionMarkdownV2(chat.original.id), MarkdownV2)
return@onMentionWithAnyContent
}
is UnknownChatType -> "Unknown :(".escapeMarkdownV2Common() is UnknownChatType -> "Unknown :(".escapeMarkdownV2Common()
} }
reply( reply(

View File

@@ -9,7 +9,6 @@ import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onDeepLi
import dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton import dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.InlineQueryResultArticle import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.InlineQueryResultArticle
import dev.inmo.tgbotapi.types.InlineQueries.InputMessageContent.InputTextMessageContent import dev.inmo.tgbotapi.types.InlineQueries.InputMessageContent.InputTextMessageContent
import dev.inmo.tgbotapi.types.InlineQueryId
import dev.inmo.tgbotapi.types.inlineQueryAnswerResultsLimit import dev.inmo.tgbotapi.types.inlineQueryAnswerResultsLimit
import dev.inmo.tgbotapi.utils.buildEntities import dev.inmo.tgbotapi.utils.buildEntities
@@ -32,9 +31,9 @@ suspend fun doInlineQueriesBot(token: String) {
answer( answer(
it, it,
results = results.map { resultNumber -> results = results.map { resultNumber ->
val inlineQueryId = InlineQueryId(resultNumber.toString()) val resultAsString = resultNumber.toString()
InlineQueryResultArticle( InlineQueryResultArticle(
inlineQueryId, resultAsString,
"Title $resultNumber", "Title $resultNumber",
InputTextMessageContent( InputTextMessageContent(
buildEntities { buildEntities {

View File

@@ -1,3 +1,5 @@
import dev.inmo.micro_utils.common.MPPFile
suspend fun main(args: Array<String>) { suspend fun main(args: Array<String>) {
doInlineQueriesBot(args.first()) doInlineQueriesBot(args.first())
} }

View File

@@ -1,27 +1,26 @@
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.bot.ktor.telegramBot import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.answers.answer import dev.inmo.tgbotapi.extensions.api.answers.answer
import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
import dev.inmo.tgbotapi.extensions.api.edit.edit import dev.inmo.tgbotapi.extensions.api.edit.edit
import dev.inmo.tgbotapi.extensions.api.edit.editMessageText
import dev.inmo.tgbotapi.extensions.api.edit.reply_markup.editMessageReplyMarkup
import dev.inmo.tgbotapi.extensions.api.edit.text.editMessageText import dev.inmo.tgbotapi.extensions.api.edit.text.editMessageText
import dev.inmo.tgbotapi.extensions.api.send.reply import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling import dev.inmo.tgbotapi.extensions.behaviour_builder.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.* import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.*
import dev.inmo.tgbotapi.extensions.utils.types.buttons.* import dev.inmo.tgbotapi.extensions.utils.types.buttons.*
import dev.inmo.tgbotapi.extensions.utils.withContent import dev.inmo.tgbotapi.extensions.utils.withContent
import dev.inmo.tgbotapi.types.BotCommand import dev.inmo.tgbotapi.types.BotCommand
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.InlineQueryResultArticle import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.InlineQueryResultArticle
import dev.inmo.tgbotapi.types.InlineQueries.InputMessageContent.InputTextMessageContent import dev.inmo.tgbotapi.types.InlineQueries.InputMessageContent.InputTextMessageContent
import dev.inmo.tgbotapi.types.InlineQueryId
import dev.inmo.tgbotapi.types.message.content.TextContent import dev.inmo.tgbotapi.types.message.content.TextContent
import dev.inmo.tgbotapi.utils.PreviewFeature import dev.inmo.tgbotapi.utils.*
import dev.inmo.tgbotapi.utils.botCommand import kotlinx.coroutines.*
import dev.inmo.tgbotapi.utils.regular
import dev.inmo.tgbotapi.utils.row private const val nextPageData = "next"
import kotlinx.coroutines.CoroutineScope private const val previousPageData = "previous"
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.currentCoroutineContext
fun String.parsePageAndCount(): Pair<Int, Int>? { fun String.parsePageAndCount(): Pair<Int, Int>? {
val (pageString, countString) = split(" ").takeIf { it.count() > 1 } ?: return null val (pageString, countString) = split(" ").takeIf { it.count() > 1 } ?: return null
@@ -73,7 +72,6 @@ fun InlineKeyboardBuilder.includePageButtons(page: Int, count: Int) {
} }
} }
@OptIn(PreviewFeature::class)
suspend fun activateKeyboardsBot( suspend fun activateKeyboardsBot(
token: String, token: String,
print: (Any) -> Unit print: (Any) -> Unit
@@ -139,7 +137,7 @@ suspend fun activateKeyboardsBot(
it, it,
results = listOf( results = listOf(
InlineQueryResultArticle( InlineQueryResultArticle(
InlineQueryId(it.query), it.query,
"Send buttons", "Send buttons",
InputTextMessageContent("It is sent via inline mode inline buttons"), InputTextMessageContent("It is sent via inline mode inline buttons"),
replyMarkup = inlineKeyboard { replyMarkup = inlineKeyboard {

View File

@@ -3,15 +3,24 @@ import dev.inmo.kslog.common.LogLevel
import dev.inmo.kslog.common.defaultMessageFormatter import dev.inmo.kslog.common.defaultMessageFormatter
import dev.inmo.kslog.common.setDefaultKSLog import dev.inmo.kslog.common.setDefaultKSLog
import dev.inmo.tgbotapi.bot.ktor.telegramBot import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
import dev.inmo.tgbotapi.extensions.api.send.copyMessage
import dev.inmo.tgbotapi.extensions.api.send.reply import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.api.send.send import dev.inmo.tgbotapi.extensions.api.send.send
import dev.inmo.tgbotapi.extensions.api.send.setMessageReaction
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatMessageReactionUpdatedByUser
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatMessageReactionsCountUpdated
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage
import dev.inmo.tgbotapi.extensions.utils.textLinkTextSourceOrNull import dev.inmo.tgbotapi.extensions.utils.textLinkTextSourceOrNull
import dev.inmo.tgbotapi.extensions.utils.uRLTextSourceOrNull import dev.inmo.tgbotapi.extensions.utils.uRLTextSourceOrNull
import dev.inmo.tgbotapi.extensions.utils.withContentOrNull import dev.inmo.tgbotapi.extensions.utils.withContentOrNull
import dev.inmo.tgbotapi.types.LinkPreviewOptions import dev.inmo.tgbotapi.types.LinkPreviewOptions
import dev.inmo.tgbotapi.types.chat.ExtendedChat
import dev.inmo.tgbotapi.types.message.content.TextContent
import dev.inmo.tgbotapi.types.message.content.TextedContent import dev.inmo.tgbotapi.types.message.content.TextedContent
import dev.inmo.tgbotapi.types.reactions.Reaction
import dev.inmo.tgbotapi.utils.customEmoji
import dev.inmo.tgbotapi.utils.regular import dev.inmo.tgbotapi.utils.regular
/** /**
@@ -32,17 +41,17 @@ suspend fun main(vararg args: String) {
val bot = telegramBot(botToken) val bot = telegramBot(botToken)
bot.buildBehaviourWithLongPolling { bot.buildBehaviourWithLongPolling {
onContentMessage { contentMessage -> onContentMessage {
val url = contentMessage.withContentOrNull<TextedContent>() ?.let { message -> val url = it.withContentOrNull<TextedContent>() ?.let {
message.content.textSources.firstNotNullOfOrNull { it.content.textSources.firstNotNullOfOrNull {
it.textLinkTextSourceOrNull() ?.url ?: it.uRLTextSourceOrNull() ?.source it.textLinkTextSourceOrNull() ?.url ?: it.uRLTextSourceOrNull() ?.source
} }
} ?: null.apply { } ?: null.apply {
reply(contentMessage) { reply(it) {
regular("I am support only content with text contains url only") regular("I am support only content with text contains url only")
} }
} ?: return@onContentMessage } ?: return@onContentMessage
contentMessage.withContentOrNull<TextedContent>() ?.let { it.withContentOrNull<TextedContent>() ?.let {
send( send(
it.chat, it.chat,
it.content.textSources, it.content.textSources,

View File

@@ -1,15 +1,33 @@
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.EditLiveLocationInfo import dev.inmo.tgbotapi.extensions.api.EditLiveLocationInfo
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
import dev.inmo.tgbotapi.extensions.api.edit.edit
import dev.inmo.tgbotapi.extensions.api.edit.location.live.stopLiveLocation import dev.inmo.tgbotapi.extensions.api.edit.location.live.stopLiveLocation
import dev.inmo.tgbotapi.extensions.api.handleLiveLocation import dev.inmo.tgbotapi.extensions.api.handleLiveLocation
import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitMessageDataCallbackQuery import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitMessageDataCallbackQuery
import dev.inmo.tgbotapi.extensions.behaviour_builder.oneOf
import dev.inmo.tgbotapi.extensions.behaviour_builder.parallel
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling 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.onCommand
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage
import dev.inmo.tgbotapi.extensions.utils.extensions.sameMessage import dev.inmo.tgbotapi.extensions.utils.extensions.sameMessage
import dev.inmo.tgbotapi.extensions.utils.formatting.linkMarkdownV2
import dev.inmo.tgbotapi.extensions.utils.formatting.textMentionMarkdownV2
import dev.inmo.tgbotapi.extensions.utils.ifFromChannelGroupContentMessage
import dev.inmo.tgbotapi.extensions.utils.types.buttons.dataButton import dev.inmo.tgbotapi.extensions.utils.types.buttons.dataButton
import dev.inmo.tgbotapi.extensions.utils.types.buttons.flatInlineKeyboard import dev.inmo.tgbotapi.extensions.utils.types.buttons.flatInlineKeyboard
import dev.inmo.tgbotapi.types.chat.*
import dev.inmo.tgbotapi.types.chat.GroupChat
import dev.inmo.tgbotapi.types.chat.PrivateChat
import dev.inmo.tgbotapi.types.chat.SupergroupChat
import dev.inmo.tgbotapi.types.location.LiveLocation
import dev.inmo.tgbotapi.types.message.MarkdownV2
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.LiveLocationContent
import dev.inmo.tgbotapi.types.message.content.LocationContent import dev.inmo.tgbotapi.types.message.content.LocationContent
import dev.inmo.tgbotapi.utils.PreviewFeature
import dev.inmo.tgbotapi.utils.extensions.escapeMarkdownV2Common
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -46,7 +64,7 @@ suspend fun main(vararg args: String) {
handleLiveLocation( handleLiveLocation(
it.chat.id, it.chat.id,
locationsFlow, locationsFlow,
sentMessageFlow = { currentMessageState.emit(it) }, sentMessageFlow = FlowCollector { currentMessageState.emit(it) }
) )
} }

View File

@@ -1,78 +1,58 @@
import dev.inmo.kslog.common.KSLog import com.benasher44.uuid.uuid4
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.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.send.polls.sendQuizPoll import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.api.send.polls.sendRegularPoll import dev.inmo.tgbotapi.extensions.api.send.polls.sendRegularPoll
import dev.inmo.tgbotapi.extensions.api.send.send
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling 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.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPollAnswer import dev.inmo.tgbotapi.extensions.utils.extensions.raw.sender_chat
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPollUpdates import dev.inmo.tgbotapi.extensions.utils.formatting.linkMarkdownV2
import dev.inmo.tgbotapi.extensions.utils.customEmojiTextSourceOrNull import dev.inmo.tgbotapi.extensions.utils.formatting.textMentionMarkdownV2
import dev.inmo.tgbotapi.extensions.utils.extensions.parseCommandsWithArgsSources import dev.inmo.tgbotapi.extensions.utils.ifChannelChat
import dev.inmo.tgbotapi.types.BotCommand import dev.inmo.tgbotapi.extensions.utils.ifFromChannelGroupContentMessage
import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.types.IdChatIdentifier import dev.inmo.tgbotapi.types.IdChatIdentifier
import dev.inmo.tgbotapi.types.PollId import dev.inmo.tgbotapi.types.PollIdentifier
import dev.inmo.tgbotapi.types.ReplyParameters import dev.inmo.tgbotapi.types.ReplyParameters
import dev.inmo.tgbotapi.types.polls.InputPollOption import dev.inmo.tgbotapi.types.chat.*
import dev.inmo.tgbotapi.types.chat.GroupChat
import dev.inmo.tgbotapi.types.chat.PrivateChat
import dev.inmo.tgbotapi.types.chat.SupergroupChat
import dev.inmo.tgbotapi.types.message.MarkdownV2
import dev.inmo.tgbotapi.types.polls.Poll
import dev.inmo.tgbotapi.types.polls.PollAnswer import dev.inmo.tgbotapi.types.polls.PollAnswer
import dev.inmo.tgbotapi.utils.buildEntities import dev.inmo.tgbotapi.types.polls.PollOption
import dev.inmo.tgbotapi.utils.customEmoji import dev.inmo.tgbotapi.types.polls.RegularPoll
import dev.inmo.tgbotapi.utils.regular import dev.inmo.tgbotapi.utils.PreviewFeature
import dev.inmo.tgbotapi.utils.underline import dev.inmo.tgbotapi.utils.extensions.escapeMarkdownV2Common
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import kotlin.random.Random
/** /**
* This bot will answer with anonymous or public poll and send message on * This bot will answer with anonymous or public poll and send message on
* any update. * updates of any of it.
* *
* * Use `/anonymous` to take anonymous regular poll * * Use `/anonymous` to take anonymous regular poll
* * Use `/public` to take public regular poll * * Use `/public` to take public regular poll
*/ */
@OptIn(PreviewFeature::class)
suspend fun main(vararg args: String) { suspend fun main(vararg args: String) {
val botToken = args.first() 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)) { telegramBotWithBehaviourAndLongPolling(botToken, CoroutineScope(Dispatchers.IO)) {
val pollToChat = mutableMapOf<PollId, IdChatIdentifier>() val me = getMe()
val pollToChat = mutableMapOf<PollIdentifier, IdChatIdentifier>()
val pollToChatMutex = Mutex() val pollToChatMutex = Mutex()
onCommand("anonymous", requireOnlyCommandInMessage = false) { onCommand("anonymous") {
val customEmoji = it.content.parseCommandsWithArgsSources()
.toList()
.firstOrNull { it.first.command == "anonymous" }
?.second
?.firstNotNullOfOrNull { it.customEmojiTextSourceOrNull() }
val sentPoll = sendRegularPoll( val sentPoll = sendRegularPoll(
it.chat.id, it.chat,
buildEntities { "Test regular anonymous poll",
regular("Test regular anonymous poll")
if (customEmoji != null) {
customEmoji(customEmoji.customEmojiId, customEmoji.subsources)
}
},
(1 .. 10).map { (1 .. 10).map {
InputPollOption { it.toString()
regular(it.toString()) + " "
if (customEmoji != null) {
customEmoji(customEmoji.customEmojiId, customEmoji.subsources)
}
}
}, },
isAnonymous = true, isAnonymous = true,
replyParameters = ReplyParameters(it) replyParameters = ReplyParameters(it)
@@ -82,27 +62,12 @@ suspend fun main(vararg args: String) {
} }
} }
onCommand("public", requireOnlyCommandInMessage = false) { onCommand("public") {
val customEmoji = it.content.parseCommandsWithArgsSources()
.toList()
.firstOrNull { it.first.command == "public" }
?.second
?.firstNotNullOfOrNull { it.customEmojiTextSourceOrNull() }
val sentPoll = sendRegularPoll( val sentPoll = sendRegularPoll(
it.chat.id, it.chat,
buildEntities { "Test regular anonymous poll",
regular("Test regular non anonymous poll")
if (customEmoji != null) {
customEmoji(customEmoji.customEmojiId, customEmoji.subsources)
}
},
(1 .. 10).map { (1 .. 10).map {
InputPollOption { it.toString()
regular(it.toString()) + " "
if (customEmoji != null) {
customEmoji(customEmoji.customEmojiId, customEmoji.subsources)
}
}
}, },
isAnonymous = false, isAnonymous = false,
replyParameters = ReplyParameters(it) replyParameters = ReplyParameters(it)
@@ -112,44 +77,6 @@ suspend fun main(vararg args: String) {
} }
} }
onCommand("quiz", requireOnlyCommandInMessage = false) {
val customEmoji = it.content.parseCommandsWithArgsSources()
.toList()
.firstOrNull { it.first.command == "quiz" }
?.second
?.firstNotNullOfOrNull { it.customEmojiTextSourceOrNull() }
val correctAnswer = Random.nextInt(10)
val sentPoll = sendQuizPoll(
it.chat.id,
questionEntities = buildEntities {
regular("Test quiz 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),
correctOptionId = correctAnswer,
explanationTextSources = buildEntities {
regular("Random solved it to be ") + underline((correctAnswer + 1).toString()) + " "
if (customEmoji != null) {
customEmoji(customEmoji.customEmojiId, customEmoji.subsources)
}
}
)
pollToChatMutex.withLock {
pollToChat[sentPoll.content.poll.id] = sentPoll.chat.id
}
}
onPollAnswer { onPollAnswer {
val chatId = pollToChat[it.pollId] ?: return@onPollAnswer val chatId = pollToChat[it.pollId] ?: return@onPollAnswer
@@ -168,12 +95,6 @@ suspend fun main(vararg args: String) {
} }
} }
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) } allUpdatesFlow.subscribeSafelyWithoutExceptions(this) { println(it) }
}.second.join() }.second.join()
} }

View File

@@ -6,6 +6,7 @@ import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
import dev.inmo.tgbotapi.extensions.api.send.reply import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.api.send.setMessageReaction import dev.inmo.tgbotapi.extensions.api.send.setMessageReaction
import dev.inmo.tgbotapi.extensions.api.send.setMessageReactions
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatMessageReactionUpdatedByUser import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatMessageReactionUpdatedByUser
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatMessageReactionsCountUpdated import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatMessageReactionsCountUpdated

View File

@@ -1,19 +1,19 @@
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.bot.getMe import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.send.withTypingAction import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.api.send.media.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.filters.CommonMessageFilterExcludeMediaGroups
import dev.inmo.tgbotapi.extensions.behaviour_builder.filters.MessageFilterByChat import dev.inmo.tgbotapi.extensions.behaviour_builder.filters.MessageFilterByChat
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage import dev.inmo.tgbotapi.extensions.utils.shortcuts.*
import dev.inmo.tgbotapi.extensions.utils.possiblyWithEffectMessageOrNull
import dev.inmo.tgbotapi.extensions.utils.shortcuts.executeUnsafe
import dev.inmo.tgbotapi.extensions.utils.withContentOrNull import dev.inmo.tgbotapi.extensions.utils.withContentOrNull
import dev.inmo.tgbotapi.types.ReplyParameters import dev.inmo.tgbotapi.types.ReplyParameters
import dev.inmo.tgbotapi.types.message.abstracts.BusinessContentMessage
import dev.inmo.tgbotapi.types.message.content.TextContent import dev.inmo.tgbotapi.types.message.content.TextContent
import dev.inmo.tgbotapi.types.quoteEntitiesField
import dev.inmo.tgbotapi.utils.extensions.threadIdOrNull import dev.inmo.tgbotapi.utils.extensions.threadIdOrNull
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.*
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.currentCoroutineContext
suspend fun activateResenderBot( suspend fun activateResenderBot(
token: String, token: String,
@@ -22,7 +22,6 @@ suspend fun activateResenderBot(
telegramBotWithBehaviourAndLongPolling(token, scope = CoroutineScope(currentCoroutineContext() + SupervisorJob())) { telegramBotWithBehaviourAndLongPolling(token, scope = CoroutineScope(currentCoroutineContext() + SupervisorJob())) {
onContentMessage( onContentMessage(
subcontextUpdatesFilter = MessageFilterByChat, subcontextUpdatesFilter = MessageFilterByChat,
initialFilter = { it !is BusinessContentMessage<*> || !it.sentByBusinessConnectionOwner }
) { ) {
val chat = it.chat val chat = it.chat
@@ -38,8 +37,7 @@ suspend fun activateResenderBot(
entities = quote ?.textSources ?: emptyList(), entities = quote ?.textSources ?: emptyList(),
quotePosition = quote ?.position quotePosition = quote ?.position
) )
}, }
effectId = it.possiblyWithEffectMessageOrNull() ?.effectId
) )
) { ) {
it.forEach(print) it.forEach(print)

View File

@@ -1,9 +1,4 @@
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.firstOf import dev.inmo.micro_utils.coroutines.firstOf
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.micro_utils.fsm.common.State import dev.inmo.micro_utils.fsm.common.State
import dev.inmo.tgbotapi.bot.ktor.telegramBot import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
@@ -16,9 +11,7 @@ import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.api.send.send import dev.inmo.tgbotapi.extensions.api.send.send
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithFSMAndStartLongPolling import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithFSMAndStartLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitChatSharedEventsMessages import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitCommandMessage
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitUserSharedEventsMessages
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand 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.behaviour_builder.triggers_handling.onMessageDataCallbackQuery
import dev.inmo.tgbotapi.extensions.utils.* import dev.inmo.tgbotapi.extensions.utils.*
@@ -29,12 +22,12 @@ import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import dev.inmo.tgbotapi.types.chat.ChannelChat import dev.inmo.tgbotapi.types.chat.ChannelChat
import dev.inmo.tgbotapi.types.chat.ChatPermissions import dev.inmo.tgbotapi.types.chat.ChatPermissions
import dev.inmo.tgbotapi.types.chat.PublicChat import dev.inmo.tgbotapi.types.chat.PublicChat
import dev.inmo.tgbotapi.types.chat.member.AdministratorChatMember import dev.inmo.tgbotapi.types.chat.member.*
import dev.inmo.tgbotapi.types.chat.member.ChatCommonAdministratorRights
import dev.inmo.tgbotapi.types.commands.BotCommandScope import dev.inmo.tgbotapi.types.commands.BotCommandScope
import dev.inmo.tgbotapi.types.message.abstracts.AccessibleMessage import dev.inmo.tgbotapi.types.message.abstracts.AccessibleMessage
import dev.inmo.tgbotapi.types.request.RequestId import dev.inmo.tgbotapi.types.request.RequestId
import dev.inmo.tgbotapi.utils.* import dev.inmo.tgbotapi.utils.*
import dev.inmo.tgbotapi.utils.mention
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.mapNotNull
@@ -54,23 +47,12 @@ sealed interface UserRetrievingStep : State {
) : UserRetrievingStep ) : UserRetrievingStep
} }
@OptIn(PreviewFeature::class)
suspend fun main(args: Array<String>) { suspend fun main(args: Array<String>) {
val botToken = args.first() val botToken = args.first()
val isDebug = args.getOrNull(2) == "debug"
if (isDebug) {
setDefaultKSLog(
KSLog { level: LogLevel, tag: String?, message: Any, throwable: Throwable? ->
println(defaultMessageFormatter(level, tag, message, throwable))
}
)
}
val bot = telegramBot(botToken) val bot = telegramBot(botToken)
val allowedAdmin = ChatId(RawChatId(args[1].toLong())) val allowedAdmin = ChatId(args[1].toLong())
fun Boolean?.allowedSymbol() = when (this) { fun Boolean?.allowedSymbol() = when (this) {
true -> "" true -> ""
@@ -227,6 +209,7 @@ suspend fun main(args: Array<String>) {
} }
) { ) {
val replyMessage = it.replyTo val replyMessage = it.replyTo
val usernameInText = it.content.textSources.firstNotNullOfOrNull { it.mentionTextSourceOrNull() } ?.username
val userInReply = replyMessage?.fromUserMessageOrNull()?.user?.id ?: return@onCommand val userInReply = replyMessage?.fromUserMessageOrNull()?.user?.id ?: return@onCommand
if (replyMessage is AccessibleMessage) { if (replyMessage is AccessibleMessage) {
@@ -379,10 +362,11 @@ suspend fun main(args: Array<String>) {
initialFilter = { it.user.id == allowedAdmin } initialFilter = { it.user.id == allowedAdmin }
) { ) {
val (channelIdString, userIdString) = it.data.split(" ").drop(1) val (channelIdString, userIdString) = it.data.split(" ").drop(1)
val channelId = ChatId(RawChatId(channelIdString.toLong())) val channelId = ChatId(channelIdString.toLong())
val userId = ChatId(RawChatId(userIdString.toLong())) val userId = ChatId(userIdString.toLong())
val chatMember = getChatMember(channelId, userId) val chatMember = getChatMember(channelId, userId)
val asAdmin = chatMember.administratorChatMemberOrNull() val asAdmin = chatMember.administratorChatMemberOrNull()
val asMember = chatMember.memberChatMemberOrNull()
val realData = it.data.takeWhile { it != ' ' } val realData = it.data.takeWhile { it != ' ' }
@@ -505,6 +489,7 @@ suspend fun main(args: Array<String>) {
strictlyOn<UserRetrievingStep.RetrievingChatInfoDoneState> { state -> strictlyOn<UserRetrievingStep.RetrievingChatInfoDoneState> { state ->
val chatMember = getChatMember(state.channelId, state.userId).administratorChatMemberOrNull() val chatMember = getChatMember(state.channelId, state.userId).administratorChatMemberOrNull()
if (chatMember == null) { if (chatMember == null) {
return@strictlyOn null return@strictlyOn null
} }
send( send(
@@ -532,9 +517,5 @@ suspend fun main(args: Array<String>) {
BotCommand("rights_in_channel", "Trigger granular keyboard. Use with reply to user"), BotCommand("rights_in_channel", "Trigger granular keyboard. Use with reply to user"),
scope = BotCommandScope.AllGroupChats scope = BotCommandScope.AllGroupChats
) )
allUpdatesFlow.subscribeSafelyWithoutExceptions(this) {
println(it)
}
}.join() }.join()
} }

View File

@@ -1,9 +0,0 @@
# CustomBot
This bot basically have no any useful behaviour, but you may customize it as a playground
## Launch
```bash
../gradlew run --args="BOT_TOKEN"
```

View File

@@ -1,21 +0,0 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'kotlin'
apply plugin: 'application'
mainClassName="StarTransactionsBotKt"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
}

View File

@@ -1,186 +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.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.answers.payments.answerPreCheckoutQueryOk
import dev.inmo.tgbotapi.extensions.api.edit.edit
import dev.inmo.tgbotapi.extensions.api.files.downloadFileToTemp
import dev.inmo.tgbotapi.extensions.api.get.getStarTransactions
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.*
import dev.inmo.tgbotapi.extensions.utils.extensions.sameChat
import dev.inmo.tgbotapi.extensions.utils.types.buttons.dataButton
import dev.inmo.tgbotapi.extensions.utils.types.buttons.flatInlineKeyboard
import dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard
import dev.inmo.tgbotapi.extensions.utils.types.buttons.payButton
import dev.inmo.tgbotapi.extensions.utils.withContentOrNull
import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile
import dev.inmo.tgbotapi.types.RawChatId
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import dev.inmo.tgbotapi.types.files.*
import dev.inmo.tgbotapi.types.media.TelegramPaidMediaPhoto
import dev.inmo.tgbotapi.types.media.TelegramPaidMediaVideo
import dev.inmo.tgbotapi.types.media.toTelegramPaidMediaPhoto
import dev.inmo.tgbotapi.types.media.toTelegramPaidMediaVideo
import dev.inmo.tgbotapi.types.message.content.TextContent
import dev.inmo.tgbotapi.types.message.textsources.TextSourcesList
import dev.inmo.tgbotapi.types.payments.LabeledPrice
import dev.inmo.tgbotapi.types.payments.stars.StarTransaction
import dev.inmo.tgbotapi.utils.bold
import dev.inmo.tgbotapi.utils.buildEntities
import dev.inmo.tgbotapi.utils.regular
import dev.inmo.tgbotapi.utils.row
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
/**
* An example bot that interacts with Telegram Stars API (used for payments)
*/
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 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 payload = "sample payload"
command("start") {
reply(
it,
price = LabeledPrice("1", 1L),
title = "Sample",
description = "Sample description",
payload = payload,
replyMarkup = flatInlineKeyboard {
payButton("Pay")
},
)
}
onPreCheckoutQuery(initialFilter = { it.invoicePayload == payload }) {
answerPreCheckoutQueryOk(it)
}
val transactionsDataPrefix = "getStarTransactions"
fun buildTransactionsData(offset: Int, limit: Int = 10) = "$transactionsDataPrefix $offset $limit"
fun parseTransactionsData(data: String): Pair<Int, Int> = data.split(" ").drop(1).let {
it.first().toInt() to it.last().toInt()
}
suspend fun buildStarTransactionsPage(offset: Int, limit: Int = 10): Pair<TextSourcesList, InlineKeyboardMarkup> {
val transactions = getStarTransactions(offset, limit)
return buildEntities {
transactions.transactions.forEach {
regular("Transaction Id: ") + bold(it.id.string) + "\n"
regular("Date: ") + bold(it.date.asDate.toStringDefault()) + "\n"
regular("Amount: ") + bold(it.amount.toString()) + "\n"
when (it) {
is StarTransaction.Incoming -> {
regular("Type: ") + bold("incoming") + "\n"
regular("Partner: ") + bold(it.partner.type) + "\n"
}
is StarTransaction.Outgoing -> {
regular("Type: ") + bold("outgoing") + "\n"
regular("Partner: ") + bold(it.partner.type) + "\n"
}
is StarTransaction.Unknown -> {
regular("Type: ") + bold("unknown") + "\n"
regular("Partner: ") + bold(it.partner.type) + "\n"
}
}
}
} to inlineKeyboard {
row {
val prevOffset = (offset - limit).coerceAtLeast(0)
if (prevOffset < offset) {
dataButton("<", buildTransactionsData(prevOffset, limit))
}
val nextOffset = (offset + limit)
dataButton(">", buildTransactionsData(nextOffset, limit))
}
}
}
onCommand("transactions", initialFilter = { it.sameChat(adminUserId) }) {
val (text, keyboard) = buildStarTransactionsPage(0)
reply(it, text, replyMarkup = keyboard)
}
onMessageDataCallbackQuery(Regex("$transactionsDataPrefix \\d+ \\d+")) {
val (offset, limit) = parseTransactionsData(it.data)
val (text, keyboard) = buildStarTransactionsPage(offset, limit)
edit(
it.message.withContentOrNull<TextContent>() ?: return@onMessageDataCallbackQuery,
text,
replyMarkup = keyboard,
)
}
onVisualGalleryMessages {
send(
it.chat,
1,
it.content.group.mapNotNull {
val file = downloadFileToTemp(it.content.media)
when (it.content.media) {
is VideoFile -> {
TelegramPaidMediaVideo(
file.asMultipartFile()
)
}
is PhotoSize -> {
TelegramPaidMediaPhoto(
file.asMultipartFile()
)
}
else -> null
}
},
it.content.textSources,
showCaptionAboveMedia = true
)
}
onPhoto {
send(
it.chat,
1,
listOf(it.content.media.toTelegramPaidMediaPhoto())
)
}
onVideo {
send(
it.chat,
1,
listOf(it.content.media.toTelegramPaidMediaVideo())
)
}
onPaidMediaInfoContent {
println(it)
}
onRefundedPayment {
reply(
it,
"Received your refund: ${it.chatEvent.payment}"
)
}
allUpdatesFlow.subscribeSafelyWithoutExceptions(this) { println(it) }
}.second.join()
}

View File

@@ -1,25 +1,29 @@
import dev.inmo.micro_utils.coroutines.defaultSafelyWithoutExceptionHandler import dev.inmo.micro_utils.coroutines.defaultSafelyWithoutExceptionHandler
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.bot.getMe import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.get.getCustomEmojiStickerOrNull import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.get.getStickerSet import dev.inmo.tgbotapi.extensions.api.get.*
import dev.inmo.tgbotapi.extensions.api.get.getStickerSetOrNull import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.api.send.reply import dev.inmo.tgbotapi.extensions.behaviour_builder.*
import dev.inmo.tgbotapi.extensions.api.send.withTypingAction import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling import dev.inmo.tgbotapi.types.StickerFormat
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onSticker
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onText
import dev.inmo.tgbotapi.types.StickerType import dev.inmo.tgbotapi.types.StickerType
import dev.inmo.tgbotapi.types.message.textsources.CustomEmojiTextSource import dev.inmo.tgbotapi.types.message.textsources.*
import dev.inmo.tgbotapi.types.message.textsources.regular import dev.inmo.tgbotapi.types.stickers.AnimatedStickerSet
import dev.inmo.tgbotapi.types.message.textsources.separateForText import dev.inmo.tgbotapi.types.stickers.CustomEmojiSimpleStickerSet
import dev.inmo.tgbotapi.types.stickers.CustomEmojiStickerSet
import dev.inmo.tgbotapi.types.stickers.CustomEmojiVideoStickerSet
import dev.inmo.tgbotapi.types.stickers.MaskSimpleStickerSet
import dev.inmo.tgbotapi.types.stickers.MaskStickerSet
import dev.inmo.tgbotapi.types.stickers.MaskVideoStickerSet
import dev.inmo.tgbotapi.types.stickers.RegularSimpleStickerSet
import dev.inmo.tgbotapi.types.stickers.RegularStickerSet
import dev.inmo.tgbotapi.types.stickers.RegularVideoStickerSet
import dev.inmo.tgbotapi.types.stickers.StickerSet import dev.inmo.tgbotapi.types.stickers.StickerSet
import dev.inmo.tgbotapi.types.stickers.UnknownStickerSet
import dev.inmo.tgbotapi.utils.bold import dev.inmo.tgbotapi.utils.bold
import dev.inmo.tgbotapi.utils.buildEntities import dev.inmo.tgbotapi.utils.buildEntities
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.*
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.currentCoroutineContext
fun StickerSet?.buildInfo() = buildEntities { fun StickerSet?.buildInfo() = buildEntities {
if (this@buildInfo == null) { if (this@buildInfo == null) {
@@ -27,6 +31,12 @@ fun StickerSet?.buildInfo() = buildEntities {
} else { } else {
bold("StickerSet name: ") + "${name}\n" bold("StickerSet name: ") + "${name}\n"
bold("StickerSet title: ") + "${title}\n" bold("StickerSet title: ") + "${title}\n"
bold("Sticker format: ") + when (stickerFormat) {
StickerFormat.Animated -> "Animated"
StickerFormat.Static -> "Static"
is StickerFormat.Unknown -> stickerFormat.type
StickerFormat.Video -> "Video"
} + "\n"
bold( bold(
when (stickerType) { when (stickerType) {
StickerType.CustomEmoji -> "Custom emoji" StickerType.CustomEmoji -> "Custom emoji"
@@ -34,7 +44,7 @@ fun StickerSet?.buildInfo() = buildEntities {
StickerType.Regular -> "Regular" StickerType.Regular -> "Regular"
is StickerType.Unknown -> "Unknown type \"${stickerType.type}\"" is StickerType.Unknown -> "Unknown type \"${stickerType.type}\""
} }
) + " sticker set with title " + bold(title) + " and name " + bold(name.string) ) + " sticker set with title " + bold(title) + " and name " + bold(name)
} }
} }

View File

@@ -1,6 +1,6 @@
import dev.inmo.micro_utils.coroutines.runCatchingSafely import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.bot.getMe import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.files.downloadFile
import dev.inmo.tgbotapi.extensions.api.files.downloadFileToTemp import dev.inmo.tgbotapi.extensions.api.files.downloadFileToTemp
import dev.inmo.tgbotapi.extensions.api.get.getStickerSet import dev.inmo.tgbotapi.extensions.api.get.getStickerSet
import dev.inmo.tgbotapi.extensions.api.send.reply import dev.inmo.tgbotapi.extensions.api.send.reply
@@ -10,14 +10,11 @@ import dev.inmo.tgbotapi.extensions.api.stickers.deleteStickerSet
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling 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.onCommand
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onSticker import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onSticker
import dev.inmo.tgbotapi.extensions.utils.extensions.raw.sticker
import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile
import dev.inmo.tgbotapi.requests.stickers.InputSticker import dev.inmo.tgbotapi.requests.stickers.InputSticker
import dev.inmo.tgbotapi.types.StickerSetName
import dev.inmo.tgbotapi.types.chat.Chat import dev.inmo.tgbotapi.types.chat.Chat
import dev.inmo.tgbotapi.types.files.CustomEmojiSticker import dev.inmo.tgbotapi.types.files.*
import dev.inmo.tgbotapi.types.files.MaskSticker
import dev.inmo.tgbotapi.types.files.RegularSticker
import dev.inmo.tgbotapi.types.files.UnknownSticker
import dev.inmo.tgbotapi.types.toChatId import dev.inmo.tgbotapi.types.toChatId
import dev.inmo.tgbotapi.utils.botCommand import dev.inmo.tgbotapi.utils.botCommand
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@@ -35,7 +32,7 @@ suspend fun main(args: Array<String>) {
} }
) { ) {
val me = getMe() val me = getMe()
fun Chat.stickerSetName() = StickerSetName("s${id.chatId}_by_${me.username ?.withoutAt}") fun Chat.stickerSetName() = "s${id.chatId}_by_${me.username ?.usernameWithoutAt}"
onCommand("start") { onCommand("start") {
reply(it) { reply(it) {
botCommand("delete") + " - to clear stickers" botCommand("delete") + " - to clear stickers"
@@ -58,19 +55,16 @@ suspend fun main(args: Array<String>) {
val newSticker = when (sticker) { val newSticker = when (sticker) {
is CustomEmojiSticker -> InputSticker.WithKeywords.CustomEmoji( is CustomEmojiSticker -> InputSticker.WithKeywords.CustomEmoji(
downloadFileToTemp(sticker.fileId).asMultipartFile(), downloadFileToTemp(sticker.fileId).asMultipartFile(),
sticker.stickerFormat,
listOf(sticker.emoji ?: "\uD83D\uDE0A"), listOf(sticker.emoji ?: "\uD83D\uDE0A"),
emptyList() emptyList()
) )
is MaskSticker -> InputSticker.Mask( is MaskSticker -> InputSticker.Mask(
downloadFileToTemp(sticker.fileId).asMultipartFile(), downloadFileToTemp(sticker.fileId).asMultipartFile(),
sticker.stickerFormat,
listOf(sticker.emoji ?: "\uD83D\uDE0A"), listOf(sticker.emoji ?: "\uD83D\uDE0A"),
sticker.maskPosition sticker.maskPosition
) )
is RegularSticker -> InputSticker.WithKeywords.Regular( is RegularSticker -> InputSticker.WithKeywords.Regular(
downloadFileToTemp(sticker.fileId).asMultipartFile(), downloadFileToTemp(sticker.fileId).asMultipartFile(),
sticker.stickerFormat,
listOf(sticker.emoji ?: "\uD83D\uDE0A"), listOf(sticker.emoji ?: "\uD83D\uDE0A"),
emptyList() emptyList()
) )
@@ -79,25 +73,18 @@ suspend fun main(args: Array<String>) {
runCatchingSafely { runCatchingSafely {
getStickerSet(stickerSetName) getStickerSet(stickerSetName)
}.onSuccess { stickerSet -> }.onSuccess { stickerSet ->
runCatching { addStickerToSet(it.chat.id.toChatId(), stickerSet.name, newSticker).also { _ ->
addStickerToSet(it.chat.id.toChatId(), stickerSet.name, newSticker).also { _ ->
reply(
it,
getStickerSet(stickerSetName).stickers.last()
)
}
}.onFailure { exception ->
exception.printStackTrace()
reply( reply(
it, it,
"Unable to add sticker in stickerset" getStickerSet(stickerSetName).stickers.last()
) )
} }
}.onFailure { exception -> }.onFailure { _ ->
createNewStickerSet( createNewStickerSet(
it.chat.id.toChatId(), it.chat.id.toChatId(),
stickerSetName.string, stickerSetName,
"Sticker set by ${me.firstName}", "Sticker set by ${me.firstName}",
it.content.media.stickerFormat,
listOf( listOf(
newSticker newSticker
), ),
@@ -110,9 +97,5 @@ suspend fun main(args: Array<String>) {
} }
} }
} }
allUpdatesFlow.subscribeSafelyWithoutExceptions(this) {
println(it)
}
}.second.join() }.second.join()
} }

View File

@@ -1,8 +1,18 @@
import com.benasher44.uuid.uuid4 import com.benasher44.uuid.uuid4
import dev.inmo.micro_utils.common.repeatOnFailure
import dev.inmo.micro_utils.coroutines.runCatchingSafely import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
import dev.inmo.tgbotapi.extensions.api.chat.forum.* import dev.inmo.tgbotapi.extensions.api.chat.forum.closeForumTopic
import dev.inmo.tgbotapi.extensions.api.chat.forum.closeGeneralForumTopic
import dev.inmo.tgbotapi.extensions.api.chat.forum.createForumTopic
import dev.inmo.tgbotapi.extensions.api.chat.forum.deleteForumTopic
import dev.inmo.tgbotapi.extensions.api.chat.forum.editForumTopic
import dev.inmo.tgbotapi.extensions.api.chat.forum.editGeneralForumTopic
import dev.inmo.tgbotapi.extensions.api.chat.forum.hideGeneralForumTopic
import dev.inmo.tgbotapi.extensions.api.chat.forum.reopenForumTopic
import dev.inmo.tgbotapi.extensions.api.chat.forum.reopenGeneralForumTopic
import dev.inmo.tgbotapi.extensions.api.chat.forum.unhideGeneralForumTopic
import dev.inmo.tgbotapi.extensions.api.send.reply import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling 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.onCommand

View File

@@ -1,15 +1,12 @@
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.runCatchingSafely import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.tgbotapi.bot.ktor.telegramBot import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
import dev.inmo.tgbotapi.extensions.api.send.reply import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatShared import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatShared
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onUserShared
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onUsersShared import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onUsersShared
import dev.inmo.tgbotapi.extensions.utils.types.buttons.* import dev.inmo.tgbotapi.extensions.utils.types.buttons.*
import dev.inmo.tgbotapi.types.BotCommand import dev.inmo.tgbotapi.types.BotCommand
@@ -21,15 +18,6 @@ import dev.inmo.tgbotapi.utils.row
suspend fun main(args: Array<String>) { suspend fun main(args: Array<String>) {
val botToken = args.first() 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 bot = telegramBot(botToken)
@@ -67,53 +55,35 @@ suspend fun main(args: Array<String>) {
row { row {
requestUserOrBotButton( requestUserOrBotButton(
"\uD83D\uDC64/\uD83E\uDD16 (1)", "\uD83D\uDC64/\uD83E\uDD16 (1)",
requestIdUserOrBot, requestIdUserOrBot
requestName = true,
requestUsername = true,
requestPhoto = true
) )
} }
row { row {
requestUserButton( requestUserButton(
"\uD83D\uDC64☆ (1)", "\uD83D\uDC64☆ (1)",
requestIdUserNonPremium, requestIdUserNonPremium,
premiumUser = false, premiumUser = false
requestName = true,
requestUsername = true,
requestPhoto = true
) )
requestUserButton( requestUserButton(
"\uD83D\uDC64 (1)", "\uD83D\uDC64 (1)",
requestIdUserAny, requestIdUserAny,
premiumUser = null, premiumUser = null
requestName = true,
requestUsername = true,
requestPhoto = true
) )
requestUserButton( requestUserButton(
"\uD83D\uDC64★ (1)", "\uD83D\uDC64★ (1)",
requestIdUserPremium, requestIdUserPremium,
premiumUser = true, premiumUser = true
requestName = true,
requestUsername = true,
requestPhoto = true
) )
requestBotButton( requestBotButton(
"\uD83E\uDD16 (1)", "\uD83E\uDD16 (1)",
requestIdBot, requestIdBot
requestName = true,
requestUsername = true,
requestPhoto = true
) )
} }
row { row {
requestUsersOrBotsButton( requestUsersOrBotsButton(
"\uD83D\uDC64/\uD83E\uDD16", "\uD83D\uDC64/\uD83E\uDD16",
requestIdUsersOrBots, requestIdUsersOrBots,
maxCount = keyboardButtonRequestUserLimit.last, maxCount = keyboardButtonRequestUserLimit.last
requestName = true,
requestUsername = true,
requestPhoto = true
) )
} }
row { row {
@@ -121,152 +91,101 @@ suspend fun main(args: Array<String>) {
"\uD83D\uDC64", "\uD83D\uDC64",
requestIdUsersNonPremium, requestIdUsersNonPremium,
premiumUser = false, premiumUser = false,
maxCount = keyboardButtonRequestUserLimit.last, maxCount = keyboardButtonRequestUserLimit.last
requestName = true,
requestUsername = true,
requestPhoto = true
) )
requestUsersButton( requestUsersButton(
"\uD83D\uDC64", "\uD83D\uDC64",
requestIdUsersAny, requestIdUsersAny,
premiumUser = null, premiumUser = null,
maxCount = keyboardButtonRequestUserLimit.last, maxCount = keyboardButtonRequestUserLimit.last
requestName = true,
requestUsername = true,
requestPhoto = true
) )
requestUsersButton( requestUsersButton(
"\uD83D\uDC64", "\uD83D\uDC64",
requestIdUsersPremium, requestIdUsersPremium,
premiumUser = true, premiumUser = true,
maxCount = keyboardButtonRequestUserLimit.last, maxCount = keyboardButtonRequestUserLimit.last
requestName = true,
requestUsername = true,
requestPhoto = true
) )
requestBotsButton( requestBotsButton(
"\uD83E\uDD16", "\uD83E\uDD16",
requestIdBots, requestIdBots,
maxCount = keyboardButtonRequestUserLimit.last, maxCount = keyboardButtonRequestUserLimit.last
requestName = true,
requestUsername = true,
requestPhoto = true
) )
} }
row { row {
requestChatButton( requestChatButton(
"\uD83D\uDDE3/\uD83D\uDC65", "\uD83D\uDDE3/\uD83D\uDC65",
requestIdAnyChat, requestIdAnyChat
requestTitle = true,
requestUsername = true,
requestPhoto = true
) )
} }
row { row {
requestChatButton( requestChatButton(
"\uD83D\uDDE3", "\uD83D\uDDE3",
requestIdChannel, requestIdChannel,
isChannel = true, isChannel = true
requestTitle = true,
requestUsername = true,
requestPhoto = true
) )
requestChatButton( requestChatButton(
"\uD83D\uDDE3\uD83D\uDD17", "\uD83D\uDDE3\uD83D\uDD17",
requestIdPublicChannel, requestIdPublicChannel,
isChannel = true, isChannel = true,
isPublic = true, isPublic = true
requestTitle = true,
requestUsername = true,
requestPhoto = true
) )
requestChatButton( requestChatButton(
"\uD83D\uDDE3\uD83D\uDD17", "\uD83D\uDDE3\uD83D\uDD17",
requestIdPrivateChannel, requestIdPrivateChannel,
isChannel = true, isChannel = true,
isPublic = false, isPublic = false
requestTitle = true,
requestUsername = true,
requestPhoto = true
) )
requestChatButton( requestChatButton(
"\uD83D\uDDE3\uD83D\uDC6E", "\uD83D\uDDE3\uD83D\uDC6E",
requestIdChannelUserOwner, requestIdChannelUserOwner,
isChannel = true, isChannel = true,
isOwnedBy = true, isOwnedBy = true
requestTitle = true,
requestUsername = true,
requestPhoto = true
) )
} }
row { row {
requestGroupButton( requestGroupButton(
"👥", "👥",
requestIdGroup, requestIdGroup
requestTitle = true,
requestUsername = true,
requestPhoto = true
) )
requestGroupButton( requestGroupButton(
"👥\uD83D\uDD17", "👥\uD83D\uDD17",
requestIdPublicGroup, requestIdPublicGroup,
isPublic = true, isPublic = true
requestTitle = true,
requestUsername = true,
requestPhoto = true
) )
requestGroupButton( requestGroupButton(
"👥❌\uD83D\uDD17", "👥❌\uD83D\uDD17",
requestIdPrivateGroup, requestIdPrivateGroup,
isPublic = false, isPublic = false
requestTitle = true,
requestUsername = true,
requestPhoto = true
) )
requestGroupButton( requestGroupButton(
"👥\uD83D\uDC6E", "👥\uD83D\uDC6E",
requestIdGroupUserOwner, requestIdGroupUserOwner,
isOwnedBy = true, isOwnedBy = true
requestTitle = true,
requestUsername = true,
requestPhoto = true
) )
} }
row { row {
requestGroupButton( requestGroupButton(
"🏛", "🏛",
requestIdForum, requestIdForum,
isForum = true, isForum = true
requestTitle = true,
requestUsername = true,
requestPhoto = true
) )
requestGroupButton( requestGroupButton(
"🏛\uD83D\uDD17", "🏛\uD83D\uDD17",
requestIdPublicForum, requestIdPublicForum,
isPublic = true, isPublic = true,
isForum = true, isForum = true
requestTitle = true,
requestUsername = true,
requestPhoto = true
) )
requestGroupButton( requestGroupButton(
"🏛❌\uD83D\uDD17", "🏛❌\uD83D\uDD17",
requestIdPrivateForum, requestIdPrivateForum,
isPublic = false, isPublic = false,
isForum = true, isForum = true
requestTitle = true,
requestUsername = true,
requestPhoto = true
) )
requestGroupButton( requestGroupButton(
"🏛\uD83D\uDC6E", "🏛\uD83D\uDC6E",
requestIdForumUserOwner, requestIdForumUserOwner,
isOwnedBy = true, isOwnedBy = true,
isForum = true, isForum = true
requestTitle = true,
requestUsername = true,
requestPhoto = true
) )
} }
} }

View File

@@ -26,7 +26,6 @@ fun HTMLElement.log(text: String) {
appendElement("p", {}) appendElement("p", {})
} }
@OptIn(ExperimentalUnsignedTypes::class)
fun main() { fun main() {
console.log("Web app started") console.log("Web app started")
val client = HttpClient() val client = HttpClient()
@@ -39,7 +38,7 @@ fun main() {
scope.launchSafelyWithoutExceptions { scope.launchSafelyWithoutExceptions {
val response = client.post("$baseUrl/check") { val response = client.post("$baseUrl/check") {
setBody( setBody(
Json.encodeToString( Json { }.encodeToString(
WebAppDataWrapper.serializer(), WebAppDataWrapper.serializer(),
WebAppDataWrapper(webApp.initData, webApp.initDataUnsafe.hash) WebAppDataWrapper(webApp.initData, webApp.initDataUnsafe.hash)
) )

View File

@@ -1,45 +1,44 @@
import dev.inmo.kslog.common.* 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.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.micro_utils.ktor.server.createKtorServer import dev.inmo.micro_utils.ktor.server.createKtorServer
import dev.inmo.tgbotapi.extensions.api.answers.answer
import dev.inmo.tgbotapi.extensions.api.answers.answerInlineQuery import dev.inmo.tgbotapi.extensions.api.answers.answerInlineQuery
import dev.inmo.tgbotapi.extensions.api.bot.getMe import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
import dev.inmo.tgbotapi.extensions.api.send.reply import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.api.send.send
import dev.inmo.tgbotapi.extensions.api.telegramBot import dev.inmo.tgbotapi.extensions.api.telegramBot
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling import dev.inmo.tgbotapi.extensions.behaviour_builder.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onBaseInlineQuery import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand import dev.inmo.tgbotapi.extensions.utils.formatting.makeTelegramStartattach
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onUnhandledCommand import dev.inmo.tgbotapi.extensions.utils.types.buttons.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onWriteAccessAllowed
import dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard
import dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard
import dev.inmo.tgbotapi.extensions.utils.types.buttons.webAppButton
import dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton import dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton
import dev.inmo.tgbotapi.types.BotCommand import dev.inmo.tgbotapi.types.BotCommand
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.InlineQueryResultArticle import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.InlineQueryResultArticle
import dev.inmo.tgbotapi.types.InlineQueries.InputMessageContent.InputTextMessageContent import dev.inmo.tgbotapi.types.InlineQueries.InputMessageContent.InputTextMessageContent
import dev.inmo.tgbotapi.types.InlineQueryId
import dev.inmo.tgbotapi.types.LinkPreviewOptions import dev.inmo.tgbotapi.types.LinkPreviewOptions
import dev.inmo.tgbotapi.types.webAppQueryIdField import dev.inmo.tgbotapi.types.webAppQueryIdField
import dev.inmo.tgbotapi.types.webapps.WebAppInfo import dev.inmo.tgbotapi.types.webapps.WebAppInfo
import dev.inmo.tgbotapi.utils.* import dev.inmo.tgbotapi.utils.*
import io.ktor.http.* import io.ktor.http.*
import io.ktor.server.application.* import io.ktor.server.application.call
import io.ktor.server.http.content.* import io.ktor.server.http.content.*
import io.ktor.server.request.* import io.ktor.server.request.receiveText
import io.ktor.server.response.* import io.ktor.server.response.respond
import io.ktor.server.routing.* import io.ktor.server.routing.post
import io.ktor.server.routing.routing
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import java.io.File import java.io.File
import java.nio.charset.Charset
/** /**
* Accepts two parameters: * Accepts two parameters:
* *
* * Telegram Token * * Telegram Token
* * URL where will be placed * * URL where will be placed
* * Port (default 8080)
* *
* Will start the server to share the static (index.html and WebApp.js) on 0.0.0.0:8080 * Will start the server to share the static (index.html and WebApp.js) on 0.0.0.0:8080
*/ */
@@ -58,7 +57,6 @@ suspend fun main(vararg args: String) {
} }
) )
} }
val initiationLogger = KSLog("Initialization")
val bot = telegramBot(telegramBotAPIUrlsKeeper) val bot = telegramBot(telegramBotAPIUrlsKeeper)
createKtorServer( createKtorServer(
@@ -70,39 +68,23 @@ suspend fun main(vararg args: String) {
) { ) {
routing { routing {
val baseJsFolder = File("WebApp/build/dist/js/") val baseJsFolder = File("WebApp/build/dist/js/")
val prodSubFolder = File(baseJsFolder, "productionExecutable") baseJsFolder.list() ?.forEach {
val devSubFolder = File(baseJsFolder, "developmentExecutable") if (it == "productionExecutable" || it == "developmentExecutable") {
staticFiles("", File(baseJsFolder, it)) {
val staticFolder = when { default("WebApp/build/dist/js/$it/index.html")
prodSubFolder.exists() -> { }
initiationLogger.i("Folder for static is ${prodSubFolder.absolutePath}")
prodSubFolder
} }
devSubFolder.exists() -> {
initiationLogger.i("Folder for static is ${devSubFolder.absolutePath}")
devSubFolder
}
else -> error("""
Unable to detect any folder with static. Current working directory: ${File("").absolutePath}.
Searched paths:
* ${prodSubFolder.absolutePath}
* ${devSubFolder.absolutePath}
""".trimIndent())
}
staticFiles("", staticFolder) {
default("${staticFolder.absolutePath}${File.separator}index.html")
} }
post("inline") { post("inline") {
val requestBody = call.receiveText() val requestBody = call.receiveText()
val queryId = call.parameters[webAppQueryIdField] ?.let(::InlineQueryId) ?: error("$webAppQueryIdField should be presented") val queryId = call.parameters[webAppQueryIdField] ?: error("$webAppQueryIdField should be presented")
bot.answerInlineQuery(queryId, listOf(InlineQueryResultArticle(queryId, "Result", InputTextMessageContent(requestBody)))) bot.answer(queryId, InlineQueryResultArticle(queryId, "Result", InputTextMessageContent(requestBody)))
call.respond(HttpStatusCode.OK) call.respond(HttpStatusCode.OK)
} }
post("check") { post("check") {
val requestBody = call.receiveText() val requestBody = call.receiveText()
val webAppCheckData = Json.decodeFromString(WebAppDataWrapper.serializer(), requestBody) val webAppCheckData = Json { }.decodeFromString(WebAppDataWrapper.serializer(), requestBody)
val isSafe = telegramBotAPIUrlsKeeper.checkWebAppData(webAppCheckData.data, webAppCheckData.hash) val isSafe = telegramBotAPIUrlsKeeper.checkWebAppData(webAppCheckData.data, webAppCheckData.hash)
@@ -114,6 +96,7 @@ suspend fun main(vararg args: String) {
bot.buildBehaviourWithLongPolling( bot.buildBehaviourWithLongPolling(
defaultExceptionsHandler = { it.printStackTrace() } defaultExceptionsHandler = { it.printStackTrace() }
) { ) {
val me = getMe()
onCommand("reply_markup") { onCommand("reply_markup") {
reply( reply(
it, it,

View File

@@ -2,11 +2,10 @@ kotlin.code.style=official
org.gradle.parallel=true org.gradle.parallel=true
# Due to parallel compilation project require next amount of memory on full build # Due to parallel compilation project require next amount of memory on full build
org.gradle.jvmargs=-Xmx2344m org.gradle.jvmargs=-Xmx2344m
kotlin.daemon.jvmargs=-Xmx2g -Xms500m
kotlin_version=1.9.23 kotlin_version=1.9.22
telegram_bot_api_version=15.1.0 telegram_bot_api_version=10.0.0
micro_utils_version=0.21.2 micro_utils_version=0.20.26
serialization_version=1.6.3 serialization_version=1.6.2
ktor_version=2.3.11 ktor_version=2.3.7

Binary file not shown.

View File

@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip

309
gradlew vendored
View File

@@ -1,78 +1,127 @@
#!/usr/bin/env sh #!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
############################################################################## ##############################################################################
## #
## Gradle start up script for UN*X # Gradle start up script for POSIX generated by Gradle.
## #
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
############################################################################## ##############################################################################
# Attempt to set APP_HOME # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
PRG="$0" app_path=$0
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do # Need this for daisy-chained symlinks.
ls=`ls -ld "$PRG"` while
link=`expr "$ls" : '.*-> \(.*\)$'` APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
if expr "$link" : '/.*' > /dev/null; then [ -h "$app_path" ]
PRG="$link" do
else ls=$( ls -ld "$app_path" )
PRG=`dirname "$PRG"`"/$link" link=${ls#*' -> '}
fi case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle" # This is normally unused
APP_BASE_NAME=`basename "$0"` # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
DEFAULT_JVM_OPTS="" APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD=maximum
warn () { warn () {
echo "$*" echo "$*"
} } >&2
die () { die () {
echo echo
echo "$*" echo "$*"
echo echo
exit 1 exit 1
} } >&2
# OS specific support (must be 'true' or 'false'). # OS specific support (must be 'true' or 'false').
cygwin=false cygwin=false
msys=false msys=false
darwin=false darwin=false
nonstop=false nonstop=false
case "`uname`" in case "$( uname )" in #(
CYGWIN* ) CYGWIN* ) cygwin=true ;; #(
cygwin=true Darwin* ) darwin=true ;; #(
;; MSYS* | MINGW* ) msys=true ;; #(
Darwin* ) NONSTOP* ) nonstop=true ;;
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables # IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java" JAVACMD=$JAVA_HOME/jre/sh/java
else else
JAVACMD="$JAVA_HOME/bin/java" JAVACMD=$JAVA_HOME/bin/java
fi fi
if [ ! -x "$JAVACMD" ] ; then if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -81,92 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi fi
else else
JAVACMD="java" JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
MAX_FD_LIMIT=`ulimit -H -n` case $MAX_FD in #(
if [ $? -eq 0 ] ; then max*)
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
MAX_FD="$MAX_FD_LIMIT" # shellcheck disable=SC2039,SC3045
fi MAX_FD=$( ulimit -H -n ) ||
ulimit -n $MAX_FD warn "Could not query maximum file descriptor limit"
if [ $? -ne 0 ] ; then esac
warn "Could not set maximum file descriptor limit: $MAX_FD" case $MAX_FD in #(
fi '' | soft) :;; #(
else *)
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
fi # shellcheck disable=SC2039,SC3045
fi ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac esac
fi fi
# Escape application args # Collect all arguments for the java command, stacking in reverse order:
save () { # * args from the command line
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done # * the main class name
echo " " # * -classpath
} # * -D...appname settings
APP_ARGS=$(save "$@") # * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules # For Cygwin or MSYS, switch paths to Windows format before running java
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong JAVACMD=$( cygpath --unix "$JAVACMD" )
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")" # Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@" exec "$JAVACMD" "$@"

76
gradlew.bat vendored
View File

@@ -1,4 +1,20 @@
@if "%DEBUG%" == "" @echo off @rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@rem Gradle startup script for Windows @rem Gradle startup script for Windows
@@ -9,25 +25,29 @@
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=. if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS= set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init if %ERRORLEVEL% equ 0 goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail goto fail
@@ -35,48 +55,36 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=% set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init if exist "%JAVA_EXE%" goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd if %ERRORLEVEL% equ 0 goto mainEnd
:fail :fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code! rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 set EXIT_CODE=%ERRORLEVEL%
exit /b 1 if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd :mainEnd
if "%OS%"=="Windows_NT" endlocal if "%OS%"=="Windows_NT" endlocal

View File

@@ -47,9 +47,3 @@ include ":ReactionsInfoBot"
include ":LinkPreviewsBot" include ":LinkPreviewsBot"
include ":BoostsInfoBot" include ":BoostsInfoBot"
include ":BusinessConnectionsBot"
include ":StarTransactionsBot"
include ":CustomBot"