diff --git a/.changelog/v0.0.8.md b/.changelog/v0.0.8.md new file mode 100644 index 0000000..163b1a0 --- /dev/null +++ b/.changelog/v0.0.8.md @@ -0,0 +1,7 @@ +> 对应核心版本: [**v4.1.0**](https://github.com/simple-robot/simpler-robot/releases/tag/v4.1.0) + + +我们欢迎并期望着您的的[反馈](https://github.com/simple-robot/simbot-component-telegram/issues)或[协助](https://github.com/simple-robot/simbot-component-telegram/pulls), +感谢您的贡献与支持! + +也欢迎您为我们献上一颗 `star`,这是对我们最大的鼓励与认可! diff --git a/README_CN.md b/README_CN.md index f721688..bfb95b8 100644 --- a/README_CN.md +++ b/README_CN.md @@ -33,144 +33,26 @@ _中文_ | [English](README.md) > 或 > [加入社群](https://simbot.forte.love/communities.html)~ -这是一个基于 [Kotlin coroutines](https://github.com/Kotlin/kotlinx.coroutines) -的 [**Telegram Bot**][telegram bot doc] API/SDK -Kotlin 多平台库,异步高效、Java友好。 +**Telegram组件** +是一个 [Kotlin 多平台](https://kotlinlang.org/docs/multiplatform.html) 的 [**Telegram Bot API**][telegram bot doc] SDK实现库, +也是 Simple Robot 标准API下实现的组件库,异步高效、Java友好! -它同样是一个 [Simple Robot v4][simbot4 gh] (下文简称 simbot) -的组件库,是 simbot 的子项目之一。 -借助 simbot 核心库提供的能力,它可以支持更多高级功能和封装,比如组件协同、Spring支持等。 +> 序列化和网络请求相关分别基于 [Kotlin serialization](https://github.com/Kotlin/kotlinx.serialization) +> 和 [Ktor](https://ktor.io/). -它可以作为一个低级别的 API/SDK 辅助依赖库, -也可在 simbot 核心库的支持下用作为一个轻量级的快速开发框架! - -序列化和网络请求相关分别基于 [Kotlin serialization](https://github.com/Kotlin/kotlinx.serialization) -和 [Ktor](https://ktor.io/). +> 序列化和网络请求相关分别基于 [Kotlin serialization](https://github.com/Kotlin/kotlinx.serialization) +> 和 [Ktor](https://ktor.io/). + ## 文档 -- **Telegram组件**手册:(待建设) -- 了解simbot: [**Simple Robot 应用手册**](https://simbot.forte.love) +- 手册: [**Simple Robot 应用手册**](https://simbot.forte.love) 及其中的 [**Telegram组件**](https://simbot.forte.love/component-telegram.html) 部分。 - **API文档**: [**文档引导站点**](https://docs.simbot.forte.love) 中 Telegram 的 [**KDoc站点**](https://docs.simbot.forte.love/components/telegram) - [**社群**](https://simbot.forte.love/communities.html): 与我们和其他开发者愉快地交流! - ## 安装 -To use the simbot component library, you first need to add the core implementation of simbot -(such as the core library (`simbot-core`) or Spring Boot starter (`simbot-core-spring-boot-starter`)), -and then add the component library dependencies of the Telegram (`simbot-component-telegram-core`). - -> [!note] -> The version of the simbot core implementation library (`SIMBOT_VERSION` below) -> goes [here](https://github.com/simple-robot/simpler-robot/releases) for reference; -> -> Telegram Component library versions (`VERSION` below) go to the [release](https://github.com/simple-robot/simbot-component-telegram/releases) reference. - -**With simbot core** - -### Gradle - -`build.gradle.kts` - -```kotlin -plugins { - kotlin("...") version "..." -} - -dependencies { - implementation("love.forte.simbot:simbot-core:${SIMBOT_VERSION}") - implementation("love.forte.simbot.component:simbot-component-telegram-core:$VERSION") -} -``` - -### Maven - -`pom.xml` - -```xml - - - love.forte.simbot - simbot-core-jvm - ${SIMBOT_VERSION} - - - love.forte.simbot.component - simbot-component-telegram-core-jvm - ${VERSION} - - -``` - -**With simbot spring boot starter** - -### Gradle - -`build.gradle.kts` - -```kotlin -plugins { - kotlin("jvm") version "..." -} - -dependencies { - implementation("love.forte.simbot:simbot-core-spring-boot-starter:${SIMBOT_VERSION}") - implementation("love.forte.simbot.component:simbot-component-telegram-core:$VERSION") -} -``` - -### Maven - -`pom.xml` - -```xml - - - love.forte.simbot - simbot-core-spring-boot-starter - ${SIMBOT_VERSION} - - - love.forte.simbot.component - simbot-component-telegram-core-jvm - ${VERSION} - - -``` - -### Ktor client engine - -The Telegram component uses Ktor as the HTTP client implementation, -but does not rely on any specific engine by default. - -Therefore, you need to choose and use a Ktor Client engine implementation. - -You can go to the [Ktor documentation](https://ktor.io/docs/client-engines.html) -to select a suitable Client Engine for your platform. - -Take the JVM platform as an example: - -
Gradle - -```kotlin -runtimeOnly("io.ktor:ktor-client-java:$ktor_version") -``` - -
- -
Maven - -```xml - - io.ktor - ktor-client-java-jvm - ${ktor_version} - runtime - -``` - -
+参考手册的 [**Telegram组件**](https://simbot.forte.love/component-telegram.html) 部分。 ## Examples diff --git a/buildSrc/src/main/kotlin/P.kt b/buildSrc/src/main/kotlin/P.kt index 72b4481..87e828b 100644 --- a/buildSrc/src/main/kotlin/P.kt +++ b/buildSrc/src/main/kotlin/P.kt @@ -40,8 +40,8 @@ object P { override val description: String get() = DESCRIPTION override val homepage: String get() = HOMEPAGE - const val VERSION = "0.0.7" - const val NEXT_VERSION = "0.0.8" + const val VERSION = "0.0.8" + const val NEXT_VERSION = "0.0.9" override val snapshotVersion = "$NEXT_VERSION-SNAPSHOT" override val version = if (isSnapshot()) snapshotVersion else VERSION diff --git a/simbot-component-telegram-api/src/commonMain/kotlin/love/forte/simbot/telegram/api/bot/command/DeleteMyCommandsApi.kt b/simbot-component-telegram-api/src/commonMain/kotlin/love/forte/simbot/telegram/api/bot/command/DeleteMyCommandsApi.kt new file mode 100644 index 0000000..4665532 --- /dev/null +++ b/simbot-component-telegram-api/src/commonMain/kotlin/love/forte/simbot/telegram/api/bot/command/DeleteMyCommandsApi.kt @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024. ForteScarlet. + * + * This file is part of simbot-component-telegram. + * + * simbot-component-telegram is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * simbot-component-telegram is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with simbot-component-telegram. + * If not, see . + */ + +package love.forte.simbot.telegram.api.bot.command + +import kotlinx.serialization.DeserializationStrategy +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.builtins.serializer +import love.forte.simbot.telegram.api.SimpleBodyTelegramApi +import love.forte.simbot.telegram.api.TelegramApiResult +import love.forte.simbot.telegram.type.BotCommandScope +import kotlin.jvm.JvmOverloads +import kotlin.jvm.JvmStatic + + +/** + * [deleteMyCommands](https://core.telegram.org/bots/api#deletemycommands) + * + * Use this method to delete the list of the bot's commands for the given scope and user language. + * After deletion, higher level commands will be shown to affected users. Returns True on success. + * + * @author ForteScarlet + */ +public class DeleteMyCommandsApi +private constructor(body: Body) : SimpleBodyTelegramApi() { + public companion object Factory { + private const val NAME = "deleteMyCommands" + private val EMPTY = DeleteMyCommandsApi(Body()) + + /** + * Create an instance of [DeleteMyCommandsApi]. + * + * @param scope A JSON-serialized object, describing scope of users for which the commands are relevant. + * Defaults to BotCommandScopeDefault. + * @param languageCode A two-letter ISO 639-1 language code. + * If empty, commands will be applied to all users from the given scope, + * for whose language there are no dedicated commands + */ + @JvmStatic + @JvmOverloads + public fun create( + scope: BotCommandScope? = null, + languageCode: String? = null, + ): DeleteMyCommandsApi { + return if (scope == null && languageCode == null) { + EMPTY + } else { + DeleteMyCommandsApi( + Body( + scope = scope, + languageCode = languageCode + ) + ) + } + } + } + + /** + * Request body for [DeleteMyCommandsApi] + * @property scope A JSON-serialized object, describing scope of users for which the commands are relevant. + * Defaults to BotCommandScopeDefault. + * @property languageCode A two-letter ISO 639-1 language code. + * If empty, commands will be applied to all users from the given scope, + * for whose language there are no dedicated commands + */ + @Serializable + public data class Body( + val scope: BotCommandScope? = null, + @SerialName("language_code") + val languageCode: String? = null, + ) + + override val name: String + get() = NAME + + override val body: Any = body + + override val responseDeserializer: DeserializationStrategy + get() = Boolean.serializer() + + override val resultDeserializer: DeserializationStrategy> + get() = TelegramApiResult.BooleanSerializer +} + +/* +Parameter Type Required Description + */ diff --git a/simbot-component-telegram-api/src/commonMain/kotlin/love/forte/simbot/telegram/api/bot/command/SetMyCommandsApi.kt b/simbot-component-telegram-api/src/commonMain/kotlin/love/forte/simbot/telegram/api/bot/command/SetMyCommandsApi.kt new file mode 100644 index 0000000..7f67184 --- /dev/null +++ b/simbot-component-telegram-api/src/commonMain/kotlin/love/forte/simbot/telegram/api/bot/command/SetMyCommandsApi.kt @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024. ForteScarlet. + * + * This file is part of simbot-component-telegram. + * + * simbot-component-telegram is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * simbot-component-telegram is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with simbot-component-telegram. + * If not, see . + */ + +package love.forte.simbot.telegram.api.bot.command + +import kotlinx.serialization.DeserializationStrategy +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.builtins.serializer +import love.forte.simbot.telegram.api.SimpleBodyTelegramApi +import love.forte.simbot.telegram.api.TelegramApiResult +import love.forte.simbot.telegram.type.BotCommand +import love.forte.simbot.telegram.type.BotCommandScope +import kotlin.jvm.JvmOverloads +import kotlin.jvm.JvmStatic + + +/** + * [setMyCommands](https://core.telegram.org/bots/api#setmycommands) + * Use this method to change the list of the bot's commands. + * See this manual for more details about bot commands. Returns True on success. + * + * @author ForteScarlet + */ +public class SetMyCommandsApi +private constructor(body: Body) : SimpleBodyTelegramApi() { + public companion object Factory { + private const val NAME = "setMyCommands" + + /** + * Create an instance of [SetMyCommandsApi]. + * + * @param commands A JSON-serialized list of bot commands to be set as the list of the bot's commands. + * At most 100 commands can be specified. + * @param scope A JSON-serialized object, describing scope of users for which the commands are relevant. + * Defaults to BotCommandScopeDefault. + * @param languageCode A two-letter ISO 639-1 language code. + * If empty, commands will be applied to all users from the given scope, + * for whose language there are no dedicated commands + */ + @JvmStatic + @JvmOverloads + public fun create( + commands: List, + scope: BotCommandScope? = null, + languageCode: String? = null, + ): SetMyCommandsApi = SetMyCommandsApi( + Body( + commands = commands, + scope = scope, + languageCode = languageCode + ) + ) + } + + /** + * Request body for [SetMyCommandsApi] + * @property commands A JSON-serialized list of bot commands to be set as the list of the bot's commands. + * At most 100 commands can be specified. + * @property scope A JSON-serialized object, describing scope of users for which the commands are relevant. + * Defaults to BotCommandScopeDefault. + * @property languageCode A two-letter ISO 639-1 language code. + * If empty, commands will be applied to all users from the given scope, + * for whose language there are no dedicated commands + */ + @Serializable + public data class Body( + val commands: List = emptyList(), + val scope: BotCommandScope? = null, + @SerialName("language_code") + val languageCode: String? = null, + ) + + override val name: String + get() = NAME + + override val body: Any = body + + override val responseDeserializer: DeserializationStrategy + get() = Boolean.serializer() + + override val resultDeserializer: DeserializationStrategy> + get() = TelegramApiResult.BooleanSerializer +} + +/* +Parameter Type Required Description + */ diff --git a/simbot-component-telegram-api/supports.md b/simbot-component-telegram-api/supports.md index fbca720..bb5ea7f 100644 --- a/simbot-component-telegram-api/supports.md +++ b/simbot-component-telegram-api/supports.md @@ -3,7 +3,9 @@ - [bot](src/commonMain/kotlin/love/forte/simbot/telegram/api/bot) - [x] [CloseApi](src/commonMain/kotlin/love/forte/simbot/telegram/api/bot/CloseApi.kt) - [command](src/commonMain/kotlin/love/forte/simbot/telegram/api/bot/command) + - [x] [DeleteMyCommandsApi](src/commonMain/kotlin/love/forte/simbot/telegram/api/bot/command/DeleteMyCommandsApi.kt) - [x] [GetMyCommandsApi](src/commonMain/kotlin/love/forte/simbot/telegram/api/bot/command/GetMyCommandsApi.kt) + - [x] [SetMyCommandsApi](src/commonMain/kotlin/love/forte/simbot/telegram/api/bot/command/SetMyCommandsApi.kt) - [x] [GetChatMenuButtonApi](src/commonMain/kotlin/love/forte/simbot/telegram/api/bot/GetChatMenuButtonApi.kt) - [x] [GetMeApi](src/commonMain/kotlin/love/forte/simbot/telegram/api/bot/GetMeApi.kt) - [x] [GetMyDefaultAdministratorRightsApi](src/commonMain/kotlin/love/forte/simbot/telegram/api/bot/GetMyDefaultAdministratorRightsApi.kt) diff --git a/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/TelegramBot.kt b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/TelegramBot.kt index ab5fcb8..fd7fd8b 100644 --- a/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/TelegramBot.kt +++ b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/TelegramBot.kt @@ -23,9 +23,12 @@ import love.forte.simbot.bot.GroupRelation import love.forte.simbot.bot.GuildRelation import love.forte.simbot.common.id.ID import love.forte.simbot.common.id.LongID.Companion.ID +import love.forte.simbot.component.telegram.core.bot.command.TelegramBotCommands +import love.forte.simbot.component.telegram.core.bot.command.TelegramBotCommandsUpdater import love.forte.simbot.component.telegram.core.component.TelegramComponent import love.forte.simbot.suspendrunner.ST import love.forte.simbot.telegram.api.update.Update +import love.forte.simbot.telegram.type.BotCommandScope import love.forte.simbot.telegram.type.User import kotlin.coroutines.CoroutineContext @@ -98,14 +101,45 @@ public interface TelegramBot : Bot { source.pushUpdate(update, raw) } + /** + * Fetches a [TelegramBotCommands] with [scope] and [languageCode]. + * + * @param scope Scope of bot commands. + * @param languageCode A two-letter ISO 639-1 language code of commands. + */ + @ST + public suspend fun commands(scope: BotCommandScope?, languageCode: String?): TelegramBotCommands + + /** + * Fetches a [TelegramBotCommands]. + */ + @ST + public suspend fun commands(): TelegramBotCommands = + commands(scope = null, languageCode = null) + + /** + * An updater for set commands. + * + * @see TelegramBotCommandsUpdater + */ + public val commandsUpdater: TelegramBotCommandsUpdater override val groupRelation: GroupRelation? - get() = null // TODO? + get() = null override val guildRelation: GuildRelation? - get() = null // TODO? + get() = null override val contactRelation: ContactRelation? - get() = null // TODO? + get() = null } + +/** + * Update bot commands by [TelegramBot.commandsUpdater] + * + * @see TelegramBot.commandsUpdater + */ +public suspend inline fun TelegramBot.updateCommands( + block: TelegramBotCommandsUpdater.() -> Unit +): TelegramBotCommands = commandsUpdater.also(block).update() diff --git a/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/command/TelegramBotCommands.kt b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/command/TelegramBotCommands.kt new file mode 100644 index 0000000..7328e57 --- /dev/null +++ b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/command/TelegramBotCommands.kt @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2024. ForteScarlet. + * + * This file is part of simbot-component-telegram. + * + * simbot-component-telegram is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * simbot-component-telegram is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with simbot-component-telegram. + * If not, see . + */ + +package love.forte.simbot.component.telegram.core.bot.command + +import love.forte.simbot.ability.DeleteOption +import love.forte.simbot.ability.DeleteSupport +import love.forte.simbot.component.telegram.core.bot.TelegramBot +import love.forte.simbot.telegram.type.BotCommand +import love.forte.simbot.telegram.type.BotCommandScope +import kotlin.jvm.JvmSynthetic + + +/** + * A set of Telegram's [BotCommand]s + * + * @author ForteScarlet + */ +public interface TelegramBotCommands : DeleteSupport, Iterable { + /** + * The list of [TelegramBotCommand] + */ + public val values: List + + /** + * Iterator of [values]. + */ + override fun iterator(): Iterator = + values.iterator() + + /** + * A command scope used in the query. + */ + public val scope: BotCommandScope? + + /** + * A two-letter ISO 639-1 language code used in the query. + */ + public val languageCode: String? + + /** + * Delete this set of commands with [scope] and [languageCode]. + */ + @JvmSynthetic + override suspend fun delete(vararg options: DeleteOption) + + /** + * Get a [TelegramBotCommandsUpdater] with [scope] and [languageCode] + * for update commands. + * + * @see TelegramBotCommandsUpdater + */ + public val updater: TelegramBotCommandsUpdater +} + +/** + * Update bot commands by [TelegramBotCommands.updater] + * + * @see TelegramBotCommands.updater + */ +public suspend inline fun TelegramBotCommands.update( + block: TelegramBotCommandsUpdater.() -> Unit +): TelegramBotCommands = updater.also(block).update() + +/** + * A [BotCommand] of [TelegramBotCommands] from [TelegramBot.commands]. + * + * @see TelegramBotCommands + * @see BotCommand + */ +public interface TelegramBotCommand { + /** + * The source type [BotCommand] + */ + public val source: BotCommand + + /** + * Text of the command. + * + * @see BotCommand.command + */ + public val command: String + get() = source.command + + /** + * Description of the command. + * + * @see BotCommand.description + */ + public val description: String + get() = source.description +} + + diff --git a/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/command/TelegramBotCommandsUpdater.kt b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/command/TelegramBotCommandsUpdater.kt new file mode 100644 index 0000000..9a040eb --- /dev/null +++ b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/command/TelegramBotCommandsUpdater.kt @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024. ForteScarlet. + * + * This file is part of simbot-component-telegram. + * + * simbot-component-telegram is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * simbot-component-telegram is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with simbot-component-telegram. + * If not, see . + */ + +package love.forte.simbot.component.telegram.core.bot.command + +import love.forte.simbot.suspendrunner.ST +import love.forte.simbot.telegram.type.BotCommand +import love.forte.simbot.telegram.type.BotCommandScope + + +/** + * An updater for set bot commands. + * + * @author ForteScarlet + */ +public interface TelegramBotCommandsUpdater { + /** + * the [BotCommandScope] + */ + public var scope: BotCommandScope? + + /** + * the [languageCode] + */ + public var languageCode: String? + + /** + * Commands for update. + */ + public var commands: MutableList + + /** + * @see scope + */ + public fun scope(scope: BotCommandScope?): TelegramBotCommandsUpdater = apply { + this.scope = scope + } + + /** + * @see languageCode + */ + public fun languageCode(languageCode: String?): TelegramBotCommandsUpdater = apply { + this.languageCode = languageCode + } + + /** + * Add a command into [commands] + * @see commands + */ + public fun addCommand(command: BotCommand): TelegramBotCommandsUpdater = apply { + commands.add(command) + } + + /** + * Add a command into [commands] + * @see commands + */ + public fun addCommand(command: String, description: String): TelegramBotCommandsUpdater = + addCommand(BotCommand(command, description)) + + /** + * Execute setting and a new [TelegramBotCommands] that + * values **directly** based on new commands is returned. + * + */ + @ST + public suspend fun update(): TelegramBotCommands +} diff --git a/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/TelegramBotImpl.kt b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/TelegramBotImpl.kt index 2285037..fbdf92f 100644 --- a/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/TelegramBotImpl.kt +++ b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/TelegramBotImpl.kt @@ -31,6 +31,10 @@ import love.forte.simbot.common.id.toLongOrNull import love.forte.simbot.component.telegram.core.bot.StdlibBot import love.forte.simbot.component.telegram.core.bot.TelegramBot import love.forte.simbot.component.telegram.core.bot.TelegramBotConfiguration +import love.forte.simbot.component.telegram.core.bot.command.TelegramBotCommands +import love.forte.simbot.component.telegram.core.bot.command.TelegramBotCommandsUpdater +import love.forte.simbot.component.telegram.core.bot.internal.command.TelegramBotCommandsUpdaterImpl +import love.forte.simbot.component.telegram.core.bot.internal.command.toTGCommands import love.forte.simbot.component.telegram.core.component.TelegramComponent import love.forte.simbot.component.telegram.core.event.TelegramUnsupportedEvent import love.forte.simbot.component.telegram.core.event.internal.TelegramChannelMessageEventImpl @@ -42,6 +46,7 @@ import love.forte.simbot.event.EventDispatcher import love.forte.simbot.event.onEachError import love.forte.simbot.logger.LoggerFactory import love.forte.simbot.telegram.api.bot.GetMeApi +import love.forte.simbot.telegram.api.bot.command.GetMyCommandsApi import love.forte.simbot.telegram.api.update.SuspendableUpdateDivider import love.forte.simbot.telegram.api.update.Update import love.forte.simbot.telegram.stdlib.bot.SubscribeSequence @@ -111,9 +116,32 @@ internal class TelegramBotImpl( isStarted = true } } + + override suspend fun commands(scope: BotCommandScope?, languageCode: String?): TelegramBotCommands { + val commands = GetMyCommandsApi.create( + scope = scope, + languageCode = languageCode + ).requestDataBy(source) + + return commands.toTGCommands( + bot = this, + scope = scope, + languageCode = languageCode + ) + } + + override val commandsUpdater: TelegramBotCommandsUpdater + get() = TelegramBotCommandsUpdaterImpl( + bot = this, + scope = null, + languageCode = null + ) } + + + @OptIn(FragileSimbotAPI::class) internal fun subscribeInternalProcessor( bot: TelegramBotImpl, diff --git a/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/command/TelegramBotCommandsImpl.kt b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/command/TelegramBotCommandsImpl.kt new file mode 100644 index 0000000..d680ae7 --- /dev/null +++ b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/command/TelegramBotCommandsImpl.kt @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024. ForteScarlet. + * + * This file is part of simbot-component-telegram. + * + * simbot-component-telegram is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * simbot-component-telegram is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with simbot-component-telegram. + * If not, see . + */ + +package love.forte.simbot.component.telegram.core.bot.internal.command + +import love.forte.simbot.ability.DeleteFailureException +import love.forte.simbot.ability.DeleteOption +import love.forte.simbot.ability.StandardDeleteOption +import love.forte.simbot.component.telegram.core.bot.TelegramBot +import love.forte.simbot.component.telegram.core.bot.command.TelegramBotCommand +import love.forte.simbot.component.telegram.core.bot.command.TelegramBotCommands +import love.forte.simbot.component.telegram.core.bot.command.TelegramBotCommandsUpdater +import love.forte.simbot.telegram.api.bot.command.DeleteMyCommandsApi +import love.forte.simbot.telegram.stdlib.bot.requestDataBy +import love.forte.simbot.telegram.type.BotCommand +import love.forte.simbot.telegram.type.BotCommandScope + +internal class TelegramBotCommandsImpl( + private val bot: TelegramBot, + override val values: List, + override val scope: BotCommandScope?, + override val languageCode: String?, +) : TelegramBotCommands { + override suspend fun delete(vararg options: DeleteOption) { + runCatching { + DeleteMyCommandsApi.create( + scope = scope, + languageCode = languageCode + ).requestDataBy(bot.source) + }.onFailure { err -> + if (StandardDeleteOption.IGNORE_ON_FAILURE !in options) { + throw DeleteFailureException(err.message, err) + } + } + } + + override val updater: TelegramBotCommandsUpdater + get() = TelegramBotCommandsUpdaterImpl( + bot = bot, + scope = scope, + languageCode = languageCode + ) + + override fun toString(): String = + "TelegramBotCommands(scope=$scope, languageCode=$languageCode, values=$values)" +} + +internal fun Iterable.toTGCommands( + bot: TelegramBot, + scope: BotCommandScope?, + languageCode: String?, +): TelegramBotCommandsImpl = + TelegramBotCommandsImpl( + bot, + this.map { it.toTGCommand() }, + scope, + languageCode + ) + +/** + * + * @author ForteScarlet + */ +internal class TelegramBotCommandImpl( + override val source: BotCommand +) : TelegramBotCommand { + override fun toString(): String { + return "TelegramBotCommand(source=$source)" + } +} + +internal fun BotCommand.toTGCommand(): TelegramBotCommandImpl = + TelegramBotCommandImpl(this) diff --git a/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/command/TelegramBotCommandsUpdaterImpl.kt b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/command/TelegramBotCommandsUpdaterImpl.kt new file mode 100644 index 0000000..26d71ac --- /dev/null +++ b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/command/TelegramBotCommandsUpdaterImpl.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024. ForteScarlet. + * + * This file is part of simbot-component-telegram. + * + * simbot-component-telegram is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * simbot-component-telegram is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with simbot-component-telegram. + * If not, see . + */ + +package love.forte.simbot.component.telegram.core.bot.internal.command + +import love.forte.simbot.component.telegram.core.bot.TelegramBot +import love.forte.simbot.component.telegram.core.bot.command.TelegramBotCommands +import love.forte.simbot.component.telegram.core.bot.command.TelegramBotCommandsUpdater +import love.forte.simbot.telegram.api.bot.command.SetMyCommandsApi +import love.forte.simbot.telegram.stdlib.bot.requestDataBy +import love.forte.simbot.telegram.type.BotCommand +import love.forte.simbot.telegram.type.BotCommandScope + + +/** + * + * @author ForteScarlet + */ +internal class TelegramBotCommandsUpdaterImpl( + private val bot: TelegramBot, + override var scope: BotCommandScope?, + override var languageCode: String?, + override var commands: MutableList = mutableListOf(), +) : TelegramBotCommandsUpdater { + override suspend fun update(): TelegramBotCommands { + val commands = commands.toList() + val scope = scope + val languageCode = languageCode + + val updated = SetMyCommandsApi.create( + commands, + scope, + languageCode + ).requestDataBy(bot.source) + + check(updated) { + "The SetMyCommandsApi request returned `false`" + } + + return commands.toTGCommands( + bot = bot, + scope = scope, + languageCode = languageCode + ) + } +}