ottobotv2/src/main/kotlin/nl/voidcorp/discord/command/Command.kt

159 lines
5.9 KiB
Kotlin

package nl.voidcorp.discord.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.events.message.MessageReceivedEvent
import nl.voidcorp.discord.creator
import nl.voidcorp.discord.storage.GuildRepo
import nl.voidcorp.discord.storage.GuildStore
import org.springframework.beans.factory.annotation.Autowired
import java.util.*
abstract class Command(
val name: String,
val helpMesage: String = "",
val usage: String = "",
val commandLevel: CommandLevel = CommandGroup.VERIFIED,
val aliases: List<String> = emptyList(),
val location: CommandSource = CommandSource.BOTH
) {
@Autowired
lateinit var repo: GuildRepo
fun onCommand(event: MessageReceivedEvent, prefix: String): CommandResult {
val starts =
event.message.contentRaw.drop(prefix.length).trim()
.startsWith(name) or aliases.any {
event.message.contentRaw.drop(prefix.length).trim().startsWith(
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) =
if (isPermOK(commandLevel, getLevel(event.member!!))) try {
handle(CommandMessage(event, translateCommandline(str)))
} catch (e: Exception) {
CommandResult.ERROR
} else CommandResult.PERMISSIONS
private fun privateStuff(event: MessageReceivedEvent, str: String) = try {
handle(CommandMessage(event, translateCommandline(str)))
} catch (e: Exception) {
CommandResult.ERROR
}
abstract fun handle(event: CommandMessage): CommandResult
fun getLevel(member: Member): CommandLevel {
val guildStore = repo.findByGuildId(member.guild.idLong) ?: GuildStore(-1)
return when {
member.user.idLong == creator.idLong -> CommandGroup.MAINTAINER
member.hasPermission(Permission.ADMINISTRATOR)
or guildStore.adminRoles.intersect(member.roles.map { it.idLong }).isNotEmpty()
-> CommandGroup.ADMIN
guildStore.moderatorRoles.intersect(member.roles.map { it.idLong }).isNotEmpty()
-> CommandGroup.MODERATOR
member.roles.isNotEmpty() or guildStore.defaultVerified -> CommandGroup.VERIFIED
else -> CommandGroup.UNVERIFIED
}
}
companion object {
var settings = CommandSettings()
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
}
}
}