Merge pull request #260 from InsanusMokrassar/12.0.0

12.0.0
This commit is contained in:
InsanusMokrassar 2024-04-21 00:25:25 +06:00 committed by GitHub
commit 99232b53d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 250 additions and 40 deletions

View File

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

View File

@ -0,0 +1,21 @@
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

@ -0,0 +1,85 @@
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 {
val sent = execute(it.content.createResend(it.from.id))
if (it.sentByBusinessConnectionOwner) {
reply(sent, "You have sent this message to the ${it.businessConnectionId.string} related chat")
} else {
reply(sent, "User have sent this message to you in the ${it.businessConnectionId.string} related chat")
}
}
}
onEditedContentMessage {
it.ifBusinessContentMessage {
val sent = execute(it.content.createResend(it.from.id))
if (it.sentByBusinessConnectionOwner) {
reply(sent, "You have edited this message in the ${it.businessConnectionId.string} related chat")
} else {
reply(sent, "User have edited this message to you in the ${it.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

@ -1,4 +1,5 @@
import dev.inmo.micro_utils.coroutines.AccumulatorFlow import dev.inmo.micro_utils.coroutines.AccumulatorFlow
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.extensions.api.send.send import dev.inmo.tgbotapi.extensions.api.send.send
import dev.inmo.tgbotapi.extensions.api.send.sendMessage import dev.inmo.tgbotapi.extensions.api.send.sendMessage
@ -8,6 +9,8 @@ import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.*
import dev.inmo.tgbotapi.extensions.utils.extensions.parseCommandsWithArgs import dev.inmo.tgbotapi.extensions.utils.extensions.parseCommandsWithArgs
import dev.inmo.tgbotapi.extensions.utils.extensions.sameThread import dev.inmo.tgbotapi.extensions.utils.extensions.sameThread
import dev.inmo.tgbotapi.extensions.utils.formatting.* import dev.inmo.tgbotapi.extensions.utils.formatting.*
import dev.inmo.tgbotapi.extensions.utils.textContentOrNull
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.MessageThreadId
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
@ -54,7 +57,8 @@ suspend fun main(args: Array<String>) {
val content = contentMessage.content val content = contentMessage.content
when { when {
content is TextContent && content.parseCommandsWithArgs().keys.contains("stop") -> StopState(it.context) content is TextContent && content.text == "/stop"
|| 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
@ -72,5 +76,17 @@ 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

@ -56,6 +56,10 @@ 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

@ -10,6 +10,7 @@ import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.*
import dev.inmo.tgbotapi.extensions.utils.shortcuts.* import dev.inmo.tgbotapi.extensions.utils.shortcuts.*
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.types.quoteEntitiesField
import dev.inmo.tgbotapi.utils.extensions.threadIdOrNull import dev.inmo.tgbotapi.utils.extensions.threadIdOrNull
@ -22,6 +23,7 @@ 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

View File

@ -9,16 +9,9 @@ import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.*
import dev.inmo.tgbotapi.types.StickerFormat import dev.inmo.tgbotapi.types.StickerFormat
import dev.inmo.tgbotapi.types.StickerType import dev.inmo.tgbotapi.types.StickerType
import dev.inmo.tgbotapi.types.message.textsources.* import dev.inmo.tgbotapi.types.message.textsources.*
import dev.inmo.tgbotapi.types.stickers.AnimatedStickerSet
import dev.inmo.tgbotapi.types.stickers.CustomEmojiSimpleStickerSet
import dev.inmo.tgbotapi.types.stickers.CustomEmojiStickerSet 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.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.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.types.stickers.UnknownStickerSet
import dev.inmo.tgbotapi.utils.bold import dev.inmo.tgbotapi.utils.bold
@ -31,12 +24,6 @@ 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"

View File

@ -56,16 +56,19 @@ 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()
) )
@ -80,12 +83,11 @@ suspend fun main(args: Array<String>) {
getStickerSet(stickerSetName).stickers.last() getStickerSet(stickerSetName).stickers.last()
) )
} }
}.onFailure { _ -> }.onFailure { exception ->
createNewStickerSet( createNewStickerSet(
it.chat.id.toChatId(), it.chat.id.toChatId(),
stickerSetName.string, stickerSetName.string,
"Sticker set by ${me.firstName}", "Sticker set by ${me.firstName}",
it.content.media.stickerFormat,
listOf( listOf(
newSticker newSticker
), ),

View File

@ -1,3 +1,7 @@
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
@ -18,6 +22,15 @@ 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)
@ -55,35 +68,53 @@ 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 {
@ -91,101 +122,152 @@ 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

@ -5,7 +5,7 @@ org.gradle.jvmargs=-Xmx2344m
kotlin_version=1.9.23 kotlin_version=1.9.23
telegram_bot_api_version=11.0.0 telegram_bot_api_version=12.0.0
micro_utils_version=0.20.39 micro_utils_version=0.20.39
serialization_version=1.6.3 serialization_version=1.6.3
ktor_version=2.3.9 ktor_version=2.3.9

View File

@ -47,3 +47,5 @@ include ":ReactionsInfoBot"
include ":LinkPreviewsBot" include ":LinkPreviewsBot"
include ":BoostsInfoBot" include ":BoostsInfoBot"
include ":BusinessConnectionsBot"