allow excluding roles from commands

This commit is contained in:
kageru 2019-06-10 09:19:03 +02:00
parent 1da7800f3d
commit f2ece85d56
Signed by: kageru
GPG Key ID: 8282A2BEA4ADA3D2
4 changed files with 66 additions and 17 deletions

View File

@ -2,7 +2,6 @@ package moe.kageru.kagebot
import moe.kageru.kagebot.Config.Companion.config
import moe.kageru.kagebot.Util.doIf
import moe.kageru.kagebot.Util.ifNotEmpty
import org.javacord.api.entity.message.MessageAuthor
import org.javacord.api.event.message.MessageCreateEvent
@ -12,28 +11,25 @@ class Command(
trigger: String?,
private val response: String?,
matchType: MatchType?,
neededPermissions: Iterable<Long>?,
private val permissions: Permissions?,
private val actions: MessageActions?
) {
val trigger: String = trigger!!
val regex: Regex? = if (matchType == MatchType.REGEX) Regex(trigger!!) else null
val matchType: MatchType = matchType ?: MatchType.PREFIX
private val neededRoles = neededPermissions?.toSet()
constructor(cmd: Command) : this(
cmd.trigger,
cmd.response,
cmd.matchType,
cmd.neededRoles,
cmd.permissions?.let { Permissions(it) },
cmd.actions
)
fun execute(message: MessageCreateEvent) {
neededRoles?.let { roles ->
if (!(message.messageAuthor.isBotOwner || hasOneOf(message.messageAuthor, roles))) {
message.channel.sendMessage(config.localization.permissionDenied)
return
}
if (!(message.messageAuthor.isBotOwner || permissions?.isAllowed(message) != false)) {
message.channel.sendMessage(config.localization.permissionDenied)
return
}
this.actions?.run(message, this)
this.response?.let {
@ -41,12 +37,6 @@ class Command(
}
}
private fun hasOneOf(messageAuthor: MessageAuthor, roles: Set<Long>): Boolean {
return messageAuthor.asUser().ifNotEmpty { user ->
user.getRoles(Config.server).map { it.id }.toSet().intersect(roles).isNotEmpty()
} ?: false
}
fun matches(msg: String) = this.matchType.matches(msg, this)
private fun respond(author: MessageAuthor) = this.response!!.doIf({ it.contains(AUTHOR_PLACEHOLDER) }) {
it.replace(AUTHOR_PLACEHOLDER, MessageUtil.mention(author))
@ -66,3 +56,23 @@ enum class MatchType {
abstract fun matches(message: String, command: Command): Boolean
}
class Permissions(hasOneOf: Iterable<Long>?, hasNoneOf: Iterable<Long>?, private val onlyDM: Boolean) {
private val hasNoneOf = hasNoneOf?.toSet()
private val hasOneOf = hasOneOf?.toSet()
constructor(perms: Permissions) : this(perms.hasOneOf, perms.hasNoneOf, perms.onlyDM)
fun isAllowed(message: MessageCreateEvent): Boolean {
if (onlyDM && !message.isPrivateMessage) {
return false
}
hasOneOf?.let {
if (!Util.hasOneOf(message.messageAuthor, hasOneOf)) return false
}
hasNoneOf?.let {
if (Util.hasOneOf(message.messageAuthor, hasNoneOf)) return false
}
return true
}
}

View File

@ -1,5 +1,6 @@
package moe.kageru.kagebot
import org.javacord.api.entity.message.MessageAuthor
import java.util.*
object Util {
@ -13,4 +14,10 @@ object Util {
}
return null
}
fun hasOneOf(messageAuthor: MessageAuthor, roles: Set<Long>): Boolean {
return messageAuthor.asUser().ifNotEmpty { user ->
user.getRoles(Config.server).map { it.id }.toSet().intersect(roles).isNotEmpty()
} ?: false
}
}

View File

@ -34,12 +34,22 @@ actions = { delete = true }
[[commands]]
trigger = "!restricted"
response = "access granted"
# a user needs *one of* these roles to trigger the command
neededRoles = [
[commands.permissions]
hasOneOf = [
452034011393425409,
446668543816106004
]
[[commands]]
trigger = "!almostUnrestricted"
response = "access granted"
[commands.permissions]
hasNoneOf = [
452034011393425409
]
# redirect every message that starts with !redirect to channel 555097559023222825
[[commands]]
trigger = "!redirect"

View File

@ -67,6 +67,28 @@ class CommandTest : StringSpec({
calls.size shouldBe 1
calls[0] shouldBe "access granted"
}
"should deny command to excluded roles" {
val calls = mutableListOf<String>()
val mockMessage = TestUtil.mockMessage("!almostUnrestricted", capturedCalls = calls)
// with the banned role
every { mockMessage.messageAuthor.asUser() } returns mockk {
every { isPresent } returns true
every { get().getRoles(any()) } returns listOf(
mockk { every { id } returns 452034011393425409 }
)
}
Kagebot.processMessage(mockMessage)
// without the role
every { mockMessage.messageAuthor.asUser() } returns mockk {
every { isPresent } returns true
every { get().getRoles(any()) } returns emptyList()
}
Kagebot.processMessage(mockMessage)
calls.size shouldBe 2
calls[0] shouldBe config.localization.permissionDenied
calls[1] shouldBe "access granted"
}
/*
* This implicitly tests that the message author is not included in anonymous complaints
* because getting the authors name from the mock is undefined.