From f6b653ca23a424ee437c7edf0e5717b0d4700213 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Thu, 8 Jul 2021 20:28:48 +0200 Subject: [PATCH 01/16] Start on swapping out JDA for Discord4j --- build.gradle.kts | 13 ++++++++++--- .../com/dunctebot/dashboard/Container.kt | 4 ++-- ...{JDARestClient.kt => DiscordRestClient.kt} | 19 ++++++++++++++++++- src/main/kotlin/com/dunctebot/jda/FakeJDA.kt | 2 +- 4 files changed, 31 insertions(+), 7 deletions(-) rename src/main/kotlin/com/dunctebot/jda/{JDARestClient.kt => DiscordRestClient.kt} (89%) diff --git a/build.gradle.kts b/build.gradle.kts index ce93151..07ed006 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -35,6 +35,16 @@ dependencies { implementation(group = "com.fasterxml.jackson.core", name = "jackson-databind", version = "2.10.1") implementation(group = "net.sf.trove4j", name = "trove4j", version = "3.0.3") + + implementation(group = "com.discord4j", name = "discord4j-core", version = "3.1.6") + + // TODO: remove after switch to d4j + implementation(group = "net.dv8tion", name = "JDA", version = "4.2.1_264") { + exclude(module = "opus-java") + } + + // TODO: remove after switch to d4j + // TODO: custom oauth client? // implementation(group = "com.jagrosh", name = "jda-utilities-oauth2", version = "3.0.5") implementation(group = "com.github.JDA-Applications", name = "JDA-Utilities", version = "804d58a") { // This is fine @@ -43,9 +53,6 @@ dependencies { exclude(module = "jda-utilities-command") exclude(module = "jda-utilities-menu") } - implementation(group = "net.dv8tion", name = "JDA", version = "4.2.1_264") { - exclude(module = "opus-java") - } // Yes, this is JDA // We're running this PR https://github.com/DV8FromTheWorld/JDA/pull/1178 diff --git a/src/main/kotlin/com/dunctebot/dashboard/Container.kt b/src/main/kotlin/com/dunctebot/dashboard/Container.kt index 1ea64d6..0205e06 100644 --- a/src/main/kotlin/com/dunctebot/dashboard/Container.kt +++ b/src/main/kotlin/com/dunctebot/dashboard/Container.kt @@ -2,11 +2,11 @@ package com.dunctebot.dashboard import com.dunctebot.dashboard.websocket.WebsocketClient import com.dunctebot.duncteapi.DuncteApi -import com.dunctebot.jda.JDARestClient +import com.dunctebot.jda.DiscordRestClient import com.fasterxml.jackson.databind.json.JsonMapper import okhttp3.OkHttpClient -val restJDA = JDARestClient(System.getenv("BOT_TOKEN")) +val restJDA = DiscordRestClient(System.getenv("BOT_TOKEN")) val duncteApis = DuncteApi("Bot ${System.getenv("BOT_TOKEN")}") val httpClient = OkHttpClient() diff --git a/src/main/kotlin/com/dunctebot/jda/JDARestClient.kt b/src/main/kotlin/com/dunctebot/jda/DiscordRestClient.kt similarity index 89% rename from src/main/kotlin/com/dunctebot/jda/JDARestClient.kt rename to src/main/kotlin/com/dunctebot/jda/DiscordRestClient.kt index 8ea470c..babad77 100644 --- a/src/main/kotlin/com/dunctebot/jda/JDARestClient.kt +++ b/src/main/kotlin/com/dunctebot/jda/DiscordRestClient.kt @@ -2,6 +2,10 @@ package com.dunctebot.jda import com.dunctebot.jda.impl.MemberPaginationActionImpl import com.github.benmanes.caffeine.cache.Caffeine +import discord4j.common.util.Snowflake +import discord4j.core.DiscordClient +import discord4j.discordjson.json.UserData +import discord4j.rest.entity.RestUser import net.dv8tion.jda.api.entities.Guild import net.dv8tion.jda.api.entities.Member import net.dv8tion.jda.api.entities.SelfUser @@ -18,6 +22,7 @@ import net.dv8tion.jda.internal.utils.config.AuthorizationConfig import net.dv8tion.jda.internal.utils.config.MetaConfig import net.dv8tion.jda.internal.utils.config.SessionConfig import net.dv8tion.jda.internal.utils.config.ThreadingConfig +import reactor.core.publisher.Mono import java.util.concurrent.Executors import java.util.concurrent.TimeUnit @@ -27,7 +32,7 @@ import java.util.concurrent.TimeUnit * * This class has been inspired by GivawayBot and all credit goes to them https://github.com/jagrosh/GiveawayBot */ -class JDARestClient(token: String) { +class DiscordRestClient(token: String) { // create a guild cache that keeps the guilds in cache for 30 minutes // When we stop accessing the guild it will be removed from the cache private val guildCache = Caffeine.newBuilder() @@ -35,8 +40,11 @@ class JDARestClient(token: String) { .build() private val jda: JDAImpl + private val client: DiscordClient init { + client = DiscordClient.create(token) + val authConfig = AuthorizationConfig(token) val sessionConfig = SessionConfig.getDefault() val threadConfig = ThreadingConfig.getDefault() @@ -61,6 +69,15 @@ class JDARestClient(token: String) { guildCache.invalidate(guildId.toString()) } + // Note: instantly starts the request + fun retrieveD4JUserById(id: Long): Mono { + return client.userService.getUser(id) + } + + fun retrieveD4JSelfUser(): Mono { + return client.userService.currentUser + } + fun retrieveUserById(id: String): RestAction { val route = Route.Users.GET_USER.compile(id) diff --git a/src/main/kotlin/com/dunctebot/jda/FakeJDA.kt b/src/main/kotlin/com/dunctebot/jda/FakeJDA.kt index c48c0ba..e1ad210 100644 --- a/src/main/kotlin/com/dunctebot/jda/FakeJDA.kt +++ b/src/main/kotlin/com/dunctebot/jda/FakeJDA.kt @@ -5,7 +5,7 @@ import net.dv8tion.jda.api.entities.User import net.dv8tion.jda.api.requests.RestAction import net.dv8tion.jda.internal.JDAImpl -class FakeJDA(private val restClient: JDARestClient, fakeClient: JDAImpl) : JDA by fakeClient { +class FakeJDA(private val restClient: DiscordRestClient, fakeClient: JDAImpl) : JDA by fakeClient { override fun retrieveUserById(id: Long, update: Boolean): RestAction { return restClient.retrieveUserById(id.toString()) } From 4f770edbc2149cab0327d32f1866d7585538f6f0 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Thu, 8 Jul 2021 21:34:59 +0200 Subject: [PATCH 02/16] More rewriting to d4j --- .../com/dunctebot/dashboard/Container.kt | 4 +-- .../com/dunctebot/dashboard/WebHelpers.kt | 5 +-- .../controllers/DashboardController.kt | 4 +-- .../dashboard/controllers/GuildController.kt | 31 +++++++------------ .../controllers/api/GuildApiController.kt | 14 +++++---- .../websocket/handlers/DataUpdateHandler.kt | 4 +-- .../{jda => discord}/DiscordRestClient.kt | 29 +++++++++++------ .../com/dunctebot/{jda => discord}/FakeJDA.kt | 2 +- .../{jda => discord}/FakeSessionController.kt | 2 +- .../MemberPaginationAction.kt | 2 +- .../dunctebot/discord/extensions/UserData.kt | 6 ++++ .../impl/MemberPaginationActionImpl.kt | 4 +-- 12 files changed, 59 insertions(+), 48 deletions(-) rename src/main/kotlin/com/dunctebot/{jda => discord}/DiscordRestClient.kt (88%) rename src/main/kotlin/com/dunctebot/{jda => discord}/FakeJDA.kt (93%) rename src/main/kotlin/com/dunctebot/{jda => discord}/FakeSessionController.kt (96%) rename src/main/kotlin/com/dunctebot/{jda => discord}/MemberPaginationAction.kt (90%) create mode 100644 src/main/kotlin/com/dunctebot/discord/extensions/UserData.kt rename src/main/kotlin/com/dunctebot/{jda => discord}/impl/MemberPaginationActionImpl.kt (95%) diff --git a/src/main/kotlin/com/dunctebot/dashboard/Container.kt b/src/main/kotlin/com/dunctebot/dashboard/Container.kt index 0205e06..1ddfad8 100644 --- a/src/main/kotlin/com/dunctebot/dashboard/Container.kt +++ b/src/main/kotlin/com/dunctebot/dashboard/Container.kt @@ -2,11 +2,11 @@ package com.dunctebot.dashboard import com.dunctebot.dashboard.websocket.WebsocketClient import com.dunctebot.duncteapi.DuncteApi -import com.dunctebot.jda.DiscordRestClient +import com.dunctebot.discord.DiscordRestClient import com.fasterxml.jackson.databind.json.JsonMapper import okhttp3.OkHttpClient -val restJDA = DiscordRestClient(System.getenv("BOT_TOKEN")) +val discordClient = DiscordRestClient(System.getenv("BOT_TOKEN")) val duncteApis = DuncteApi("Bot ${System.getenv("BOT_TOKEN")}") val httpClient = OkHttpClient() diff --git a/src/main/kotlin/com/dunctebot/dashboard/WebHelpers.kt b/src/main/kotlin/com/dunctebot/dashboard/WebHelpers.kt index b0c0676..0df8ea8 100644 --- a/src/main/kotlin/com/dunctebot/dashboard/WebHelpers.kt +++ b/src/main/kotlin/com/dunctebot/dashboard/WebHelpers.kt @@ -43,7 +43,7 @@ fun Request.fetchGuild(): Guild? { val guildId: String = this.guildId ?: return null return try { - restJDA.retrieveGuildById(guildId).complete() + discordClient.retrieveGuildById(guildId).complete() } catch (e: Exception) { e.printStackTrace() null @@ -80,8 +80,9 @@ fun String?.toSafeLong(): Long { } } +@Throws(HaltException::class) fun haltNotFound(request: Request, response: Response) { - Spark.halt(404, CustomErrorPages.getFor(404, request, response) as String) + throw Spark.halt(404, CustomErrorPages.getFor(404, request, response) as String) } fun verifyCaptcha(response: String): JsonNode { diff --git a/src/main/kotlin/com/dunctebot/dashboard/controllers/DashboardController.kt b/src/main/kotlin/com/dunctebot/dashboard/controllers/DashboardController.kt index c16f8f0..3379cc0 100644 --- a/src/main/kotlin/com/dunctebot/dashboard/controllers/DashboardController.kt +++ b/src/main/kotlin/com/dunctebot/dashboard/controllers/DashboardController.kt @@ -5,7 +5,7 @@ import com.dunctebot.dashboard.WebServer.Companion.SESSION_ID import com.dunctebot.dashboard.WebServer.Companion.USER_ID import com.dunctebot.dashboard.fetchGuild import com.dunctebot.dashboard.guildId -import com.dunctebot.dashboard.restJDA +import com.dunctebot.dashboard.discordClient import com.dunctebot.dashboard.userId import net.dv8tion.jda.api.Permission import spark.Request @@ -27,7 +27,7 @@ object DashboardController { "&scope=bot&permissions=1609952470\" target=\"_blank\">invite it?") val member = try { - restJDA.retrieveMemberById(guild, request.userId).complete() + discordClient.retrieveMemberById(guild, request.userId).complete() } catch (e: Exception) { e.printStackTrace() throw Spark.halt(200, "

Either discord did a fucky wucky or you are not in the server that you are trying to edit

") diff --git a/src/main/kotlin/com/dunctebot/dashboard/controllers/GuildController.kt b/src/main/kotlin/com/dunctebot/dashboard/controllers/GuildController.kt index 83ff359..52b5842 100644 --- a/src/main/kotlin/com/dunctebot/dashboard/controllers/GuildController.kt +++ b/src/main/kotlin/com/dunctebot/dashboard/controllers/GuildController.kt @@ -4,13 +4,11 @@ import com.dunctebot.dashboard.* import com.dunctebot.dashboard.rendering.DbModelAndView import com.dunctebot.dashboard.rendering.WebVariables import com.github.benmanes.caffeine.cache.Caffeine -import net.dv8tion.jda.api.entities.Member -import net.dv8tion.jda.api.entities.Role -import net.dv8tion.jda.api.exceptions.ErrorResponseException +import discord4j.discordjson.json.MemberData +import discord4j.discordjson.json.RoleData import spark.Request import spark.Response import java.util.concurrent.TimeUnit -import kotlin.streams.toList object GuildController { // some hash -> "$userId-$guildId" @@ -88,32 +86,27 @@ object GuildController { fun showGuildRoles(request: Request, response: Response): Any { val hash = request.params("hash") val guildId = guildHashes.getIfPresent(hash) ?: return haltNotFound(request, response) - val guild = try { - // TODO: do we want to do this? - // Maybe only cache for a short time as it will get outdated data - restJDA.fakeJDA.getGuildById(guildId) ?: restJDA.retrieveGuildById(guildId.toString()).complete() - } catch (e: ErrorResponseException) { - e.printStackTrace() - return haltNotFound(request, response) - } - val roles = guildRoleCache.get(guild.idLong) { - val members = restJDA.retrieveAllMembers(guild).stream().toList() + val roles = guildRoleCache.get(guildId) { + val internalRoles = discordClient.retrieveGuildRoles(guildId) + val members = discordClient.retrieveGuildMembers(guildId).collectList().block()!! - guild.roles.map { CustomRole(it, members) } + internalRoles.map { CustomRole(it, members) }.collectList().block() }!! + val guildName = "TEMP GUILD NAME" + return WebVariables() .put("hide_menu", true) - .put("title", "Roles for ${guild.name}") - .put("guild_name", guild.name) + .put("title", "Roles for $guildName") + .put("guild_name", guildName) .put("roles", roles) .toModelAndView("guildRoles.vm") } - class CustomRole(private val realRole: Role, allMembers: List) : Role by realRole { + class CustomRole(private val realRole: RoleData, allMembers: List) : RoleData by realRole { // Accessed by our templating engine @Suppress("unused") - val memberCount = allMembers.filter { it.roles.contains(realRole) }.size + val memberCount = allMembers.filter { it.roles().contains(realRole.id()) } } } diff --git a/src/main/kotlin/com/dunctebot/dashboard/controllers/api/GuildApiController.kt b/src/main/kotlin/com/dunctebot/dashboard/controllers/api/GuildApiController.kt index ece83aa..6a9d069 100644 --- a/src/main/kotlin/com/dunctebot/dashboard/controllers/api/GuildApiController.kt +++ b/src/main/kotlin/com/dunctebot/dashboard/controllers/api/GuildApiController.kt @@ -3,9 +3,10 @@ package com.dunctebot.dashboard.controllers.api import com.dunctebot.dashboard.* import com.dunctebot.dashboard.controllers.GuildController import com.dunctebot.dashboard.utils.HashUtils +import com.dunctebot.discord.extensions.asTag import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.node.ObjectNode -import net.dv8tion.jda.api.entities.User +import discord4j.discordjson.json.UserData import spark.Request import spark.Response import java.util.concurrent.CompletableFuture @@ -45,8 +46,8 @@ object GuildApiController { .put("code", response.status()) } - val user: User? = try { - restJDA.retrieveUserById(data["user_id"].asText()).complete() + val user: UserData? = try { + discordClient.retrieveD4JUserById(data["user_id"].asText()).data.block() } catch (e: Exception) { e.printStackTrace() null @@ -101,12 +102,13 @@ object GuildApiController { .put("id", guildId) .put("name", guild["name"].asText()) + val userId = user.id().asString() val userJson = jsonMapper.createObjectNode() - .put("id", user.id) - .put("name", user.name) + .put("id", userId) + .put("name", user.username()) .put("formatted", user.asTag) - val theKey = "${user.idLong}-${guildId}" + val theKey = "$userId-$guildId" val theHash = HashUtils.sha1(theKey + System.currentTimeMillis()) GuildController.securityKeys[theHash] = theKey diff --git a/src/main/kotlin/com/dunctebot/dashboard/websocket/handlers/DataUpdateHandler.kt b/src/main/kotlin/com/dunctebot/dashboard/websocket/handlers/DataUpdateHandler.kt index 09aecef..70c6de9 100644 --- a/src/main/kotlin/com/dunctebot/dashboard/websocket/handlers/DataUpdateHandler.kt +++ b/src/main/kotlin/com/dunctebot/dashboard/websocket/handlers/DataUpdateHandler.kt @@ -1,6 +1,6 @@ package com.dunctebot.dashboard.websocket.handlers -import com.dunctebot.dashboard.restJDA +import com.dunctebot.dashboard.discordClient import com.dunctebot.dashboard.websocket.handlers.base.SocketHandler import com.fasterxml.jackson.databind.JsonNode @@ -8,7 +8,7 @@ class DataUpdateHandler : SocketHandler() { override fun handleInternally(data: JsonNode?) { if (data!!.has("guilds")) { data["guilds"]["invalidate"].forEach { - restJDA.invalidateGuild(it.asLong()) + discordClient.invalidateGuild(it.asLong()) } } } diff --git a/src/main/kotlin/com/dunctebot/jda/DiscordRestClient.kt b/src/main/kotlin/com/dunctebot/discord/DiscordRestClient.kt similarity index 88% rename from src/main/kotlin/com/dunctebot/jda/DiscordRestClient.kt rename to src/main/kotlin/com/dunctebot/discord/DiscordRestClient.kt index babad77..13b9dfd 100644 --- a/src/main/kotlin/com/dunctebot/jda/DiscordRestClient.kt +++ b/src/main/kotlin/com/dunctebot/discord/DiscordRestClient.kt @@ -1,10 +1,10 @@ -package com.dunctebot.jda +package com.dunctebot.discord -import com.dunctebot.jda.impl.MemberPaginationActionImpl import com.github.benmanes.caffeine.cache.Caffeine import discord4j.common.util.Snowflake import discord4j.core.DiscordClient -import discord4j.discordjson.json.UserData +import discord4j.discordjson.json.* +import discord4j.rest.entity.RestGuild import discord4j.rest.entity.RestUser import net.dv8tion.jda.api.entities.Guild import net.dv8tion.jda.api.entities.Member @@ -22,6 +22,7 @@ import net.dv8tion.jda.internal.utils.config.AuthorizationConfig import net.dv8tion.jda.internal.utils.config.MetaConfig import net.dv8tion.jda.internal.utils.config.SessionConfig import net.dv8tion.jda.internal.utils.config.ThreadingConfig +import reactor.core.publisher.Flux import reactor.core.publisher.Mono import java.util.concurrent.Executors import java.util.concurrent.TimeUnit @@ -40,11 +41,9 @@ class DiscordRestClient(token: String) { .build() private val jda: JDAImpl - private val client: DiscordClient + private val client = DiscordClient.create(token) init { - client = DiscordClient.create(token) - val authConfig = AuthorizationConfig(token) val sessionConfig = SessionConfig.getDefault() val threadConfig = ThreadingConfig.getDefault() @@ -70,14 +69,26 @@ class DiscordRestClient(token: String) { } // Note: instantly starts the request - fun retrieveD4JUserById(id: Long): Mono { - return client.userService.getUser(id) + fun retrieveD4JUserById(id: String): RestUser { + return client.getUserById(Snowflake.of(id)) } fun retrieveD4JSelfUser(): Mono { return client.userService.currentUser } + fun retrieveD4JGuild(guildId: Long): RestGuild { + return client.getGuildById(Snowflake.of(guildId)) + } + + fun retrieveGuildRoles(guildId: Long): Flux { + return client.getGuildById(Snowflake.of(guildId)).roles + } + + fun retrieveGuildMembers(guildId: Long): Flux { + return client.getGuildById(Snowflake.of(guildId)).members + } + fun retrieveUserById(id: String): RestAction { val route = Route.Users.GET_USER.compile(id) @@ -94,8 +105,6 @@ class DiscordRestClient(token: String) { } } - fun retrieveAllMembers(guild: Guild): MemberPaginationAction = MemberPaginationActionImpl(guild) - private fun retrieveGuildChannelsArray(guildId: String): RestAction { val route = Route.Guilds.GET_CHANNELS.compile(guildId) diff --git a/src/main/kotlin/com/dunctebot/jda/FakeJDA.kt b/src/main/kotlin/com/dunctebot/discord/FakeJDA.kt similarity index 93% rename from src/main/kotlin/com/dunctebot/jda/FakeJDA.kt rename to src/main/kotlin/com/dunctebot/discord/FakeJDA.kt index e1ad210..ca85f39 100644 --- a/src/main/kotlin/com/dunctebot/jda/FakeJDA.kt +++ b/src/main/kotlin/com/dunctebot/discord/FakeJDA.kt @@ -1,4 +1,4 @@ -package com.dunctebot.jda +package com.dunctebot.discord import net.dv8tion.jda.api.JDA import net.dv8tion.jda.api.entities.User diff --git a/src/main/kotlin/com/dunctebot/jda/FakeSessionController.kt b/src/main/kotlin/com/dunctebot/discord/FakeSessionController.kt similarity index 96% rename from src/main/kotlin/com/dunctebot/jda/FakeSessionController.kt rename to src/main/kotlin/com/dunctebot/discord/FakeSessionController.kt index 14e32d0..b169741 100644 --- a/src/main/kotlin/com/dunctebot/jda/FakeSessionController.kt +++ b/src/main/kotlin/com/dunctebot/discord/FakeSessionController.kt @@ -1,4 +1,4 @@ -package com.dunctebot.jda +package com.dunctebot.discord import net.dv8tion.jda.api.JDA import net.dv8tion.jda.api.utils.SessionController diff --git a/src/main/kotlin/com/dunctebot/jda/MemberPaginationAction.kt b/src/main/kotlin/com/dunctebot/discord/MemberPaginationAction.kt similarity index 90% rename from src/main/kotlin/com/dunctebot/jda/MemberPaginationAction.kt rename to src/main/kotlin/com/dunctebot/discord/MemberPaginationAction.kt index fa2e8f4..617bcdd 100644 --- a/src/main/kotlin/com/dunctebot/jda/MemberPaginationAction.kt +++ b/src/main/kotlin/com/dunctebot/discord/MemberPaginationAction.kt @@ -1,4 +1,4 @@ -package com.dunctebot.jda +package com.dunctebot.discord import net.dv8tion.jda.api.entities.Guild import net.dv8tion.jda.api.entities.Member diff --git a/src/main/kotlin/com/dunctebot/discord/extensions/UserData.kt b/src/main/kotlin/com/dunctebot/discord/extensions/UserData.kt new file mode 100644 index 0000000..a3a0844 --- /dev/null +++ b/src/main/kotlin/com/dunctebot/discord/extensions/UserData.kt @@ -0,0 +1,6 @@ +package com.dunctebot.discord.extensions + +import discord4j.discordjson.json.UserData + +val UserData.asTag: String + get() = "${this.username()}#${this.discriminator()}" diff --git a/src/main/kotlin/com/dunctebot/jda/impl/MemberPaginationActionImpl.kt b/src/main/kotlin/com/dunctebot/discord/impl/MemberPaginationActionImpl.kt similarity index 95% rename from src/main/kotlin/com/dunctebot/jda/impl/MemberPaginationActionImpl.kt rename to src/main/kotlin/com/dunctebot/discord/impl/MemberPaginationActionImpl.kt index 36a2b90..232e737 100644 --- a/src/main/kotlin/com/dunctebot/jda/impl/MemberPaginationActionImpl.kt +++ b/src/main/kotlin/com/dunctebot/discord/impl/MemberPaginationActionImpl.kt @@ -1,6 +1,6 @@ -package com.dunctebot.jda.impl +package com.dunctebot.discord.impl -import com.dunctebot.jda.MemberPaginationAction +import com.dunctebot.discord.MemberPaginationAction import net.dv8tion.jda.api.entities.Guild import net.dv8tion.jda.api.entities.Member import net.dv8tion.jda.api.exceptions.ParsingException From cd2d71d1955888231ef618510987a8c73d50e624 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Thu, 8 Jul 2021 22:03:08 +0200 Subject: [PATCH 03/16] Almost completely strip out JDA --- .../com/dunctebot/dashboard/WebHelpers.kt | 13 +- .../com/dunctebot/dashboard/WebServer.kt | 5 +- .../controllers/DashboardController.kt | 11 +- .../dashboard/controllers/GuildController.kt | 3 +- .../dunctebot/discord/DiscordRestClient.kt | 132 ++---------------- .../kotlin/com/dunctebot/discord/FakeJDA.kt | 12 -- .../discord/FakeSessionController.kt | 31 ---- .../discord/MemberPaginationAction.kt | 9 -- .../impl/MemberPaginationActionImpl.kt | 69 --------- 9 files changed, 39 insertions(+), 246 deletions(-) delete mode 100644 src/main/kotlin/com/dunctebot/discord/FakeJDA.kt delete mode 100644 src/main/kotlin/com/dunctebot/discord/FakeSessionController.kt delete mode 100644 src/main/kotlin/com/dunctebot/discord/MemberPaginationAction.kt delete mode 100644 src/main/kotlin/com/dunctebot/discord/impl/MemberPaginationActionImpl.kt diff --git a/src/main/kotlin/com/dunctebot/dashboard/WebHelpers.kt b/src/main/kotlin/com/dunctebot/dashboard/WebHelpers.kt index 0df8ea8..30d4eb4 100644 --- a/src/main/kotlin/com/dunctebot/dashboard/WebHelpers.kt +++ b/src/main/kotlin/com/dunctebot/dashboard/WebHelpers.kt @@ -6,6 +6,8 @@ import com.dunctebot.dashboard.WebServer.Companion.USER_ID import com.fasterxml.jackson.databind.JsonNode import com.jagrosh.jdautilities.oauth2.OAuth2Client import com.jagrosh.jdautilities.oauth2.session.Session +import discord4j.discordjson.json.GuildUpdateData +import discord4j.rest.entity.RestGuild import net.dv8tion.jda.api.entities.Guild import net.dv8tion.jda.internal.utils.IOUtil import okhttp3.FormBody @@ -39,11 +41,18 @@ val Request.userId: String val Request.guildId: String? get() = this.params(GUILD_ID) -fun Request.fetchGuild(): Guild? { +val Request.guild: RestGuild? + get() { + val guildId = this.guildId ?: return null + + return discordClient.getGuild(guildId.toLong()) + } + +fun Request.fetchGuild(): GuildUpdateData? { val guildId: String = this.guildId ?: return null return try { - discordClient.retrieveGuildById(guildId).complete() + discordClient.retrieveGuildData(guildId.toLong()) } catch (e: Exception) { e.printStackTrace() null diff --git a/src/main/kotlin/com/dunctebot/dashboard/WebServer.kt b/src/main/kotlin/com/dunctebot/dashboard/WebServer.kt index ccde9b3..4ff7136 100644 --- a/src/main/kotlin/com/dunctebot/dashboard/WebServer.kt +++ b/src/main/kotlin/com/dunctebot/dashboard/WebServer.kt @@ -270,11 +270,12 @@ class WebServer { private fun getWithGuildData(path: String, map: WebVariables, view: String) { get(path) { request, _ -> - val guild = request.fetchGuild() + val guild = request.guild if (guild != null) { - val guildId = guild.idLong + val guildId = guild.id.asLong() + // TODO: rewrite val tcs = guild.textChannelCache.filter(TextChannel::canTalk).toList() val goodRoles = guild.roleCache.filter { guild.selfMember.canInteract(it) && it.name != "@everyone" && it.name != "@here" diff --git a/src/main/kotlin/com/dunctebot/dashboard/controllers/DashboardController.kt b/src/main/kotlin/com/dunctebot/dashboard/controllers/DashboardController.kt index 3379cc0..7b20fa7 100644 --- a/src/main/kotlin/com/dunctebot/dashboard/controllers/DashboardController.kt +++ b/src/main/kotlin/com/dunctebot/dashboard/controllers/DashboardController.kt @@ -7,7 +7,7 @@ import com.dunctebot.dashboard.fetchGuild import com.dunctebot.dashboard.guildId import com.dunctebot.dashboard.discordClient import com.dunctebot.dashboard.userId -import net.dv8tion.jda.api.Permission +import discord4j.rest.util.Permission import spark.Request import spark.Response import spark.Spark @@ -27,13 +27,18 @@ object DashboardController { "&scope=bot&permissions=1609952470\" target=\"_blank\">invite it?") val member = try { - discordClient.retrieveMemberById(guild, request.userId).complete() + discordClient.retrieveMemberById(guild.id().asLong(), request.userId).block()!! } catch (e: Exception) { e.printStackTrace() throw Spark.halt(200, "

Either discord did a fucky wucky or you are not in the server that you are trying to edit

") } - if (!member.hasPermission(Permission.MANAGE_SERVER)) { + println("---------------------------------------") + println("Permissions") + println(member.permissions().get()) + println("---------------------------------------") + + if (!member.permissions().get().contains(Permission.MANAGE_GUILD.name)) { Spark.halt(200, "

You do not have permission to edit this server

") } } diff --git a/src/main/kotlin/com/dunctebot/dashboard/controllers/GuildController.kt b/src/main/kotlin/com/dunctebot/dashboard/controllers/GuildController.kt index 52b5842..47215f2 100644 --- a/src/main/kotlin/com/dunctebot/dashboard/controllers/GuildController.kt +++ b/src/main/kotlin/com/dunctebot/dashboard/controllers/GuildController.kt @@ -86,6 +86,7 @@ object GuildController { fun showGuildRoles(request: Request, response: Response): Any { val hash = request.params("hash") val guildId = guildHashes.getIfPresent(hash) ?: return haltNotFound(request, response) + val guild = discordClient.retrieveGuildData(guildId) val roles = guildRoleCache.get(guildId) { val internalRoles = discordClient.retrieveGuildRoles(guildId) @@ -94,7 +95,7 @@ object GuildController { internalRoles.map { CustomRole(it, members) }.collectList().block() }!! - val guildName = "TEMP GUILD NAME" + val guildName = guild.name() return WebVariables() .put("hide_menu", true) diff --git a/src/main/kotlin/com/dunctebot/discord/DiscordRestClient.kt b/src/main/kotlin/com/dunctebot/discord/DiscordRestClient.kt index 13b9dfd..16dcb73 100644 --- a/src/main/kotlin/com/dunctebot/discord/DiscordRestClient.kt +++ b/src/main/kotlin/com/dunctebot/discord/DiscordRestClient.kt @@ -7,24 +7,8 @@ import discord4j.discordjson.json.* import discord4j.rest.entity.RestGuild import discord4j.rest.entity.RestUser import net.dv8tion.jda.api.entities.Guild -import net.dv8tion.jda.api.entities.Member -import net.dv8tion.jda.api.entities.SelfUser -import net.dv8tion.jda.api.entities.User -import net.dv8tion.jda.api.requests.RestAction -import net.dv8tion.jda.api.utils.MiscUtil -import net.dv8tion.jda.api.utils.data.DataArray -import net.dv8tion.jda.internal.JDAImpl -import net.dv8tion.jda.internal.entities.GuildImpl -import net.dv8tion.jda.internal.requests.CompletedRestAction -import net.dv8tion.jda.internal.requests.RestActionImpl -import net.dv8tion.jda.internal.requests.Route -import net.dv8tion.jda.internal.utils.config.AuthorizationConfig -import net.dv8tion.jda.internal.utils.config.MetaConfig -import net.dv8tion.jda.internal.utils.config.SessionConfig -import net.dv8tion.jda.internal.utils.config.ThreadingConfig import reactor.core.publisher.Flux import reactor.core.publisher.Mono -import java.util.concurrent.Executors import java.util.concurrent.TimeUnit @@ -36,130 +20,44 @@ import java.util.concurrent.TimeUnit class DiscordRestClient(token: String) { // create a guild cache that keeps the guilds in cache for 30 minutes // When we stop accessing the guild it will be removed from the cache + // TODO: use expiring map instead private val guildCache = Caffeine.newBuilder() .expireAfterAccess(30, TimeUnit.MINUTES) .build() - private val jda: JDAImpl private val client = DiscordClient.create(token) - init { - val authConfig = AuthorizationConfig(token) - val sessionConfig = SessionConfig.getDefault() - val threadConfig = ThreadingConfig.getDefault() - val metaConfig = MetaConfig.getDefault() - - threadConfig.setRateLimitPool(Executors.newScheduledThreadPool(5) { - val t = Thread(it, "dunctebot-rest-thread") - t.isDaemon = true - return@newScheduledThreadPool t - }, true) - - jda = JDAImpl(authConfig, sessionConfig, threadConfig, metaConfig) - - retrieveSelfUser().queue(jda::setSelfUser) - } - - // is public for JDA utils - val fakeJDA = FakeJDA(this, jda) - + // TODO: still needed? fun invalidateGuild(guildId: Long) { - jda.guildsView.remove(guildId) - guildCache.invalidate(guildId.toString()) + this.guildCache.invalidate(guildId.toString()) } // Note: instantly starts the request fun retrieveD4JUserById(id: String): RestUser { - return client.getUserById(Snowflake.of(id)) + return this.client.getUserById(Snowflake.of(id)) } fun retrieveD4JSelfUser(): Mono { - return client.userService.currentUser - } - - fun retrieveD4JGuild(guildId: Long): RestGuild { - return client.getGuildById(Snowflake.of(guildId)) + return this.client.userService.currentUser } - fun retrieveGuildRoles(guildId: Long): Flux { - return client.getGuildById(Snowflake.of(guildId)).roles - } - - fun retrieveGuildMembers(guildId: Long): Flux { - return client.getGuildById(Snowflake.of(guildId)).members - } - - fun retrieveUserById(id: String): RestAction { - val route = Route.Users.GET_USER.compile(id) - - return RestActionImpl(jda, route) { - response, _ -> jda.entityBuilder.createUser(response.getObject()) - } + fun retrieveGuildData(guildId: Long): GuildUpdateData { + return this.getGuild(guildId).data.block()!! } - private fun retrieveSelfUser(): RestAction { - val route = Route.Self.GET_SELF.compile() - - return RestActionImpl(jda, route) { - response, _ -> jda.entityBuilder.createSelfUser(response.getObject()) - } + fun getGuild(guildId: Long): RestGuild { + return this.client.getGuildById(Snowflake.of(guildId)) } - private fun retrieveGuildChannelsArray(guildId: String): RestAction { - val route = Route.Guilds.GET_CHANNELS.compile(guildId) - - return RestActionImpl(jda, route) { response, _ -> response.array } + fun retrieveGuildRoles(guildId: Long): Flux { + return this.getGuild(guildId).roles } - fun retrieveMemberById(guild: Guild, memberId: String): RestAction { - val route = Route.Guilds.GET_MEMBER.compile(guild.id, memberId) - - return RestActionImpl(jda, route) { - response, _ -> jda.entityBuilder.createMember(guild as GuildImpl, response.getObject()) - } + fun retrieveGuildMembers(guildId: Long): Flux { + return this.getGuild(guildId).members } - fun retrieveGuildById(id: String): RestAction { - // We're caching two events here, is that worth it? - /*// Lookup the guild from the cache - val guildById = jda.getGuildById(id) - - // If we already have it we will return the cached guild - // TODO: invalidation of caches - if (guildById != null) { - return CompletedRestAction(jda, guildById) - }*/ - - // Temp cache - val cachedGuild = guildCache.getIfPresent(id) - - if (cachedGuild != null && cachedGuild.channels.isNotEmpty()) { - return CompletedRestAction(jda, cachedGuild) - } - - val route = Route.Guilds.GET_GUILD.compile(id).withQueryParams("with_counts", "true") - - // if the first rest action fails the second one will never be called - return retrieveGuildChannelsArray(id).flatMap { channels -> - RestActionImpl(jda, route) { response, _ -> - val data = response.getObject() - - // fake a bit of data - data.put("channels", channels) - data.put("voice_states", DataArray.empty()) - - val guild = jda.entityBuilder - .createGuild(id.toLong(), data, MiscUtil.newLongMap(), data.getInt("approximate_member_count")) - - val selfMember = retrieveMemberById(guild, jda.selfUser.id).complete() - guild.membersView.writeLock().use { - guild.membersView.map.put(jda.selfUser.idLong, selfMember) - } - - guildCache.put(id, guild) - - guild - } - } + fun retrieveMemberById(guildId: Long, memberId: String): Mono { + return this.getGuild(guildId).getMember(Snowflake.of(memberId)) } } diff --git a/src/main/kotlin/com/dunctebot/discord/FakeJDA.kt b/src/main/kotlin/com/dunctebot/discord/FakeJDA.kt deleted file mode 100644 index ca85f39..0000000 --- a/src/main/kotlin/com/dunctebot/discord/FakeJDA.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.dunctebot.discord - -import net.dv8tion.jda.api.JDA -import net.dv8tion.jda.api.entities.User -import net.dv8tion.jda.api.requests.RestAction -import net.dv8tion.jda.internal.JDAImpl - -class FakeJDA(private val restClient: DiscordRestClient, fakeClient: JDAImpl) : JDA by fakeClient { - override fun retrieveUserById(id: Long, update: Boolean): RestAction { - return restClient.retrieveUserById(id.toString()) - } -} diff --git a/src/main/kotlin/com/dunctebot/discord/FakeSessionController.kt b/src/main/kotlin/com/dunctebot/discord/FakeSessionController.kt deleted file mode 100644 index b169741..0000000 --- a/src/main/kotlin/com/dunctebot/discord/FakeSessionController.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.dunctebot.discord - -import net.dv8tion.jda.api.JDA -import net.dv8tion.jda.api.utils.SessionController -import net.dv8tion.jda.internal.utils.tuple.Pair - -class FakeSessionController : SessionController { - private var globalRateLimit = 0L - - override fun appendSession(node: SessionController.SessionConnectNode) { - // do nothing - } - - override fun removeSession(node: SessionController.SessionConnectNode) { - TODO("Not yet implemented") - } - - override fun getGlobalRatelimit(): Long = globalRateLimit - - override fun setGlobalRatelimit(ratelimit: Long) { - globalRateLimit = ratelimit - } - - override fun getGateway(api: JDA): String { - TODO("Not yet implemented") - } - - override fun getGatewayBot(api: JDA): Pair { - TODO("Not yet implemented") - } -} diff --git a/src/main/kotlin/com/dunctebot/discord/MemberPaginationAction.kt b/src/main/kotlin/com/dunctebot/discord/MemberPaginationAction.kt deleted file mode 100644 index 617bcdd..0000000 --- a/src/main/kotlin/com/dunctebot/discord/MemberPaginationAction.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.dunctebot.discord - -import net.dv8tion.jda.api.entities.Guild -import net.dv8tion.jda.api.entities.Member -import net.dv8tion.jda.api.requests.restaction.pagination.PaginationAction - -interface MemberPaginationAction : PaginationAction { - val guild: Guild -} diff --git a/src/main/kotlin/com/dunctebot/discord/impl/MemberPaginationActionImpl.kt b/src/main/kotlin/com/dunctebot/discord/impl/MemberPaginationActionImpl.kt deleted file mode 100644 index 232e737..0000000 --- a/src/main/kotlin/com/dunctebot/discord/impl/MemberPaginationActionImpl.kt +++ /dev/null @@ -1,69 +0,0 @@ -package com.dunctebot.discord.impl - -import com.dunctebot.discord.MemberPaginationAction -import net.dv8tion.jda.api.entities.Guild -import net.dv8tion.jda.api.entities.Member -import net.dv8tion.jda.api.exceptions.ParsingException -import net.dv8tion.jda.api.requests.Request -import net.dv8tion.jda.api.requests.Response -import net.dv8tion.jda.internal.entities.GuildImpl -import net.dv8tion.jda.internal.requests.Route -import net.dv8tion.jda.internal.requests.restaction.pagination.PaginationActionImpl - -class MemberPaginationActionImpl(override val guild: Guild) : - PaginationActionImpl( - guild.jda, - Route.get("guilds/${guild.id}/members").compile(), - 1, - 1000, - 1000 - ), MemberPaginationAction { - override fun getKey(it: Member): Long = it.idLong - - override fun finalizeRoute(): Route.CompiledRoute { - var route = super.finalizeRoute() - - var after: String? = null - val limit = getLimit().toString() - val last = this.lastKey - - if (last != 0L) { - after = last.toString() - } - - route = route.withQueryParams("limit", limit) - - if (after != null) { - route = route.withQueryParams("after", after) - } - - return route - } - - override fun handleSuccess(response: Response, request: Request>) { - val builder = api.entityBuilder - val array = response.array - val members = mutableListOf() - - for (i in 0 until array.length()) { - try { - val member = builder.createMember(guild as GuildImpl, array.getObject(i)) - - members.add(member) - - if (useCache) { - cached.add(member) - } - - last = member - lastKey = member.idLong - } catch (e: ParsingException) { - LOG.warn("Encountered exception in MemberPagination", e) - } catch (e: NullPointerException) { - LOG.warn("Encountered exception in MemberPagination", e) - } - } - - request.onSuccess(members) - } -} From c65a6079389435f547650b17bb88475efbddfe58 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Thu, 8 Jul 2021 22:14:16 +0200 Subject: [PATCH 04/16] Start on converting the last parts --- .../com/dunctebot/dashboard/WebServer.kt | 25 +++++++++++++++---- .../dunctebot/discord/DiscordRestClient.kt | 3 ++- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/com/dunctebot/dashboard/WebServer.kt b/src/main/kotlin/com/dunctebot/dashboard/WebServer.kt index 4ff7136..64b6150 100644 --- a/src/main/kotlin/com/dunctebot/dashboard/WebServer.kt +++ b/src/main/kotlin/com/dunctebot/dashboard/WebServer.kt @@ -18,7 +18,11 @@ import com.dunctebot.models.settings.WarnAction import com.dunctebot.models.utils.Utils import com.fasterxml.jackson.databind.JsonNode import com.jagrosh.jdautilities.oauth2.OAuth2Client -import net.dv8tion.jda.api.entities.TextChannel +import discord4j.common.util.Snowflake +import discord4j.core.`object`.entity.channel.TextChannel +import discord4j.rest.util.Permission +import discord4j.rest.util.PermissionSet +import net.dv8tion.jda.api.entities.TextChannel as JDATextChannel import spark.ModelAndView import spark.Spark.* @@ -275,11 +279,22 @@ class WebServer { if (guild != null) { val guildId = guild.id.asLong() - // TODO: rewrite - val tcs = guild.textChannelCache.filter(TextChannel::canTalk).toList() - val goodRoles = guild.roleCache.filter { + val tcs = guild.channels + .ofType(TextChannel::class.java) + // TODO: selfMember + .filter { + it.getEffectivePermissions(Snowflake.of(0L)).map { p -> + p.containsAll(PermissionSet.of( + Permission.SEND_MESSAGES, Permission.VIEW_CHANNEL /* read messages */ + )) + }.block()!! + } + + val goodRoles = guild.roles + + /*val goodRoles_old = guild.roleCache.filter { guild.selfMember.canInteract(it) && it.name != "@everyone" && it.name != "@here" - }.filter { !it.isManaged }.toList() + }.filter { !it.isManaged }.toList()*/ map.put("goodChannels", tcs) map.put("goodRoles", goodRoles) diff --git a/src/main/kotlin/com/dunctebot/discord/DiscordRestClient.kt b/src/main/kotlin/com/dunctebot/discord/DiscordRestClient.kt index 16dcb73..56a47d4 100644 --- a/src/main/kotlin/com/dunctebot/discord/DiscordRestClient.kt +++ b/src/main/kotlin/com/dunctebot/discord/DiscordRestClient.kt @@ -37,8 +37,9 @@ class DiscordRestClient(token: String) { return this.client.getUserById(Snowflake.of(id)) } + // TODO: cache this fun retrieveD4JSelfUser(): Mono { - return this.client.userService.currentUser + return this.client.self } fun retrieveGuildData(guildId: Long): GuildUpdateData { From 915457ba09966c6e7c8cfaaeb0fe54137a1d17c2 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Thu, 8 Jul 2021 22:23:20 +0200 Subject: [PATCH 05/16] Filter roles --- src/main/kotlin/com/dunctebot/dashboard/WebHelpers.kt | 4 ++-- src/main/kotlin/com/dunctebot/dashboard/WebServer.kt | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/com/dunctebot/dashboard/WebHelpers.kt b/src/main/kotlin/com/dunctebot/dashboard/WebHelpers.kt index 30d4eb4..9bc4697 100644 --- a/src/main/kotlin/com/dunctebot/dashboard/WebHelpers.kt +++ b/src/main/kotlin/com/dunctebot/dashboard/WebHelpers.kt @@ -49,10 +49,10 @@ val Request.guild: RestGuild? } fun Request.fetchGuild(): GuildUpdateData? { - val guildId: String = this.guildId ?: return null + val guild: RestGuild = this.guild ?: return null return try { - discordClient.retrieveGuildData(guildId.toLong()) + guild.data.block() } catch (e: Exception) { e.printStackTrace() null diff --git a/src/main/kotlin/com/dunctebot/dashboard/WebServer.kt b/src/main/kotlin/com/dunctebot/dashboard/WebServer.kt index 64b6150..30645a5 100644 --- a/src/main/kotlin/com/dunctebot/dashboard/WebServer.kt +++ b/src/main/kotlin/com/dunctebot/dashboard/WebServer.kt @@ -22,7 +22,6 @@ import discord4j.common.util.Snowflake import discord4j.core.`object`.entity.channel.TextChannel import discord4j.rest.util.Permission import discord4j.rest.util.PermissionSet -import net.dv8tion.jda.api.entities.TextChannel as JDATextChannel import spark.ModelAndView import spark.Spark.* @@ -278,12 +277,13 @@ class WebServer { if (guild != null) { val guildId = guild.id.asLong() + val self = guild.selfMember.block()!! + val selfId = Snowflake.of(self.user().id()) val tcs = guild.channels .ofType(TextChannel::class.java) - // TODO: selfMember .filter { - it.getEffectivePermissions(Snowflake.of(0L)).map { p -> + it.getEffectivePermissions(selfId).map { p -> p.containsAll(PermissionSet.of( Permission.SEND_MESSAGES, Permission.VIEW_CHANNEL /* read messages */ )) @@ -291,6 +291,9 @@ class WebServer { } val goodRoles = guild.roles + .filter { !it.managed() } + .filter { it.name() != "@everyone" && it.name() != "@here" } + // TODO: check if can interact /*val goodRoles_old = guild.roleCache.filter { guild.selfMember.canInteract(it) && it.name != "@everyone" && it.name != "@here" From d3f4f4e8ea419018a3dba2b0c2a68e4ed0d29c76 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Fri, 9 Jul 2021 07:58:06 +0200 Subject: [PATCH 06/16] Make the role page work --- .../dashboard/controllers/GuildController.kt | 29 ++++++++++++------- .../dashboard/websocket/WebsocketClient.kt | 4 +-- .../dunctebot/discord/DiscordRestClient.kt | 1 + src/main/resources/views/templates/base.vm | 4 ++- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/main/kotlin/com/dunctebot/dashboard/controllers/GuildController.kt b/src/main/kotlin/com/dunctebot/dashboard/controllers/GuildController.kt index 47215f2..1614786 100644 --- a/src/main/kotlin/com/dunctebot/dashboard/controllers/GuildController.kt +++ b/src/main/kotlin/com/dunctebot/dashboard/controllers/GuildController.kt @@ -11,14 +11,17 @@ import spark.Response import java.util.concurrent.TimeUnit object GuildController { + private const val DEFAULT_ROLE_COLOUR = 0x1FFFFFFF + // some hash -> "$userId-$guildId" + // TODO: convert to expiring map val securityKeys = mutableMapOf() val guildHashes = Caffeine.newBuilder() .expireAfterWrite(2, TimeUnit.HOURS) .build() val guildRoleCache = Caffeine.newBuilder() .expireAfterWrite(1, TimeUnit.HOURS) - .build>() + .build>>() fun handleOneGuildRegister(request: Request): Any { val params = request.paramsMap @@ -85,18 +88,19 @@ object GuildController { fun showGuildRoles(request: Request, response: Response): Any { val hash = request.params("hash") - val guildId = guildHashes.getIfPresent(hash) ?: return haltNotFound(request, response) - val guild = discordClient.retrieveGuildData(guildId) +// val guildId = guildHashes.getIfPresent(hash) ?: return haltNotFound(request, response) + val guildId = hash.toLong() // cheat :D - val roles = guildRoleCache.get(guildId) { + val (guildName, roles) = guildRoleCache.get(guildId) { val internalRoles = discordClient.retrieveGuildRoles(guildId) val members = discordClient.retrieveGuildMembers(guildId).collectList().block()!! + val guild = discordClient.retrieveGuildData(guildId) - internalRoles.map { CustomRole(it, members) }.collectList().block() + guild.name() to internalRoles.map { CustomRole(it, members) } + .sort { o1, o2 -> o2.position() - o1.position() } + .collectList().block()!! }!! - val guildName = guild.name() - return WebVariables() .put("hide_menu", true) .put("title", "Roles for $guildName") @@ -105,9 +109,14 @@ object GuildController { .toModelAndView("guildRoles.vm") } + // Accessed by our templating engine + @Suppress("unused") class CustomRole(private val realRole: RoleData, allMembers: List) : RoleData by realRole { - // Accessed by our templating engine - @Suppress("unused") - val memberCount = allMembers.filter { it.roles().contains(realRole.id()) } + val memberCount = allMembers.filter { it.roles().contains(realRole.id()) }.size + + // overloads mimicking JDA names for easy access in the template + val idLong = realRole.id().asLong() + val name: String = realRole.name() + val colorRaw = if (realRole.color() == 0) DEFAULT_ROLE_COLOUR else realRole.color() } } diff --git a/src/main/kotlin/com/dunctebot/dashboard/websocket/WebsocketClient.kt b/src/main/kotlin/com/dunctebot/dashboard/websocket/WebsocketClient.kt index 2d6efdb..4cdeb0f 100644 --- a/src/main/kotlin/com/dunctebot/dashboard/websocket/WebsocketClient.kt +++ b/src/main/kotlin/com/dunctebot/dashboard/websocket/WebsocketClient.kt @@ -48,7 +48,7 @@ class WebsocketClient : WebSocketAdapter(), WebSocketListener { init { setupHandlers() - connect() + /*connect() reconnectThread.scheduleWithFixedDelay( ReconnectTask(this), @@ -62,7 +62,7 @@ class WebsocketClient : WebSocketAdapter(), WebSocketListener { 1L, 1L, TimeUnit.MINUTES - ) + )*/ } override fun onConnected(websocket: WebSocket, headers: MutableMap>) { diff --git a/src/main/kotlin/com/dunctebot/discord/DiscordRestClient.kt b/src/main/kotlin/com/dunctebot/discord/DiscordRestClient.kt index 56a47d4..8300242 100644 --- a/src/main/kotlin/com/dunctebot/discord/DiscordRestClient.kt +++ b/src/main/kotlin/com/dunctebot/discord/DiscordRestClient.kt @@ -42,6 +42,7 @@ class DiscordRestClient(token: String) { return this.client.self } + // TODO: cache this fun retrieveGuildData(guildId: Long): GuildUpdateData { return this.getGuild(guildId).data.block()!! } diff --git a/src/main/resources/views/templates/base.vm b/src/main/resources/views/templates/base.vm index 2148543..d21659c 100644 --- a/src/main/resources/views/templates/base.vm +++ b/src/main/resources/views/templates/base.vm @@ -82,7 +82,9 @@