diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/BuiltInCommands.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/BuiltInCommands.kt index 2693c59ef..8f1a28139 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/BuiltInCommands.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/BuiltInCommands.kt @@ -16,17 +16,23 @@ import net.mamoe.mirai.Bot import net.mamoe.mirai.alsoLogin import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register +import net.mamoe.mirai.console.command.description.PermissibleIdentifierArgumentParser +import net.mamoe.mirai.console.command.description.PermissionIdArgumentParser +import net.mamoe.mirai.console.command.description.buildCommandArgumentContext import net.mamoe.mirai.console.internal.command.CommandManagerImpl import net.mamoe.mirai.console.internal.command.CommandManagerImpl.allRegisteredCommands import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip -import net.mamoe.mirai.console.util.BotManager.INSTANCE.addManager -import net.mamoe.mirai.console.util.BotManager.INSTANCE.managers -import net.mamoe.mirai.console.util.BotManager.INSTANCE.removeManager +import net.mamoe.mirai.console.permission.ExperimentalPermission +import net.mamoe.mirai.console.permission.PermissibleIdentifier +import net.mamoe.mirai.console.permission.PermissionId +import net.mamoe.mirai.console.permission.PermissionService +import net.mamoe.mirai.console.permission.PermissionService.Companion.denyPermission +import net.mamoe.mirai.console.permission.PermissionService.Companion.getGrantedPermissions +import net.mamoe.mirai.console.permission.PermissionService.Companion.grantPermission import net.mamoe.mirai.console.util.ConsoleExperimentalAPI import net.mamoe.mirai.console.util.ConsoleInternalAPI import net.mamoe.mirai.contact.* import net.mamoe.mirai.event.events.EventCancelledException -import net.mamoe.mirai.getFriendOrNull import net.mamoe.mirai.message.nextMessageOrNull import net.mamoe.mirai.utils.secondsToMillis import kotlin.concurrent.thread @@ -57,30 +63,6 @@ public object BuiltInCommands { } } - public object Managers : CompositeCommand( - ConsoleCommandOwner, "managers", - description = "Manage the managers for each bot" - ), BuiltInCommand { - @SubCommand - public suspend fun CommandSender.add(target: User) { - target.bot.addManager(target.id) - sendMessage("已成功添加 ${target.render()} 为 ${target.bot.render()} 的管理员") - } - - @SubCommand - public suspend fun CommandSender.remove(target: User) { - target.bot.removeManager(target.id) - sendMessage("已成功取消 ${target.render()} 对 ${target.bot.render()} 的管理员权限") - } - - @SubCommand - public suspend fun CommandSender.list(bot: Bot) { - sendMessage("$bot 的管理员列表:\n" + bot.managers.joinToString("\n") { - bot.getFriendOrNull(it)?.render() ?: it.toString() - }) - } - } - public object Help : SimpleCommand( ConsoleCommandOwner, "help", description = "Command list" @@ -136,7 +118,7 @@ public object BuiltInCommands { } public object Login : SimpleCommand( - ConsoleCommandOwner, "login", + ConsoleCommandOwner, "login", "登录", description = "Log in a bot account." ), BuiltInCommand { @Handler @@ -161,6 +143,40 @@ public object BuiltInCommands { ) } } + + @OptIn(ExperimentalPermission::class) + public object Permission : CompositeCommand( + ConsoleCommandOwner, "permission", "权限", + description = "Manage permissions", + overrideContext = buildCommandArgumentContext { + PermissibleIdentifier::class with PermissibleIdentifierArgumentParser + PermissionId::class with PermissionIdArgumentParser + } + ), BuiltInCommand { + // TODO: 2020/9/10 improve Permission command + @SubCommand + public suspend fun CommandSender.grant(target: PermissibleIdentifier, permission: PermissionId) { + target.grantPermission(permission) + sendMessage("OK") + } + + @SubCommand + public suspend fun CommandSender.deny(target: PermissibleIdentifier, permission: PermissionId) { + target.denyPermission(permission) + sendMessage("OK") + } + + @SubCommand("grantedPermissions", "gp") + public suspend fun CommandSender.grantedPermissions(target: PermissibleIdentifier) { + val grantedPermissions = target.getGrantedPermissions() + sendMessage(grantedPermissions.joinToString("\n") { it.id.toString() }) + } + + @SubCommand("listPermissions", "lp") + public suspend fun CommandSender.listPermissions() { + sendMessage(PermissionService.INSTANCE.getRegisteredPermissions().joinToString("\n") { it.id.toString() }) + } + } } internal inline fun ignoreException(block: () -> R): R? { diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/description/CommandArgumentParserBuiltins.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/description/CommandArgumentParserBuiltins.kt index a72d00f9d..e43b9a190 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/description/CommandArgumentParserBuiltins.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/description/CommandArgumentParserBuiltins.kt @@ -11,7 +11,12 @@ package net.mamoe.mirai.console.command.description import net.mamoe.mirai.Bot import net.mamoe.mirai.console.command.* +import net.mamoe.mirai.console.command.CommandSender.Companion.asCommandSender import net.mamoe.mirai.console.internal.command.fuzzySearchMember +import net.mamoe.mirai.console.permission.AbstractPermissibleIdentifier +import net.mamoe.mirai.console.permission.ExperimentalPermission +import net.mamoe.mirai.console.permission.PermissibleIdentifier +import net.mamoe.mirai.console.permission.PermissionId import net.mamoe.mirai.contact.* import net.mamoe.mirai.getFriendOrNull import net.mamoe.mirai.getGroupOrNull @@ -303,6 +308,31 @@ public object ExistingMemberArgumentParser : InternalCommandArgumentParserExtens } } +@ExperimentalPermission +public object PermissionIdArgumentParser : CommandArgumentParser { + override fun parse(raw: String, sender: CommandSender): PermissionId { + return kotlin.runCatching { PermissionId.parseFromString(raw) }.getOrElse { + illegalArgument("无法解析 $raw 为 PermissionId") + } + } +} + +@ExperimentalPermission +public object PermissibleIdentifierArgumentParser : CommandArgumentParser { + override fun parse(raw: String, sender: CommandSender): PermissibleIdentifier { + return kotlin.runCatching { AbstractPermissibleIdentifier.parseFromString(raw) }.getOrElse { + illegalArgument("无法解析 $raw 为 PermissionId") + } + } + + override fun parse(raw: MessageContent, sender: CommandSender): PermissibleIdentifier { + if (raw is At) { + return ExistingUserArgumentParser.parse(raw, sender).asCommandSender(false).identifier + } + return super.parse(raw, sender) + } +} + internal interface InternalCommandArgumentParserExtensions : CommandArgumentParser { fun String.parseToLongOrFail(): Long = toLongOrNull() ?: illegalArgument("无法解析 $this 为整数") diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/AbstractConcurrentPermissionService.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/AbstractConcurrentPermissionService.kt index f76a769ef..12baee7b6 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/AbstractConcurrentPermissionService.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/AbstractConcurrentPermissionService.kt @@ -46,6 +46,7 @@ public abstract class AbstractConcurrentPermissionService

: Perm grantedPermissionsMap[permission.id]?.remove(permissibleIdentifier) } + override fun getRegisteredPermissions(): Sequence

