220 lines
8.7 KiB
Kotlin
220 lines
8.7 KiB
Kotlin
package nl.voidcorp.ottobot.command
|
|
|
|
import net.dv8tion.jda.api.Permission
|
|
import net.dv8tion.jda.api.entities.ChannelType
|
|
import net.dv8tion.jda.api.entities.Member
|
|
import net.dv8tion.jda.api.entities.TextChannel
|
|
import net.dv8tion.jda.api.events.message.MessageReceivedEvent
|
|
import nl.voidcorp.ottobot.commands.HelpCommand
|
|
import nl.voidcorp.ottobot.commands.`fun`.*
|
|
import nl.voidcorp.ottobot.commands.debug.DebugCommand
|
|
import nl.voidcorp.ottobot.commands.debug.Flex
|
|
import nl.voidcorp.ottobot.commands.debug.PermissionLevelCommand
|
|
import nl.voidcorp.ottobot.commands.general.ATQCommand
|
|
import nl.voidcorp.ottobot.commands.general.SpillKerrieCommand
|
|
import nl.voidcorp.ottobot.commands.general.XYProblemCommand
|
|
import nl.voidcorp.ottobot.commands.management.*
|
|
import nl.voidcorp.ottobot.commands.roles.*
|
|
import nl.voidcorp.ottobot.creator
|
|
import nl.voidcorp.ottobot.database.GuildStore
|
|
import nl.voidcorp.ottobot.database.GuildStores
|
|
import org.jetbrains.exposed.sql.transactions.transaction
|
|
import java.util.*
|
|
|
|
|
|
abstract class Command(
|
|
val name: String,
|
|
val helpMesage: String = "",
|
|
val usage: String = "",
|
|
val commandLevel: CommandLevel = CommandLevel.VERIFIED,
|
|
val aliases: List<String> = emptyList(),
|
|
val location: CommandSource = CommandSource.BOTH,
|
|
val group: CommandGroup = CommandGroup.GENERAL,
|
|
val allowAnywhere: Boolean = false
|
|
) {
|
|
|
|
fun getStore(guildId: Long) = transaction {
|
|
GuildStore.find { GuildStores.guildId eq guildId }
|
|
.firstOrNull() ?: GuildStore.new { this.guildId = guildId }
|
|
}
|
|
|
|
fun onCommand(event: MessageReceivedEvent, prefix: String): CommandResult {
|
|
val starts =
|
|
(event.message.contentRaw.drop(prefix.length).trim().split("\\s".toRegex())
|
|
.first() == name) or (aliases.any {
|
|
event.message.contentRaw.drop(prefix.length).trim().split("\\s".toRegex())
|
|
.first() == it
|
|
})
|
|
return if (!starts) CommandResult.NOPE else when (location) {
|
|
CommandSource.PRIVATE -> if (event.channelType == ChannelType.PRIVATE) guildStuff(
|
|
event,
|
|
event.message.contentRaw.drop(prefix.length).trim()
|
|
) else CommandResult.NOPE
|
|
CommandSource.GUILD -> if (event.channelType == ChannelType.TEXT) privateStuff(
|
|
event,
|
|
event.message.contentRaw.drop(prefix.length).trim()
|
|
) else CommandResult.NOPE
|
|
CommandSource.BOTH ->
|
|
if (event.channelType == ChannelType.TEXT) guildStuff(
|
|
event,
|
|
event.message.contentRaw.drop(prefix.length).trim()
|
|
)
|
|
else privateStuff(event, event.message.contentRaw.drop(prefix.length).trim())
|
|
}
|
|
}
|
|
|
|
private fun guildStuff(event: MessageReceivedEvent, str: String) =
|
|
when {
|
|
!(isBotChannel(event.textChannel) or
|
|
isPermOK(CommandLevel.MODERATOR, getLevel(event.member))) -> CommandResult.CHANNEL
|
|
isPermOK(commandLevel, getLevel(event.member)) -> try {
|
|
handle(CommandMessage(event, translateCommandline(str)))
|
|
} catch (e: Exception) {
|
|
e.printStackTrace()
|
|
CommandResult.ERROR
|
|
}
|
|
else -> CommandResult.PERMISSIONS
|
|
}
|
|
|
|
private fun privateStuff(event: MessageReceivedEvent, str: String) =
|
|
if (isPermOK(commandLevel, getLevel(event.member))) try {
|
|
handle(CommandMessage(event, translateCommandline(str)))
|
|
} catch (e: Exception) {
|
|
e.printStackTrace()
|
|
CommandResult.ERROR
|
|
} else {
|
|
CommandResult.PERMISSIONS
|
|
}
|
|
|
|
abstract fun handle(event: CommandMessage): CommandResult
|
|
|
|
fun getLevel(member: Member?): CommandLevel {
|
|
if (member == null) return CommandLevel.ADMIN
|
|
val guildStore = getStore(member.guild.idLong)
|
|
return when {
|
|
member.user.idLong == creator -> CommandLevel.MAINTAINER
|
|
member.hasPermission(Permission.ADMINISTRATOR)
|
|
or transaction {
|
|
guildStore.adminRoles.map { it.adminRoleId }.intersect(member.roles.map { it.idLong }).isNotEmpty()
|
|
}
|
|
-> CommandLevel.ADMIN
|
|
transaction {
|
|
guildStore.moderatorRoles.map { it.moderatorRoleId }.intersect(member.roles.map { it.idLong })
|
|
.isNotEmpty()
|
|
}
|
|
-> CommandLevel.MODERATOR
|
|
member.roles.isNotEmpty() or guildStore.defaultVerified -> CommandLevel.VERIFIED
|
|
else -> CommandLevel.ALL
|
|
}
|
|
}
|
|
|
|
private fun isBotChannel(channel: TextChannel): Boolean {
|
|
val store = getStore(channel.guild.idLong)
|
|
return when {
|
|
allowAnywhere -> true
|
|
transaction { store.botChannels.empty() } and channel.name.contains("bot") -> true
|
|
else -> transaction { store.botChannels.map { it.botchannel }.contains(channel.idLong) }
|
|
}
|
|
}
|
|
|
|
override fun toString(): String {
|
|
return "Command(name=$name, level=$commandLevel, group=$group)"
|
|
}
|
|
|
|
companion object {
|
|
|
|
fun isPermOK(required: CommandLevel, user: CommandLevel): Boolean {
|
|
var test: CommandLevel? = required
|
|
while (test != null) {
|
|
if (test == user) {
|
|
return true
|
|
}
|
|
test = test.parent
|
|
}
|
|
return false
|
|
}
|
|
|
|
/**
|
|
* [code borrowed from ant.jar]
|
|
* Crack a command line.
|
|
* @param toProcess the command line to process.
|
|
* @return the command line broken into strings.
|
|
* An empty or null toProcess parameter results in a zero sized array.
|
|
*/
|
|
private fun translateCommandline(toProcess: String): List<String> {
|
|
if (toProcess.isEmpty()) {
|
|
//no command? no string
|
|
return emptyList()
|
|
}
|
|
// parse with a simple finite state machine
|
|
|
|
val normal = 0
|
|
val inQuote = 1
|
|
val inDoubleQuote = 2
|
|
var state = normal
|
|
val tok = StringTokenizer(toProcess, "\"\' ", true)
|
|
val result = mutableListOf<String>()
|
|
val current = StringBuilder()
|
|
var lastTokenHasBeenQuoted = false
|
|
|
|
while (tok.hasMoreTokens()) {
|
|
val nextTok = tok.nextToken()
|
|
when (state) {
|
|
inQuote -> if ("\'" == nextTok) {
|
|
lastTokenHasBeenQuoted = true
|
|
state = normal
|
|
} else {
|
|
current.append(nextTok)
|
|
}
|
|
inDoubleQuote -> if ("\"" == nextTok) {
|
|
lastTokenHasBeenQuoted = true
|
|
state = normal
|
|
} else {
|
|
current.append(nextTok)
|
|
}
|
|
else -> {
|
|
if ("\'" == nextTok) {
|
|
state = inQuote
|
|
} else if ("\"" == nextTok) {
|
|
state = inDoubleQuote
|
|
} else if (" " == nextTok) {
|
|
if (lastTokenHasBeenQuoted || current.isNotEmpty()) {
|
|
result.add(current.toString())
|
|
current.setLength(0)
|
|
}
|
|
} else {
|
|
current.append(nextTok)
|
|
}
|
|
lastTokenHasBeenQuoted = false
|
|
}
|
|
}
|
|
}
|
|
if (lastTokenHasBeenQuoted || current.isNotEmpty()) {
|
|
result.add(current.toString())
|
|
}
|
|
return result
|
|
}
|
|
|
|
private val debugCommands = setOf(DebugCommand, Flex, PermissionLevelCommand)
|
|
private val funCommands =
|
|
setOf(CatCommand, DogCommand, Echo, Nice, WeatherCommand, WoolooCommand, XKCDComicCommand)
|
|
private val generalCommands = setOf(ATQCommand, SpillKerrieCommand, XYProblemCommand)
|
|
private val managementCommands = setOf(
|
|
AddBotChannelCommand,
|
|
AdminRoleCommand,
|
|
ModeratorRoleCommand,
|
|
RemoveAdminRoleCommand,
|
|
RemoveBotChannelCommand,
|
|
RemoveModeratorRoleCommand,
|
|
SetPrefixCommand,
|
|
SetVerifiedCommand
|
|
)
|
|
private val rolesCommands =
|
|
setOf(AddRoleCommand, JoinRoleCommand, LeaveRole, MoveRoleCommand, RemoveRoleCommand)
|
|
val allCommands =
|
|
setOf<Command>(HelpCommand).union(debugCommands).union(funCommands).union(generalCommands).union(
|
|
managementCommands
|
|
).union(rolesCommands)
|
|
|
|
}
|
|
} |