Skip to content

Commit

Permalink
feat(gh-101): allow admins to use most commands in DMs
Browse files Browse the repository at this point in the history
  • Loading branch information
DarkAtra committed Apr 7, 2024
1 parent 3e30c0a commit 1ce2e62
Show file tree
Hide file tree
Showing 12 changed files with 101 additions and 35 deletions.
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@
</compilerPlugins>
<args>
<arg>-Xjsr305=strict</arg>
<arg>-Xemit-jvm-type-annotations</arg>
</args>
</configuration>
<dependencies>
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/de/darkatra/vrising/discord/Bot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class Bot(

kord.on<ChatInputCommandInteractionCreateEvent> {

val command = commands.find { command -> command.isSupported(interaction) }
val command = commands.find { command -> command.isSupported(interaction, botProperties.adminUserIds) }
if (command == null) {
interaction.deferEphemeralResponse().respond {
content = """This command is not supported here, please refer to the documentation.
Expand Down
4 changes: 4 additions & 0 deletions src/main/kotlin/de/darkatra/vrising/discord/BotProperties.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,9 @@ class BotProperties {
@field:NotNull
var maxCharactersPerError: Int = 200

@field:NotNull
var allowLocalAddressRanges: Boolean = true

@field:NotNull
var adminUserIds: Set<@NotBlank String> = emptySet()
}
11 changes: 4 additions & 7 deletions src/main/kotlin/de/darkatra/vrising/discord/DatabaseUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ package de.darkatra.vrising.discord
import org.dizitart.kno2.filters.and
import org.dizitart.no2.objects.ObjectFilter

operator fun ObjectFilter?.plus(other: ObjectFilter?): ObjectFilter? {
if (this == null && other == null) {
return null
operator fun ObjectFilter.plus(other: ObjectFilter?): ObjectFilter {
if (other == null) {
return this
}
if (this != null && other != null) {
return this.and(other)
}
return this ?: other
return this.and(other)
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import de.darkatra.vrising.discord.serverstatus.model.ServerStatusMonitorStatus
import dev.kord.core.Kord
import dev.kord.core.behavior.interaction.response.respond
import dev.kord.core.entity.interaction.ChatInputCommandInteraction
import dev.kord.core.entity.interaction.GlobalChatInputCommandInteraction
import dev.kord.core.entity.interaction.GuildChatInputCommandInteraction
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.stereotype.Component
Expand Down Expand Up @@ -65,6 +66,13 @@ class AddServerCommand(
}
}

override fun isSupported(interaction: ChatInputCommandInteraction, adminUserIds: Set<String>): Boolean {
if (interaction is GlobalChatInputCommandInteraction) {
return false
}
return super.isSupported(interaction, adminUserIds)
}

override suspend fun handle(interaction: ChatInputCommandInteraction) {

val hostname = interaction.getServerHostnameParameter()!!
Expand Down
13 changes: 11 additions & 2 deletions src/main/kotlin/de/darkatra/vrising/discord/commands/Command.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package de.darkatra.vrising.discord.commands

import dev.kord.core.Kord
import dev.kord.core.entity.interaction.ChatInputCommandInteraction
import dev.kord.core.entity.interaction.GlobalChatInputCommandInteraction
import dev.kord.core.entity.interaction.GuildChatInputCommandInteraction

interface Command {
Expand All @@ -10,8 +11,16 @@ interface Command {

suspend fun register(kord: Kord)

fun isSupported(interaction: ChatInputCommandInteraction): Boolean {
return interaction.invokedCommandName == getCommandName() && !interaction.user.isBot && interaction is GuildChatInputCommandInteraction
fun isSupported(interaction: ChatInputCommandInteraction, adminUserIds: Set<String>): Boolean {

if (interaction.invokedCommandName != getCommandName() || interaction.user.isBot) {
return false
}

return when (interaction) {
is GuildChatInputCommandInteraction -> true
is GlobalChatInputCommandInteraction -> adminUserIds.contains(interaction.user.id.toString())
}
}

suspend fun handle(interaction: ChatInputCommandInteraction)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import de.darkatra.vrising.discord.serverstatus.ServerStatusMonitorRepository
import dev.kord.core.Kord
import dev.kord.core.behavior.interaction.response.respond
import dev.kord.core.entity.interaction.ChatInputCommandInteraction
import dev.kord.core.entity.interaction.GlobalChatInputCommandInteraction
import dev.kord.core.entity.interaction.GuildChatInputCommandInteraction
import dev.kord.rest.builder.message.modify.embed
import org.springframework.boot.context.properties.EnableConfigurationProperties
Expand Down Expand Up @@ -41,9 +42,12 @@ class GetServerDetailsCommand(
override suspend fun handle(interaction: ChatInputCommandInteraction) {

val serverStatusMonitorId = interaction.getServerStatusMonitorIdParameter()
val discordServerId = (interaction as GuildChatInputCommandInteraction).guildId

val serverStatusMonitor = serverStatusMonitorRepository.getServerStatusMonitor(serverStatusMonitorId, discordServerId.toString())
val serverStatusMonitor = when (interaction) {
is GuildChatInputCommandInteraction -> serverStatusMonitorRepository.getServerStatusMonitor(serverStatusMonitorId, interaction.guildId.toString())
is GlobalChatInputCommandInteraction -> serverStatusMonitorRepository.getServerStatusMonitor(serverStatusMonitorId)
}

if (serverStatusMonitor == null) {
interaction.deferEphemeralResponse().respond {
content = "No server with id '$serverStatusMonitorId' was found."
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
package de.darkatra.vrising.discord.commands

import de.darkatra.vrising.discord.BotProperties
import de.darkatra.vrising.discord.serverstatus.ServerStatusMonitorRepository
import de.darkatra.vrising.discord.serverstatus.model.ServerStatusMonitor
import dev.kord.core.Kord
import dev.kord.core.behavior.interaction.response.respond
import dev.kord.core.entity.interaction.ChatInputCommandInteraction
import dev.kord.core.entity.interaction.GlobalChatInputCommandInteraction
import dev.kord.core.entity.interaction.GuildChatInputCommandInteraction
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.stereotype.Component

@Component
@EnableConfigurationProperties(BotProperties::class)
class ListServersCommand(
private val serverStatusMonitorRepository: ServerStatusMonitorRepository,
private val serverStatusMonitorRepository: ServerStatusMonitorRepository
) : Command {

private val name: String = "list-servers"
Expand All @@ -30,15 +35,16 @@ class ListServersCommand(

override suspend fun handle(interaction: ChatInputCommandInteraction) {

val discordServerId = (interaction as GuildChatInputCommandInteraction).guildId

val serverStatusConfigurations = serverStatusMonitorRepository.getServerStatusMonitors(discordServerId.toString())
val serverStatusMonitors: List<ServerStatusMonitor> = when (interaction) {
is GuildChatInputCommandInteraction -> serverStatusMonitorRepository.getServerStatusMonitors(interaction.guildId.toString())
is GlobalChatInputCommandInteraction -> serverStatusMonitorRepository.getServerStatusMonitors()
}

interaction.deferEphemeralResponse().respond {
content = when (serverStatusConfigurations.isEmpty()) {
content = when (serverStatusMonitors.isEmpty()) {
true -> "No servers found."
false -> serverStatusConfigurations.joinToString(separator = "\n") { serverStatusConfiguration ->
"${serverStatusConfiguration.id} - ${serverStatusConfiguration.hostname}:${serverStatusConfiguration.queryPort} - ${serverStatusConfiguration.status.name}"
false -> serverStatusMonitors.joinToString(separator = "\n") { serverStatusMonitor ->
"${serverStatusMonitor.id} - ${serverStatusMonitor.hostname}:${serverStatusMonitor.queryPort} - ${serverStatusMonitor.status.name}"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import de.darkatra.vrising.discord.serverstatus.ServerStatusMonitorRepository
import dev.kord.core.Kord
import dev.kord.core.behavior.interaction.response.respond
import dev.kord.core.entity.interaction.ChatInputCommandInteraction
import dev.kord.core.entity.interaction.GlobalChatInputCommandInteraction
import dev.kord.core.entity.interaction.GuildChatInputCommandInteraction
import org.springframework.stereotype.Component

@Component
class RemoveServerCommand(
private val serverStatusMonitorRepository: ServerStatusMonitorRepository,
private val serverStatusMonitorRepository: ServerStatusMonitorRepository
) : Command {

private val name: String = "remove-server"
Expand All @@ -35,9 +36,15 @@ class RemoveServerCommand(
override suspend fun handle(interaction: ChatInputCommandInteraction) {

val serverStatusMonitorId = interaction.getServerStatusMonitorIdParameter()
val discordServerId = (interaction as GuildChatInputCommandInteraction).guildId

val wasSuccessful = serverStatusMonitorRepository.removeServerStatusMonitor(serverStatusMonitorId, discordServerId.toString())
val wasSuccessful = when (interaction) {
is GuildChatInputCommandInteraction -> serverStatusMonitorRepository.removeServerStatusMonitor(
serverStatusMonitorId,
interaction.guildId.toString()
)

is GlobalChatInputCommandInteraction -> serverStatusMonitorRepository.removeServerStatusMonitor(serverStatusMonitorId)
}

interaction.deferEphemeralResponse().respond {
content = when (wasSuccessful) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import de.darkatra.vrising.discord.serverstatus.ServerStatusMonitorRepository
import dev.kord.core.Kord
import dev.kord.core.behavior.interaction.response.respond
import dev.kord.core.entity.interaction.ChatInputCommandInteraction
import dev.kord.core.entity.interaction.GlobalChatInputCommandInteraction
import dev.kord.core.entity.interaction.GuildChatInputCommandInteraction
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.stereotype.Component
Expand Down Expand Up @@ -83,9 +84,11 @@ class UpdateServerCommand(
val playerActivityFeedChannelId = interaction.getPlayerActivityFeedChannelIdParameter()
val pvpKillFeedChannelId = interaction.getPvpKillFeedChannelIdParameter()

val discordServerId = (interaction as GuildChatInputCommandInteraction).guildId
val serverStatusMonitor = when (interaction) {
is GuildChatInputCommandInteraction -> serverStatusMonitorRepository.getServerStatusMonitor(serverStatusMonitorId, interaction.guildId.toString())
is GlobalChatInputCommandInteraction -> serverStatusMonitorRepository.getServerStatusMonitor(serverStatusMonitorId)
}

val serverStatusMonitor = serverStatusMonitorRepository.getServerStatusMonitor(serverStatusMonitorId, discordServerId.toString())
if (serverStatusMonitor == null) {
interaction.deferEphemeralResponse().respond {
content = "No server with id '$serverStatusMonitorId' was found."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,39 @@ class ServerStatusMonitorRepository(
repository.update(updateVersion(serverStatusMonitor))
}

fun removeServerStatusMonitor(id: String, discordServerId: String): Boolean {
return repository.remove(ObjectFilters.eq("id", id).and(ObjectFilters.eq("discordServerId", discordServerId))).affectedCount > 0
}
fun removeServerStatusMonitor(id: String, discordServerId: String? = null): Boolean {
var objectFilter: ObjectFilter = ObjectFilters.eq("id", id)

fun getServerStatusMonitor(id: String, discordServerId: String): ServerStatusMonitor? {
return repository.find(ObjectFilters.eq("id", id).and(ObjectFilters.eq("discordServerId", discordServerId))).firstOrNull()
if (discordServerId != null) {
objectFilter += ObjectFilters.eq("discordServerId", discordServerId)
}

return repository.remove(objectFilter).affectedCount > 0
}

fun getServerStatusMonitors(discordServerId: String? = null, status: ServerStatusMonitorStatus? = null): List<ServerStatusMonitor> {
fun getServerStatusMonitor(id: String, discordServerId: String? = null): ServerStatusMonitor? {

var objectFilter: ObjectFilter? = null
var objectFilter: ObjectFilter = ObjectFilters.eq("id", id)

// apply filters
if (discordServerId != null) {
objectFilter = ObjectFilters.eq("discordServerId", discordServerId)
objectFilter += ObjectFilters.eq("discordServerId", discordServerId)
}
if (status != null) {
objectFilter += ObjectFilters.eq("status", status)

return repository.find(objectFilter).firstOrNull()
}

fun getServerStatusMonitors(discordServerId: String? = null, status: ServerStatusMonitorStatus? = null): List<ServerStatusMonitor> {

val filters = buildList<ObjectFilter> {
if (discordServerId != null) {
add(ObjectFilters.eq("discordServerId", discordServerId))
}
if (status != null) {
add(ObjectFilters.eq("status", status))
}
}

val objectFilter = filters.reduceOrNull { acc: ObjectFilter, objectFilter: ObjectFilter -> acc.and(objectFilter) }
return when {
objectFilter != null -> repository.find(objectFilter).toList()
else -> repository.find().toList()
Expand Down
14 changes: 14 additions & 0 deletions src/test/kotlin/de/darkatra/vrising/discord/BotPropertiesTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,19 @@ class BotPropertiesTest {
assertThat(result).hasSize(1)
}

@ParameterizedTest
@ValueSource(strings = ["", " ", "\t"])
fun `should be invalid if adminUserIds contains blank string`(adminUserId: String) {

val botProperties = getValidBotProperties().apply {
this.adminUserIds = setOf(adminUserId)
}

val result = validator.validate(botProperties)

assertThat(result).hasSize(1)
}

private fun getValidBotProperties(): BotProperties {
return BotProperties().apply {
discordBotToken = "discord-token"
Expand All @@ -94,6 +107,7 @@ class BotPropertiesTest {
databasePassword = "password"
updateDelay = Duration.ofSeconds(30)
maxFailedAttempts = 5
adminUserIds = setOf("test-admin-id")
}
}
}

0 comments on commit 1ce2e62

Please sign in to comment.