diff --git a/docs b/docs index 75b1a97..bf0470f 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 75b1a9735ba768d9e64a8d1bd87f1cd93a85f23e +Subproject commit bf0470f2fee8865a3e9df7059b4b09dc7fcaab1c diff --git a/gradle.properties b/gradle.properties index 79674a2..86fd0e2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ kotlin.code.style=official -libVersion=2.6.8 +libVersion=2.6.9 #systemProp.http.proxyHost=127.0.0.1 #systemProp.http.proxyPort=12334 diff --git a/ronebot-common/src/main/kotlin/cn/rtast/rob/command/ICommandSource.kt b/ronebot-common/src/main/kotlin/cn/rtast/rob/command/ICommandSource.kt index e3d696a..789179e 100644 --- a/ronebot-common/src/main/kotlin/cn/rtast/rob/command/ICommandSource.kt +++ b/ronebot-common/src/main/kotlin/cn/rtast/rob/command/ICommandSource.kt @@ -8,6 +8,7 @@ package cn.rtast.rob.command import cn.rtast.rob.BaseBotInstance +import cn.rtast.rob.entity.IFiredUser import cn.rtast.rob.entity.IGroupMessage import cn.rtast.rob.entity.IMessage import cn.rtast.rob.entity.IPrivateMessage @@ -41,4 +42,9 @@ interface ICommandSource { * 私聊消息(可能为空) */ val privateMessage: IPrivateMessage? + + /** + * 触发命令的用户 + */ + val firedUser: IFiredUser } \ No newline at end of file diff --git a/ronebot-common/src/main/kotlin/cn/rtast/rob/entity/IFiredUser.kt b/ronebot-common/src/main/kotlin/cn/rtast/rob/entity/IFiredUser.kt new file mode 100644 index 0000000..b7eb67e --- /dev/null +++ b/ronebot-common/src/main/kotlin/cn/rtast/rob/entity/IFiredUser.kt @@ -0,0 +1,15 @@ +/* + * Copyright © 2025 RTAkland + * Author: RTAkland + * Date: 2025/1/29 + */ + + +package cn.rtast.rob.entity + +/** + * 权限管理中触发命令的用户 + */ +interface IFiredUser { + val id: String +} \ No newline at end of file diff --git a/ronebot-onebot-v11/src/main/kotlin/cn/rtast/rob/entity/FiredUser.kt b/ronebot-onebot-v11/src/main/kotlin/cn/rtast/rob/entity/FiredUser.kt new file mode 100644 index 0000000..35feb29 --- /dev/null +++ b/ronebot-onebot-v11/src/main/kotlin/cn/rtast/rob/entity/FiredUser.kt @@ -0,0 +1,14 @@ +/* + * Copyright © 2025 RTAkland + * Author: RTAkland + * Date: 2025/1/29 + */ + + +package cn.rtast.rob.entity + +data class FiredUser( + override val id: String, + val isGroup: Boolean, + val groupId: Long? +) : IFiredUser \ No newline at end of file diff --git a/ronebot-onebot-v11/src/main/kotlin/cn/rtast/rob/util/BrigadierCommandManagerImpl.kt b/ronebot-onebot-v11/src/main/kotlin/cn/rtast/rob/util/BrigadierCommandManagerImpl.kt index aa7d946..0c1dbcc 100644 --- a/ronebot-onebot-v11/src/main/kotlin/cn/rtast/rob/util/BrigadierCommandManagerImpl.kt +++ b/ronebot-onebot-v11/src/main/kotlin/cn/rtast/rob/util/BrigadierCommandManagerImpl.kt @@ -9,6 +9,7 @@ package cn.rtast.rob.util import cn.rtast.rob.BotInstance import cn.rtast.rob.command.BrigadierCommandManager +import cn.rtast.rob.entity.FiredUser import cn.rtast.rob.entity.GroupMessage import cn.rtast.rob.entity.IMessage import cn.rtast.rob.entity.PrivateMessage @@ -42,7 +43,8 @@ class BrigadierCommandManagerImpl internal constructor( message, messageType, message as GroupMessage, - null + null, + FiredUser(message.sender.userId.toString(), true, message.groupId) ) BrigadierMessageType.Private -> CommandSource( @@ -50,7 +52,8 @@ class BrigadierCommandManagerImpl internal constructor( message, messageType, null, - message as PrivateMessage + message as PrivateMessage, + FiredUser(message.sender.userId.toString(), false, null), ) } dispatcher.execute(command, context) diff --git a/ronebot-onebot-v11/src/main/kotlin/cn/rtast/rob/util/CommandSource.kt b/ronebot-onebot-v11/src/main/kotlin/cn/rtast/rob/util/CommandSource.kt index be08ed8..4ccbcdc 100644 --- a/ronebot-onebot-v11/src/main/kotlin/cn/rtast/rob/util/CommandSource.kt +++ b/ronebot-onebot-v11/src/main/kotlin/cn/rtast/rob/util/CommandSource.kt @@ -9,6 +9,7 @@ package cn.rtast.rob.util import cn.rtast.rob.BotInstance import cn.rtast.rob.command.ICommandSource +import cn.rtast.rob.entity.IFiredUser import cn.rtast.rob.entity.GroupMessage import cn.rtast.rob.entity.IMessage import cn.rtast.rob.entity.PrivateMessage @@ -22,5 +23,6 @@ data class CommandSource( override val message: IMessage, override val messageType: BrigadierMessageType, override val groupMessage: GroupMessage?, - override val privateMessage: PrivateMessage? + override val privateMessage: PrivateMessage?, + override val firedUser: IFiredUser ) : ICommandSource \ No newline at end of file diff --git a/ronebot-onebot-v11/src/test/kotlin/test/TestClient.kt b/ronebot-onebot-v11/src/test/kotlin/test/TestClient.kt index 65a9d4c..fc19f85 100644 --- a/ronebot-onebot-v11/src/test/kotlin/test/TestClient.kt +++ b/ronebot-onebot-v11/src/test/kotlin/test/TestClient.kt @@ -16,6 +16,9 @@ import cn.rtast.rob.entity.custom.ErrorEvent import cn.rtast.rob.enums.QQFace import cn.rtast.rob.onebot.OneBotListener import cn.rtast.rob.onebot.sdl.messageChain +import cn.rtast.rob.permission.enums.BasicPermission +import cn.rtast.rob.permission.getPermissionManager +import cn.rtast.rob.permission.hasPermission import cn.rtast.rob.segment.Text import cn.rtast.rob.util.BaseCommand import cn.rtast.rob.util.BrigadierCommand @@ -58,6 +61,7 @@ class TestBrigadierCommand : BrigadierCommand() { override fun register(dispatcher: CommandDispatcher) { val root = LiteralArgumentBuilder.literal("/foo") + .requires { it.hasPermission(BasicPermission.Admin) } .then( RequiredArgumentBuilder.argument("bar", StringArgumentType.string()) .executes { @@ -117,9 +121,21 @@ suspend fun main() { println(this) } instance1.addListeningGroup(985927054) + ROneBotFactory.getPermissionManager().apply { +// setUserPermissionLevel(3458671395.toString(), BasicPermission.User) +// setUserPermission(3458671395.toString(), BasicPermission.User) +// setUserPermission(3458671395.toString(), "command.test.main") + // 只要大于3就拥有所有权限, 所有权限指的是BasicPermission和Int level的所有权限 + // 权限节点需要单独配置 + setUserPermission(3458671395.toString(), 114514) + + } ROneBotFactory.brigadierCommandManager.register(TestBrigadierCommand()) ROneBotFactory.brigadierCommandManager.register( Commands.literal("main") +// .requires { it.hasPermission(BasicPermission.Admin) } +// .requires { it.hasPermission("command.test.main") } + .requires { it.hasPermission(114514) } .then( Commands.argument("test", CharArgumentType.char()) .executes { diff --git a/ronebot-permission/build.gradle.kts b/ronebot-permission/build.gradle.kts new file mode 100644 index 0000000..00656d8 --- /dev/null +++ b/ronebot-permission/build.gradle.kts @@ -0,0 +1,3 @@ +dependencies { + api(project(":ronebot-common")) +} \ No newline at end of file diff --git a/ronebot-permission/src/main/kotlin/cn/rtast/rob/permission/Permission.kt b/ronebot-permission/src/main/kotlin/cn/rtast/rob/permission/Permission.kt new file mode 100644 index 0000000..77d40e2 --- /dev/null +++ b/ronebot-permission/src/main/kotlin/cn/rtast/rob/permission/Permission.kt @@ -0,0 +1,34 @@ +/* + * Copyright © 2025 RTAkland + * Author: RTAkland + * Date: 2025/1/29 + */ + +@file:Suppress("unused") + +package cn.rtast.rob.permission + +import cn.rtast.rob.command.ICommandSource +import cn.rtast.rob.permission.enums.BasicPermission + + +/** + * 使用权限等级[Int]来判断是否有权限 + */ +fun T.hasPermission(level: Int): Boolean { + return permissionManager.hasPermission(this.firedUser.id, BasicPermission.fromLevel(level)) +} + +/** + * 使用权限等级[BasicPermission]来判断是否有权限 + */ +fun T.hasPermission(permission: BasicPermission): Boolean { + return permissionManager.hasPermission(this.firedUser.id, permission) +} + +/** + * 使用权限节点等级[String]来判断是否有权限 + */ +fun T.hasPermission(permNode: String): Boolean { + return permissionManager.hasPermission(this.firedUser.id, permNode) +} diff --git a/ronebot-permission/src/main/kotlin/cn/rtast/rob/permission/PermissionManager.kt b/ronebot-permission/src/main/kotlin/cn/rtast/rob/permission/PermissionManager.kt new file mode 100644 index 0000000..d2c4a37 --- /dev/null +++ b/ronebot-permission/src/main/kotlin/cn/rtast/rob/permission/PermissionManager.kt @@ -0,0 +1,64 @@ +/* + * Copyright © 2025 RTAkland + * Author: RTAkland + * Date: 2025/1/29 + */ + +@file:Suppress("unused") + +package cn.rtast.rob.permission + +import cn.rtast.rob.BotFactory +import cn.rtast.rob.permission.enums.BasicPermission + +fun T.getPermissionManager() = permissionManager + +val permissionManager by lazy { PermissionManager() } + +class PermissionManager { + + private val userPermissions: MutableMap = mutableMapOf() + private val userPermissionNodes: MutableMap> = mutableMapOf() + + /** + * 使用内置的[BasicPermission]枚举类来确定一个用户的权限 + */ + fun setUserPermission(userId: String, permission: BasicPermission) { + userPermissions[userId] = permission + } + + /** + * 通过权限节点来确定用户权限 + */ + fun setUserPermission(userId: String, permissionNode: String) { + userPermissionNodes.computeIfAbsent(userId) { mutableSetOf() }.add(permissionNode) + } + + /** + * 通过权限等级来确定用户权限 + */ + fun setUserPermission(userId: String, level: Int) { + userPermissions[userId] = BasicPermission.fromLevel(level) + } + + /** + * 通过内置的[BasicPermission]判断是否拥有权限 + */ + internal fun hasPermission(userId: String, requiredPermission: BasicPermission): Boolean { + val userPermission = userPermissions[userId] ?: BasicPermission.Other + if (userPermission == BasicPermission.Owner) { + return true + } + return userPermission.level >= requiredPermission.level + } + /** + * 通过权限节点判断是否拥有权限 + */ + internal fun hasPermission(userId: String, permissionNode: String): Boolean { + val userPermission = userPermissions[userId] ?: BasicPermission.Other + if (userPermission == BasicPermission.Owner) { + return true + } + return userPermissionNodes[userId]?.contains(permissionNode) == true + } +} \ No newline at end of file diff --git a/ronebot-permission/src/main/kotlin/cn/rtast/rob/permission/enums/BasicPermission.kt b/ronebot-permission/src/main/kotlin/cn/rtast/rob/permission/enums/BasicPermission.kt new file mode 100644 index 0000000..7d863d4 --- /dev/null +++ b/ronebot-permission/src/main/kotlin/cn/rtast/rob/permission/enums/BasicPermission.kt @@ -0,0 +1,27 @@ +/* + * Copyright © 2025 RTAkland + * Author: RTAkland + * Date: 2025/1/29 + */ + +@file:Suppress("unused") + +package cn.rtast.rob.permission.enums + +/** + * 内置的基本权限 + */ +enum class BasicPermission(val level: Int) { + Owner(3), Admin(2), User(1), Other(0); + + companion object { + fun fromLevel(level: Int): BasicPermission { + return when { + level > 3 -> Owner + level == 2 -> Admin + level == 1 -> User + else -> Other + } + } + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 4241512..b0a18f3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,3 +4,4 @@ include(":ronebot-common-ext") include(":ronebot-onebot-v11") include(":ronebot-satori") include(":ronebot-qqbot-webhook") +include(":ronebot-permission")