= permissions.values.asSequence() public override fun getGrantedPermissions(permissibleIdentifier: PermissibleIdentifier): Sequence

= sequence

{ for ((permissionIdentifier, permissibleIdentifiers) in grantedPermissionsMap) { diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/BuiltInPermissionServices.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/BuiltInPermissionServices.kt index 9a7279545..de50373cb 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/BuiltInPermissionServices.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/BuiltInPermissionServices.kt @@ -37,6 +37,7 @@ public object AllGrantPermissionService : PermissionService { } override fun get(id: PermissionId): PermissionImpl? = all[id] + override fun getRegisteredPermissions(): Sequence = all.values.asSequence() override fun getGrantedPermissions(permissibleIdentifier: PermissibleIdentifier): Sequence = all.values.asSequence() @@ -68,6 +69,7 @@ public object AllDenyPermissionService : PermissionService { } override fun get(id: PermissionId): PermissionImpl? = all[id] + override fun getRegisteredPermissions(): Sequence = all.values.asSequence() override fun getGrantedPermissions(permissibleIdentifier: PermissibleIdentifier): Sequence = emptySequence() diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissibleIdentifier.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissibleIdentifier.kt index 544175a37..e65719740 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissibleIdentifier.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissibleIdentifier.kt @@ -43,13 +43,26 @@ public interface PermissibleIdentifier { public sealed class AbstractPermissibleIdentifier( public final override vararg val parents: PermissibleIdentifier ) : PermissibleIdentifier { - internal companion object { - val objects by lazy { + public companion object { + @JvmStatic + public fun parseFromString(string: String): AbstractPermissibleIdentifier { + val str = string.trim() + objects.find { it.toString() == str }?.let { return it as AbstractPermissibleIdentifier } + for ((regex, block) in regexes) { + val result = regex.find(str) ?: continue + if (result.range.last != str.lastIndex) continue + if (result.range.first != 0) continue + return result.destructured.run(block) + } + error("Cannot deserialize '$str' as AbstractPermissibleIdentifier") + } + + internal val objects by lazy { // https://youtrack.jetbrains.com/issue/KT-41782 AbstractPermissibleIdentifier::class.nestedClasses.mapNotNull { it.objectInstance } } - val regexes: List AbstractPermissibleIdentifier>> = + internal val regexes: List AbstractPermissibleIdentifier>> = listOf( Regex("""ExactGroup\(\s*([0-9]+)\s*\)""") to { (id) -> ExactGroup(id.toLong()) }, Regex("""ExactFriend\(\s*([0-9]+)\s*\)""") to { (id) -> ExactFriend(id.toLong()) }, @@ -69,17 +82,7 @@ public sealed class AbstractPermissibleIdentifier( public object AsStringSerializer : KSerializer by String.serializer().map( serializer = { it.toString() }, - deserializer = d@{ str -> - @Suppress("NAME_SHADOWING") val str = str.trim() - objects.find { it.toString() == str }?.let { return@d it as AbstractPermissibleIdentifier } - for ((regex, block) in regexes) { - val result = regex.find(str) ?: continue - if (result.range.last != str.lastIndex) continue - if (result.range.first != 0) continue - return@d result.destructured.run(block) - } - error("Cannot deserialize '$str' as AbstractPermissibleIdentifier") - } + deserializer = d@{ str -> parseFromString(str) } ) public object AnyGroup : AbstractPermissibleIdentifier(AnyContact) { diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionService.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionService.kt index d517392bf..42e30cb20 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionService.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionService.kt @@ -28,6 +28,7 @@ public interface PermissionService

{ public operator fun get(id: PermissionId): P? + public fun getRegisteredPermissions(): Sequence

public fun getGrantedPermissions(permissibleIdentifier: PermissibleIdentifier): Sequence

public fun testPermission(permissibleIdentifier: PermissibleIdentifier, permission: P): Boolean { @@ -74,6 +75,18 @@ public interface PermissionService

{ INSTANCE.checkType(permission::class).grant(this, permission) } + public fun PermissibleIdentifier.grantPermission(permissionId: PermissionId) { + grantPermission(permissionId.findCorrespondingPermissionOrFail()) + } + + public fun PermissibleIdentifier.denyPermission(permission: Permission) { + INSTANCE.checkType(permission::class).deny(this, permission) + } + + public fun PermissibleIdentifier.denyPermission(permissionId: PermissionId) { + denyPermission(permissionId.findCorrespondingPermissionOrFail()) + } + public fun Permissible.hasPermission(permission: Permission): Boolean = permission.testPermission(this@hasPermission)