Skip to content

Commit

Permalink
feat(core): 组件模块下支持 TelegramBotCommandsTelegramBotCommand、`Teleg…
Browse files Browse the repository at this point in the history
…ramBotCommandsUpdater` 等与 bot commands 相关的API
  • Loading branch information
ForteScarlet committed Jul 22, 2024
1 parent c7790e1 commit e7fe507
Show file tree
Hide file tree
Showing 7 changed files with 403 additions and 4 deletions.
2 changes: 1 addition & 1 deletion simbot-component-telegram-api/supports.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@
- [x] [SetWebhookApi](src/commonMain/kotlin/love/forte/simbot/telegram/api/update/SetWebhookApi.kt)
- [user](src/commonMain/kotlin/love/forte/simbot/telegram/api/user)
- [x] [GetUserProfilePhotosApi](src/commonMain/kotlin/love/forte/simbot/telegram/api/user/GetUserProfilePhotosApi.kt)
- [ ] **Others aren’t listed**
- [ ] **Others not listed**
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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()
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.
*/

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<TelegramBotCommand> {
/**
* The list of [TelegramBotCommand]
*/
public val values: List<TelegramBotCommand>

/**
* Iterator of [values].
*/
override fun iterator(): Iterator<TelegramBotCommand> =
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
}


Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.
*/

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<BotCommand>

/**
* @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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.
*/

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<TelegramBotCommand>,
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<BotCommand>.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)
Loading

0 comments on commit e7fe507

Please sign in to comment.