Add builtin Permission command

This commit is contained in:
Him188 2020-09-10 10:44:49 +08:00
parent c76a6dacc9
commit 8dd302073b
6 changed files with 108 additions and 43 deletions

View File

@ -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 <reified E : Throwable, R> ignoreException(block: () -> R): R? {

View File

@ -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<PermissionId> {
override fun parse(raw: String, sender: CommandSender): PermissionId {
return kotlin.runCatching { PermissionId.parseFromString(raw) }.getOrElse {
illegalArgument("无法解析 $raw 为 PermissionId")
}
}
}
@ExperimentalPermission
public object PermissibleIdentifierArgumentParser : CommandArgumentParser<PermissibleIdentifier> {
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<T : Any> : CommandArgumentParser<T> {
fun String.parseToLongOrFail(): Long = toLongOrNull() ?: illegalArgument("无法解析 $this 为整数")

View File

@ -46,6 +46,7 @@ public abstract class AbstractConcurrentPermissionService<P : Permission> : Perm
grantedPermissionsMap[permission.id]?.remove(permissibleIdentifier)
}
override fun getRegisteredPermissions(): Sequence<P> = permissions.values.asSequence()
public override fun getGrantedPermissions(permissibleIdentifier: PermissibleIdentifier): Sequence<P> = sequence<P> {
for ((permissionIdentifier, permissibleIdentifiers) in grantedPermissionsMap) {

View File

@ -37,6 +37,7 @@ public object AllGrantPermissionService : PermissionService<PermissionImpl> {
}
override fun get(id: PermissionId): PermissionImpl? = all[id]
override fun getRegisteredPermissions(): Sequence<PermissionImpl> = all.values.asSequence()
override fun getGrantedPermissions(permissibleIdentifier: PermissibleIdentifier): Sequence<PermissionImpl> =
all.values.asSequence()
@ -68,6 +69,7 @@ public object AllDenyPermissionService : PermissionService<PermissionImpl> {
}
override fun get(id: PermissionId): PermissionImpl? = all[id]
override fun getRegisteredPermissions(): Sequence<PermissionImpl> = all.values.asSequence()
override fun getGrantedPermissions(permissibleIdentifier: PermissibleIdentifier): Sequence<PermissionImpl> =
emptySequence()

View File

@ -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<Pair<Regex, (matchGroup: MatchResult.Destructured) -> AbstractPermissibleIdentifier>> =
internal val regexes: List<Pair<Regex, (matchGroup: MatchResult.Destructured) -> 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<AbstractPermissibleIdentifier> 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) {

View File

@ -28,6 +28,7 @@ public interface PermissionService<P : Permission> {
public operator fun get(id: PermissionId): P?
public fun getRegisteredPermissions(): Sequence<P>
public fun getGrantedPermissions(permissibleIdentifier: PermissibleIdentifier): Sequence<P>
public fun testPermission(permissibleIdentifier: PermissibleIdentifier, permission: P): Boolean {
@ -74,6 +75,18 @@ public interface PermissionService<P : Permission> {
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)