diff --git a/src/main/kotlin/de/darkatra/vrising/discord/commands/ListServersCommand.kt b/src/main/kotlin/de/darkatra/vrising/discord/commands/ListServersCommand.kt index dca4b14..6fbe912 100644 --- a/src/main/kotlin/de/darkatra/vrising/discord/commands/ListServersCommand.kt +++ b/src/main/kotlin/de/darkatra/vrising/discord/commands/ListServersCommand.kt @@ -1,6 +1,9 @@ package de.darkatra.vrising.discord.commands import de.darkatra.vrising.discord.BotProperties +import de.darkatra.vrising.discord.commands.parameters.PageParameter +import de.darkatra.vrising.discord.commands.parameters.addPageParameter +import de.darkatra.vrising.discord.commands.parameters.getPageParameter import de.darkatra.vrising.discord.serverstatus.ServerStatusMonitorRepository import de.darkatra.vrising.discord.serverstatus.model.ServerStatusMonitor import dev.kord.core.Kord @@ -11,6 +14,8 @@ import dev.kord.core.entity.interaction.GuildChatInputCommandInteraction import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.stereotype.Component +private const val PAGE_SIZE = 10 + @Component @EnableConfigurationProperties(BotProperties::class) class ListServersCommand( @@ -30,14 +35,40 @@ class ListServersCommand( ) { dmPermission = true disableCommandInGuilds() + + addPageParameter(required = false) } } override suspend fun handle(interaction: ChatInputCommandInteraction) { + val page = interaction.getPageParameter() ?: 0 + PageParameter.validate(page) + + val totalElements = when (interaction) { + is GuildChatInputCommandInteraction -> serverStatusMonitorRepository.count(interaction.guildId.toString()) + is GlobalChatInputCommandInteraction -> serverStatusMonitorRepository.count() + } + val totalPages = totalElements / PAGE_SIZE + 1 + + if (page >= totalPages) { + interaction.deferEphemeralResponse().respond { + content = "This page does not exist." + } + return + } + val serverStatusMonitors: List = when (interaction) { - is GuildChatInputCommandInteraction -> serverStatusMonitorRepository.getServerStatusMonitors(interaction.guildId.toString()) - is GlobalChatInputCommandInteraction -> serverStatusMonitorRepository.getServerStatusMonitors() + is GuildChatInputCommandInteraction -> serverStatusMonitorRepository.getServerStatusMonitors( + discordServerId = interaction.guildId.toString(), + offset = page * PAGE_SIZE, + limit = PAGE_SIZE + ) + + is GlobalChatInputCommandInteraction -> serverStatusMonitorRepository.getServerStatusMonitors( + offset = page * PAGE_SIZE, + limit = PAGE_SIZE + ) } interaction.deferEphemeralResponse().respond { @@ -45,7 +76,7 @@ class ListServersCommand( true -> "No servers found." false -> serverStatusMonitors.joinToString(separator = "\n") { serverStatusMonitor -> "${serverStatusMonitor.id} - ${serverStatusMonitor.hostname}:${serverStatusMonitor.queryPort} - ${serverStatusMonitor.status.name}" - } + } + "\n*Current Page: $page, Total Pages: $totalPages*" } } } diff --git a/src/main/kotlin/de/darkatra/vrising/discord/commands/parameters/PageParameter.kt b/src/main/kotlin/de/darkatra/vrising/discord/commands/parameters/PageParameter.kt new file mode 100644 index 0000000..f9d4621 --- /dev/null +++ b/src/main/kotlin/de/darkatra/vrising/discord/commands/parameters/PageParameter.kt @@ -0,0 +1,29 @@ +package de.darkatra.vrising.discord.commands.parameters + +import de.darkatra.vrising.discord.commands.exceptions.ValidationException +import dev.kord.core.entity.interaction.ChatInputCommandInteraction +import dev.kord.rest.builder.interaction.GlobalChatInputCreateBuilder +import dev.kord.rest.builder.interaction.integer + +object PageParameter { + const val NAME = "page" + + fun validate(page: Int) { + if (page < 0) { + throw ValidationException("'$NAME' must be greater than or equal to zero. Rejected: $page") + } + } +} + +fun GlobalChatInputCreateBuilder.addPageParameter(required: Boolean = true) { + integer( + name = PageParameter.NAME, + description = "The page. Defaults to 0, the first page." + ) { + this.required = required + } +} + +fun ChatInputCommandInteraction.getPageParameter(): Int? { + return command.integers[PageParameter.NAME]?.let { Math.toIntExact(it) } +} diff --git a/src/main/kotlin/de/darkatra/vrising/discord/serverstatus/ServerStatusMonitorRepository.kt b/src/main/kotlin/de/darkatra/vrising/discord/serverstatus/ServerStatusMonitorRepository.kt index c4fe641..abd90d0 100644 --- a/src/main/kotlin/de/darkatra/vrising/discord/serverstatus/ServerStatusMonitorRepository.kt +++ b/src/main/kotlin/de/darkatra/vrising/discord/serverstatus/ServerStatusMonitorRepository.kt @@ -5,6 +5,7 @@ import de.darkatra.vrising.discord.serverstatus.exceptions.OutdatedServerStatusM import de.darkatra.vrising.discord.serverstatus.model.ServerStatusMonitor import de.darkatra.vrising.discord.serverstatus.model.ServerStatusMonitorStatus import org.dizitart.kno2.filters.and +import org.dizitart.no2.FindOptions import org.dizitart.no2.Nitrite import org.dizitart.no2.objects.ObjectFilter import org.dizitart.no2.objects.filters.ObjectFilters @@ -64,24 +65,51 @@ class ServerStatusMonitorRepository( return repository.find(objectFilter).firstOrNull() } - fun getServerStatusMonitors(discordServerId: String? = null, status: ServerStatusMonitorStatus? = null): List { + fun getServerStatusMonitors( + discordServerId: String? = null, + status: ServerStatusMonitorStatus? = null, + offset: Int? = null, + limit: Int? = null + ): List { - val filters = buildList { + val objectFilter = buildList { if (discordServerId != null) { add(ObjectFilters.eq("discordServerId", discordServerId)) } if (status != null) { add(ObjectFilters.eq("status", status)) } + }.reduceOrNull { acc: ObjectFilter, objectFilter: ObjectFilter -> acc.and(objectFilter) } + + if (offset != null && limit != null) { + + if (offset >= repository.size()) { + return emptyList() + } + + val findOptions = FindOptions.limit(offset, limit) + return when { + objectFilter != null -> repository.find(objectFilter, findOptions).toList() + else -> repository.find(findOptions).toList() + } } - val objectFilter = filters.reduceOrNull { acc: ObjectFilter, objectFilter: ObjectFilter -> acc.and(objectFilter) } return when { objectFilter != null -> repository.find(objectFilter).toList() else -> repository.find().toList() } } + fun count( + discordServerId: String? = null, + ): Int { + + return when { + discordServerId != null -> repository.find(ObjectFilters.eq("discordServerId", discordServerId)).size() + else -> repository.find().size() + } + } + private fun updateVersion(serverStatusMonitor: ServerStatusMonitor): ServerStatusMonitor { return serverStatusMonitor.apply { @Suppress("DEPRECATION") // this is the internal usage the warning is referring to