From 15975141db180d26005a249798656668da8035ba Mon Sep 17 00:00:00 2001 From: duncte123 Date: Sun, 16 Apr 2023 12:09:38 +0200 Subject: [PATCH 01/20] Now I know this sounds bad --- .../skybot/database/MariaDBDatabase.kt | 258 ++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt new file mode 100644 index 000000000..773791ff9 --- /dev/null +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt @@ -0,0 +1,258 @@ +/* + * Skybot, a multipurpose discord bot + * Copyright (C) 2017 Duncan "duncte123" Sterken & Ramid "ramidzkh" Khan & Maurice R S "Sanduhr32" + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package ml.duncte123.skybot.database + +import com.dunctebot.models.settings.GuildSetting +import com.dunctebot.models.settings.WarnAction +import com.zaxxer.hikari.HikariConfig +import com.zaxxer.hikari.HikariDataSource +import liquibase.Contexts +import liquibase.Liquibase +import liquibase.database.jvm.JdbcConnection +import liquibase.resource.ClassLoaderResourceAccessor +import ml.duncte123.skybot.objects.Tag +import ml.duncte123.skybot.objects.api.* +import ml.duncte123.skybot.objects.command.CommandResult +import ml.duncte123.skybot.objects.command.CustomCommand +import java.sql.Connection +import java.time.OffsetDateTime +import java.util.concurrent.CompletableFuture + +class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> }) : AbstractDatabase(2, ohShitFn) { + private val ds: HikariDataSource + private val connection: Connection + get() { + return this.ds.connection + } + + init { + val config = HikariConfig() + + config.jdbcUrl = jdbcURI + + this.ds = HikariDataSource(config) + } + + override fun getCustomCommands(): CompletableFuture> { + TODO("Not yet implemented") + } + + override fun createCustomCommand(guildId: Long, invoke: String, message: String): CompletableFuture { + TODO("Not yet implemented") + } + + override fun updateCustomCommand( + guildId: Long, + invoke: String, + message: String, + autoresponse: Boolean + ): CompletableFuture { + TODO("Not yet implemented") + } + + override fun deleteCustomCommand(guildId: Long, invoke: String): CompletableFuture { + TODO("Not yet implemented") + } + + override fun getGuildSettings(): CompletableFuture> { + TODO("Not yet implemented") + } + + override fun loadGuildSetting(guildId: Long): CompletableFuture { + TODO("Not yet implemented") + } + + override fun deleteGuildSetting(guildId: Long): CompletableFuture { + TODO("Not yet implemented") + } + + override fun purgeGuildSettings(guildIds: List): CompletableFuture { + TODO("Not yet implemented") + } + + override fun updateGuildSetting(guildSettings: GuildSetting): CompletableFuture { + TODO("Not yet implemented") + } + + override fun registerNewGuild(guildSettings: GuildSetting): CompletableFuture { + TODO("Not yet implemented") + } + + override fun addWordToBlacklist(guildId: Long, word: String): CompletableFuture { + TODO("Not yet implemented") + } + + override fun addWordsToBlacklist(guildId: Long, words: List): CompletableFuture { + TODO("Not yet implemented") + } + + override fun removeWordFromBlacklist(guildId: Long, word: String): CompletableFuture { + TODO("Not yet implemented") + } + + override fun clearBlacklist(guildId: Long): CompletableFuture { + TODO("Not yet implemented") + } + + override fun updateOrCreateEmbedColor(guildId: Long, color: Int): CompletableFuture { + TODO("Not yet implemented") + } + + override fun loadAllPatrons(): CompletableFuture { + TODO("Not yet implemented") + } + + override fun removePatron(userId: Long): CompletableFuture { + TODO("Not yet implemented") + } + + override fun createOrUpdatePatron(patron: Patron): CompletableFuture { + TODO("Not yet implemented") + } + + override fun addOneGuildPatrons(userId: Long, guildId: Long): CompletableFuture> { + TODO("Not yet implemented") + } + + override fun getOneGuildPatron(userId: Long): CompletableFuture { + TODO("Not yet implemented") + } + + override fun createBan(modId: Long, userId: Long, unbanDate: String, guildId: Long): CompletableFuture { + TODO("Not yet implemented") + } + + override fun createWarning(modId: Long, userId: Long, guildId: Long, reason: String): CompletableFuture { + TODO("Not yet implemented") + } + + override fun createMute( + modId: Long, + userId: Long, + userTag: String, + unmuteDate: String, + guildId: Long + ): CompletableFuture { + TODO("Not yet implemented") + } + + override fun getWarningsForUser(userId: Long, guildId: Long): CompletableFuture> { + TODO("Not yet implemented") + } + + override fun getWarningCountForUser(userId: Long, guildId: Long): CompletableFuture { + TODO("Not yet implemented") + } + + override fun deleteLatestWarningForUser(userId: Long, guildId: Long): CompletableFuture { + TODO("Not yet implemented") + } + + override fun getExpiredBansAndMutes(): CompletableFuture, List>> { + TODO("Not yet implemented") + } + + override fun purgeBans(ids: List): CompletableFuture { + TODO("Not yet implemented") + } + + override fun purgeMutes(ids: List): CompletableFuture { + TODO("Not yet implemented") + } + + override fun createBanBypass(guildId: Long, userId: Long): CompletableFuture { + TODO("Not yet implemented") + } + + override fun getBanBypass(guildId: Long, userId: Long): CompletableFuture { + TODO("Not yet implemented") + } + + override fun deleteBanBypass(banBypass: BanBypas): CompletableFuture { + TODO("Not yet implemented") + } + + override fun getVcAutoRoles(): CompletableFuture> { + TODO("Not yet implemented") + } + + override fun setVcAutoRole(guildId: Long, voiceChannelId: Long, roleId: Long): CompletableFuture { + TODO("Not yet implemented") + } + + override fun setVcAutoRoleBatch(guildId: Long, voiceChannelIds: List, roleId: Long): CompletableFuture { + TODO("Not yet implemented") + } + + override fun removeVcAutoRole(voiceChannelId: Long): CompletableFuture { + TODO("Not yet implemented") + } + + override fun removeVcAutoRoleForGuild(guildId: Long): CompletableFuture { + TODO("Not yet implemented") + } + + override fun loadTags(): CompletableFuture> { + TODO("Not yet implemented") + } + + override fun createTag(tag: Tag): CompletableFuture> { + TODO("Not yet implemented") + } + + override fun deleteTag(tag: Tag): CompletableFuture> { + TODO("Not yet implemented") + } + + override fun createReminder( + userId: Long, + reminder: String, + expireDate: OffsetDateTime, + channelId: Long, + messageId: Long, + guildId: Long, + inChannel: Boolean + ): CompletableFuture> { + TODO("Not yet implemented") + } + + override fun removeReminder(reminderId: Int, userId: Long): CompletableFuture { + TODO("Not yet implemented") + } + + override fun showReminder(reminderId: Int, userId: Long): CompletableFuture { + TODO("Not yet implemented") + } + + override fun listReminders(userId: Long): CompletableFuture> { + TODO("Not yet implemented") + } + + override fun getExpiredReminders(): CompletableFuture> { + TODO("Not yet implemented") + } + + override fun purgeReminders(ids: List): CompletableFuture { + TODO("Not yet implemented") + } + + override fun setWarnActions(guildId: Long, actions: List): CompletableFuture { + TODO("Not yet implemented") + } +} From 1705bf63b09d27acf9db127945d044eac051f5ae Mon Sep 17 00:00:00 2001 From: duncte123 Date: Sun, 16 Apr 2023 13:04:45 +0200 Subject: [PATCH 02/20] Add first mysql query --- .../skybot/database/MariaDBDatabase.kt | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt index 773791ff9..23385159c 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt @@ -49,8 +49,27 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> this.ds = HikariDataSource(config) } - override fun getCustomCommands(): CompletableFuture> { - TODO("Not yet implemented") + override fun getCustomCommands() = runOnThread { + val customCommands = arrayListOf() + + this.connection.use { con -> + con.createStatement().use { smt -> + smt.executeQuery("SELECT * FROM customCommands").use { res -> + while (res.next()) { + customCommands.add( + CustomCommand( + res.getString("invoke"), + res.getString("message"), + res.getString("guildId").toLong(), + res.getBoolean("autoresponse") + ) + ) + } + } + } + } + + return@runOnThread customCommands.toList() } override fun createCustomCommand(guildId: Long, invoke: String, message: String): CompletableFuture { From 81fab55ff1851d19b500e0e27e0c2e68ec54b1e8 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Sun, 16 Apr 2023 13:05:02 +0200 Subject: [PATCH 03/20] Add sql dialects --- .idea/sqldialects.xml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .idea/sqldialects.xml diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml new file mode 100644 index 000000000..b651e5258 --- /dev/null +++ b/.idea/sqldialects.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file From 37edfa89e2700567cf566bb4847728489e495ee4 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Sun, 16 Apr 2023 16:50:59 +0200 Subject: [PATCH 04/20] I can mostly copy-paste this shit :D --- .../skybot/database/AbstractDatabase.kt | 4 + .../skybot/database/MariaDBDatabase.kt | 153 +++++++++++++++++- .../skybot/database/PostgreDatabase.kt | 17 +- .../skybot/extensions/DatabaseExtensions.kt | 38 +++++ 4 files changed, 202 insertions(+), 10 deletions(-) diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt index 79341cc39..cedd58c3b 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt @@ -246,4 +246,8 @@ abstract class AbstractDatabase(threads: Int = 2, private val ohShitFn: (Int, In return future } + + companion object { + const val MAX_CUSTOM_COMMANDS = 50 + } } diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt index 23385159c..17263a094 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt @@ -22,15 +22,19 @@ import com.dunctebot.models.settings.GuildSetting import com.dunctebot.models.settings.WarnAction import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource +import io.sentry.Sentry import liquibase.Contexts import liquibase.Liquibase import liquibase.database.jvm.JdbcConnection import liquibase.resource.ClassLoaderResourceAccessor +import ml.duncte123.skybot.extensions.toGuildSetting +import ml.duncte123.skybot.extensions.toGuildSettingMySQL import ml.duncte123.skybot.objects.Tag import ml.duncte123.skybot.objects.api.* import ml.duncte123.skybot.objects.command.CommandResult import ml.duncte123.skybot.objects.command.CustomCommand import java.sql.Connection +import java.sql.SQLException import java.time.OffsetDateTime import java.util.concurrent.CompletableFuture @@ -72,8 +76,55 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> return@runOnThread customCommands.toList() } - override fun createCustomCommand(guildId: Long, invoke: String, message: String): CompletableFuture { - TODO("Not yet implemented") + override fun createCustomCommand( + guildId: Long, + invoke: String, + message: String + ) = runOnThread { + this.connection.use { con -> + con.prepareStatement( + "SELECT COUNT(guildId) as cmd_count FROM customCommands WHERE guildId = ?" + ).use { smt -> + smt.setString(1, guildId.toString()) + + smt.executeQuery().use { res -> + if (res.next() && res.getInt("cmd_count") >= MAX_CUSTOM_COMMANDS) { + return@runOnThread CommandResult.LIMIT_REACHED + } + } + } + + con.prepareStatement( + "SELECT COUNT(invoke) AS cmd_count FROM customCommands WHERE invoke = ? AND guildId = ?" + ).use { smt -> + smt.setString(1, invoke) + smt.setString(2, guildId.toString()) + + smt.executeQuery().use { res -> + // Would be funny to see more than one command with the same invoke here. + if (res.next() && res.getInt("cmd_count") >= 1) { + return@runOnThread CommandResult.COMMAND_EXISTS + } + } + } + + con.prepareStatement( + "INSERT INTO customCommands (guildId, invoke, message, autoresponse) VALUES (?,?,?,?)" + ).use { smt -> + smt.setString(1, guildId.toString()) + smt.setString(2, invoke) + smt.setString(3, message) + smt.setBoolean(4, false) + + try { + smt.execute() + return@runOnThread CommandResult.SUCCESS + } catch (e: SQLException) { + Sentry.captureException(e) + return@runOnThread CommandResult.UNKNOWN + } + } + } } override fun updateCustomCommand( @@ -81,16 +132,64 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> invoke: String, message: String, autoresponse: Boolean - ): CompletableFuture { - TODO("Not yet implemented") + ) = runOnThread { + this.connection.use { con -> + con.prepareStatement( + "UPDATE customCommands SET message = ?, autoresponse = ? WHERE guildId = ? AND invoke = ?" + ).use { smt -> + smt.setString(1, message) + smt.setBoolean(2, autoresponse) + smt.setString(3, guildId.toString()) + smt.setString(4, invoke) + + try { + smt.executeUpdate() + return@runOnThread CommandResult.SUCCESS + } catch (e: SQLException) { + Sentry.captureException(e) + return@runOnThread CommandResult.UNKNOWN + } + } + } } - override fun deleteCustomCommand(guildId: Long, invoke: String): CompletableFuture { - TODO("Not yet implemented") + override fun deleteCustomCommand(guildId: Long, invoke: String) = runOnThread { + this.connection.use { con -> + con.prepareStatement("DELETE FROM customCommands WHERE guildId = ? AND invoke = ?").use { smt -> + smt.setString(1, guildId.toString()) + smt.setString(2, invoke) + + try { + smt.execute() + return@runOnThread true + } catch (e: SQLException) { + Sentry.captureException(e) + return@runOnThread false + } + } + } } - override fun getGuildSettings(): CompletableFuture> { - TODO("Not yet implemented") + override fun getGuildSettings() = runOnThread { + val settings = arrayListOf() + + this.connection.use { con -> + con.createStatement().use { smt -> + smt.executeQuery("SELECT * FROM guildSettings").use { res -> + while (res.next()) { + val guildId = res.getLong("guildId") + settings.add( + res.toGuildSettingMySQL() // TODO: update fields + // be smart and re-use the connection we already have + .setBlacklistedWords(getBlackListsForGuild(guildId, con)) + .setWarnActions(getWarnActionsForGuild(guildId, con)) + ) + } + } + } + } + + return@runOnThread settings.toList() } override fun loadGuildSetting(guildId: Long): CompletableFuture { @@ -274,4 +373,42 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> override fun setWarnActions(guildId: Long, actions: List): CompletableFuture { TODO("Not yet implemented") } + + private fun getBlackListsForGuild(guildId: Long, con: Connection): List { + val list = arrayListOf() + + con.prepareStatement("SELECT word FROM guild_blacklists WHERE guild_id = ?").use { smt -> + smt.setString(1, guildId.toString()) + + smt.executeQuery().use { res -> + while (res.next()) { + list.add(res.getString("word")) + } + } + } + + return list + } + + private fun getWarnActionsForGuild(guildId: Long, con: Connection): List { + val list = arrayListOf() + + con.prepareStatement("SELECT * FROM warn_actions WHERE guild_id = ?").use { smt -> + smt.setString(1, guildId.toString()) + + smt.executeQuery().use { res -> + while (res.next()) { + list.add( + WarnAction( + WarnAction.Type.valueOf(res.getString("type")), + res.getInt("threshold"), + res.getInt("duration") + ) + ) + } + } + } + + return list + } } diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt index ae2fba1ee..ad01c6657 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt @@ -101,13 +101,26 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> smt.setLong(1, guildId) smt.executeQuery().use { res -> - // TODO: make count constant - if (res.next() && res.getInt("cmd_count") >= 50) { + if (res.next() && res.getInt("cmd_count") >= MAX_CUSTOM_COMMANDS) { return@runOnThread CommandResult.LIMIT_REACHED } } } + con.prepareStatement( + "SELECT COUNT(invoke) AS cmd_count FROM root.public.custom_commands WHERE invoke = ? AND guild_id = ?" + ).use { smt -> + smt.setString(1, invoke) + smt.setLong(2, guildId) + + smt.executeQuery().use { res -> + // Would be funny to see more than one command with the same invoke here. + if (res.next() && res.getInt("cmd_count") >= 1) { + return@runOnThread CommandResult.COMMAND_EXISTS + } + } + } + con.prepareStatement("INSERT INTO custom_commands(guild_id, invoke, message, auto_response) VALUES (?, ?, ?, ?)") .use { smt -> smt.setLong(1, guildId) diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt b/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt index 77ae4bc83..0fbf93a05 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt @@ -46,6 +46,44 @@ fun ResultSet.toReminder() = Reminder( this.getBoolean("in_channel") ) +fun ResultSet.toGuildSettingMySQL() = GuildSetting(this.getLong("guild_id")) + .setCustomPrefix(this.getString("prefix")) + .setAutoroleRole(toLong(this.getString("auto_role_id"))) + .setEmbedColor(this.getInt("embed_color")) + .setLeaveTimeout(this.getInt("voice_leave_timeout_seconds")) + .setAnnounceTracks(this.getBoolean("announce_track_enabled")) + .setAllowAllToStop(this.getBoolean("allow_all_to_stop")) + .setServerDesc(this.getString("server_description")) + // Join/leave + .setWelcomeLeaveChannel(toLong(this.getString("join_leave_channel_id"))) + .setEnableJoinMessage(this.getBoolean("join_message_enabled")) + .setEnableLeaveMessage(this.getBoolean("leave_message_enabled")) + .setCustomJoinMessage(this.getString("join_message")) + .setCustomLeaveMessage(this.getString("leave_message")) + // moderation + .setLogChannel(toLong(this.getString("log_channel_id"))) + .setMuteRoleId(toLong(this.getString("mute_role_id"))) + .setEnableSwearFilter(this.getBoolean("swear_filter_enabled")) + .setFilterType(this.getString("swear_filter_type")) + .setAiSensitivity(this.getFloat("swear_sensitivity")) + .setAutoDeHoist(this.getBoolean("auto_dehoist_enabled")) + .setFilterInvites(this.getBoolean("invite_filter_enabled")) + .setEnableSpamFilter(this.getBoolean("spam_filter_state")) + .setKickState(this.getBoolean("kick_instead_state")) + .setRatelimits(ratelimmitChecks(this.getString("ratelimits"))) + .setSpamThreshold(this.getInt("spam_threshold")) + .setYoungAccountBanEnabled(this.getBoolean("ban_young_account_enabled")) + .setYoungAccountThreshold(this.getInt("ban_young_account_threshold_days")) + // logging + .setBanLogging(this.getBoolean("ban_logging_enabled")) + .setUnbanLogging(this.getBoolean("unban_logging_enabled")) + .setMuteLogging(this.getBoolean("mute_logging_enabled")) + .setKickLogging(this.getBoolean("kick_logging_enabled")) + .setWarnLogging(this.getBoolean("warn_logging_enabled")) + .setMemberLogging(this.getBoolean("member_logging_enabled")) + .setInviteLogging(this.getBoolean("invite_logging_enabled")) + .setMessageLogging(this.getBoolean("message_logging_enabled")) + fun ResultSet.toGuildSetting() = GuildSetting(this.getLong("guild_id")) .setCustomPrefix(this.getString("prefix")) .setAutoroleRole(toLong(this.getString("auto_role_id"))) From a596c9f9391ca6fdabc9decff9f0b2465d1862f5 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Wed, 19 Apr 2023 09:42:06 +0200 Subject: [PATCH 05/20] Implement loading of guild settings --- .../main/java/ml/duncte123/skybot/SkyBot.java | 2 + .../java/ml/duncte123/skybot/Variables.java | 14 ++--- .../listeners/ReadyShutdownListener.java | 8 +++ settings.gradle.kts | 3 +- shared/build.gradle.kts | 1 + .../skybot/database/AbstractDatabase.kt | 2 +- .../skybot/database/MariaDBDatabase.kt | 42 ++++++++++++- .../skybot/database/PostgreDatabase.kt | 8 ++- .../duncte123/skybot/database/WebDatabase.kt | 4 ++ .../skybot/extensions/DatabaseExtensions.kt | 62 +++++++++---------- 10 files changed, 100 insertions(+), 46 deletions(-) diff --git a/bot/src/main/java/ml/duncte123/skybot/SkyBot.java b/bot/src/main/java/ml/duncte123/skybot/SkyBot.java index 3d6bc16e8..47efde6d8 100644 --- a/bot/src/main/java/ml/duncte123/skybot/SkyBot.java +++ b/bot/src/main/java/ml/duncte123/skybot/SkyBot.java @@ -80,6 +80,8 @@ private SkyBot() throws LoginException { logger.info("Using PostgreSQL as database impl"); } else if ("web".equals(useDatabase)) { logger.warn("Using web api for all connections, please migrate to PostgreSQL"); + } else if ("mysql".equals(useDatabase)) { + logger.warn("Using native MariaDB connection, please migrate to PostgreSQL"); } else { shardManager = null; // for compiling n' stuff logger.error("Unknown database driver \"{}\", exiting!", useDatabase); diff --git a/bot/src/main/java/ml/duncte123/skybot/Variables.java b/bot/src/main/java/ml/duncte123/skybot/Variables.java index 176a2cdb0..2a3cd4f1f 100644 --- a/bot/src/main/java/ml/duncte123/skybot/Variables.java +++ b/bot/src/main/java/ml/duncte123/skybot/Variables.java @@ -32,6 +32,7 @@ import me.duncte123.weebJava.models.WeebApi; import me.duncte123.weebJava.types.TokenType; import ml.duncte123.skybot.database.AbstractDatabase; +import ml.duncte123.skybot.database.MariaDBDatabase; import ml.duncte123.skybot.database.PostgreDatabase; import ml.duncte123.skybot.database.WebDatabase; import ml.duncte123.skybot.objects.DBMap; @@ -172,13 +173,12 @@ public AbstractDatabase getDatabase() { return null; }; - if ("psql".equals(this.config.useDatabase)) { - this.database = new PostgreDatabase(this.config.jdbcURI, ohShitFn); - } else if ("web".equals(this.config.useDatabase)) { - this.database = new WebDatabase(this.getApis(), this.getJackson(), ohShitFn); - } else { - throw new IllegalArgumentException("Unknown database engine: " + this.config.useDatabase); - } + this.database = switch (this.config.useDatabase) { + case "psql" -> new PostgreDatabase(this.config.jdbcURI, ohShitFn); + case "mysql" -> new MariaDBDatabase(this.config.jdbcURI, ohShitFn); + case "web" -> new WebDatabase(this.getApis(), this.getJackson(), ohShitFn); + default -> throw new IllegalArgumentException("Unknown database engine: " + this.config.useDatabase); + }; } return this.database; diff --git a/bot/src/main/java/ml/duncte123/skybot/listeners/ReadyShutdownListener.java b/bot/src/main/java/ml/duncte123/skybot/listeners/ReadyShutdownListener.java index 4c7306c34..6e9ac67be 100644 --- a/bot/src/main/java/ml/duncte123/skybot/listeners/ReadyShutdownListener.java +++ b/bot/src/main/java/ml/duncte123/skybot/listeners/ReadyShutdownListener.java @@ -91,6 +91,7 @@ private void onReady(ReadyEvent event) { TimeUnit.DAYS ); + // TODO: mariadb support if ("psql".equals(this.variables.getConfig().useDatabase)) { DataTimers.startReminderTimer(this.variables, LOGGER); DataTimers.startUnbanTimer(this.variables, LOGGER); @@ -138,6 +139,13 @@ private void onShutdown() { // shut down weeb.java this.variables.getWeebApi().shutdown(); LOGGER.info("Weeb.java shutdown"); + + try { + this.variables.getDatabase().close(); + } catch (Exception e) { + throw new RuntimeException(e); // hack ;) + } + LOGGER.info("Bot and JDA shutdown cleanly"); } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 489852404..1aca8cefe 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -83,8 +83,7 @@ fun VersionCatalogBuilder.database() { library("redis", "redis.clients", "jedis").version("3.7.0") library("hikari", "com.zaxxer", "HikariCP").version("5.0.1") - // TODO: replace with official? https://jdbc.postgresql.org/ -// library("psql", "com.impossibl.pgjdbc-ng", "pgjdbc-ng").version("0.8.9") + library("mariadb", "org.mariadb.jdbc", "mariadb-java-client").version("3.1.3") library("psql", "org.postgresql", "postgresql").version("42.5.0") library("liquibase", "org.liquibase", "liquibase-core").version("4.8.0") library("liquibase-slf4j", "com.mattbertolini", "liquibase-slf4j").version("4.1.0") // TODO: make this runtime only diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index fb4faab83..446336bd5 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -44,6 +44,7 @@ java { dependencies { implementation(libs.bundles.database) + implementation(libs.mariadb) compileOnly(libs.jda) compileOnly(libs.weebjava) // lmao wtf compileOnly(libs.botCommons) diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt index cedd58c3b..301c783ed 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt @@ -32,7 +32,7 @@ import java.util.concurrent.Executors import java.util.concurrent.ThreadPoolExecutor import java.util.concurrent.TimeUnit -abstract class AbstractDatabase(threads: Int = 2, private val ohShitFn: (Int, Int) -> Unit) { +abstract class AbstractDatabase(threads: Int = 2, private val ohShitFn: (Int, Int) -> Unit) : AutoCloseable { private val databaseThread = Executors.newFixedThreadPool(threads) { val t = Thread(it, "DatabaseThread") t.isDaemon = true diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt index 17263a094..d1945e847 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt @@ -179,8 +179,9 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> while (res.next()) { val guildId = res.getLong("guildId") settings.add( - res.toGuildSettingMySQL() // TODO: update fields + res.toGuildSettingMySQL() // be smart and re-use the connection we already have + .setEmbedColor(getEmbedColorForGuild(guildId, con)) .setBlacklistedWords(getBlackListsForGuild(guildId, con)) .setWarnActions(getWarnActionsForGuild(guildId, con)) ) @@ -192,8 +193,24 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> return@runOnThread settings.toList() } - override fun loadGuildSetting(guildId: Long): CompletableFuture { - TODO("Not yet implemented") + override fun loadGuildSetting(guildId: Long) = runOnThread { + this.connection.use { con -> + con.prepareStatement("SELECT * FROM guildSettings WHERE guildId = ?").use { smt -> + smt.setString(1, guildId.toString()) + + smt.executeQuery().use { res -> + if (res.next()) { + return@runOnThread res.toGuildSettingMySQL() + // be smart and re-use the connection we already have + .setEmbedColor(getEmbedColorForGuild(guildId, con)) + .setBlacklistedWords(getBlackListsForGuild(guildId, con)) + .setWarnActions(getWarnActionsForGuild(guildId, con)) + } + } + } + } + + return@runOnThread null } override fun deleteGuildSetting(guildId: Long): CompletableFuture { @@ -374,6 +391,25 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> TODO("Not yet implemented") } + override fun close() { + this.ds.close() + } + + private fun getEmbedColorForGuild(guildId: Long, con: Connection): Int { + con.prepareStatement("SELECT embed_color FROM embedSettings WHERE guild_id =?").use { smt -> + smt.setString(1, guildId.toString()) + + smt.executeQuery().use { res -> + if (res.next()) { + return res.getInt("embed_color") + } + } + } + + + return -1 + } + private fun getBlackListsForGuild(guildId: Long, con: Connection): List { val list = arrayListOf() diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt index ad01c6657..94f8ffc6a 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt @@ -216,11 +216,11 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> .setBlacklistedWords(getBlackListsForGuild(guildId, con)) .setWarnActions(getWarnActionsForGuild(guildId, con)) } - - return@runOnThread null } } } + + return@runOnThread null } override fun deleteGuildSetting(guildId: Long) = purgeGuildSettings(listOf(guildId)) @@ -1042,6 +1042,10 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> return@runOnThread } + override fun close() { + this.ds.close() + } + private fun getBlackListsForGuild(guildId: Long, con: Connection): List { val list = arrayListOf() diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/WebDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/WebDatabase.kt index e218b2233..9c2065d6c 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/WebDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/WebDatabase.kt @@ -348,4 +348,8 @@ class WebDatabase(private val apis: DuncteApis, private val jackson: ObjectMappe apis.deleteBanBypass(banBypass.guildId, banBypass.userId) return@runOnThread } + + override fun close() { + // Nothing to close + } } diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt b/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt index 0fbf93a05..329438e27 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt @@ -46,43 +46,43 @@ fun ResultSet.toReminder() = Reminder( this.getBoolean("in_channel") ) -fun ResultSet.toGuildSettingMySQL() = GuildSetting(this.getLong("guild_id")) +fun ResultSet.toGuildSettingMySQL() = GuildSetting(this.getString("guildId").toLong()) .setCustomPrefix(this.getString("prefix")) - .setAutoroleRole(toLong(this.getString("auto_role_id"))) - .setEmbedColor(this.getInt("embed_color")) - .setLeaveTimeout(this.getInt("voice_leave_timeout_seconds")) - .setAnnounceTracks(this.getBoolean("announce_track_enabled")) - .setAllowAllToStop(this.getBoolean("allow_all_to_stop")) - .setServerDesc(this.getString("server_description")) + .setAutoroleRole(toLong(this.getString("autoRole"))) + // .setEmbedColor(this.getInt("embed_color")) // NOTE: this is in a different table + .setLeaveTimeout(this.getInt("leave_timeout")) + .setAnnounceTracks(this.getBoolean("announceNextTrack")) + .setAllowAllToStop(this.getBoolean("allowAllToStop")) + .setServerDesc(this.getString("serverDesc")) // Join/leave - .setWelcomeLeaveChannel(toLong(this.getString("join_leave_channel_id"))) - .setEnableJoinMessage(this.getBoolean("join_message_enabled")) - .setEnableLeaveMessage(this.getBoolean("leave_message_enabled")) - .setCustomJoinMessage(this.getString("join_message")) - .setCustomLeaveMessage(this.getString("leave_message")) + .setWelcomeLeaveChannel(toLong(this.getString("welcomeLeaveChannel"))) + .setEnableJoinMessage(this.getBoolean("enableJoinMessage")) + .setEnableLeaveMessage(this.getBoolean("enableLeaveMessage")) + .setCustomJoinMessage(this.getString("customWelcomeMessage")) + .setCustomLeaveMessage(this.getString("customLeaveMessage")) // moderation - .setLogChannel(toLong(this.getString("log_channel_id"))) - .setMuteRoleId(toLong(this.getString("mute_role_id"))) - .setEnableSwearFilter(this.getBoolean("swear_filter_enabled")) - .setFilterType(this.getString("swear_filter_type")) - .setAiSensitivity(this.getFloat("swear_sensitivity")) - .setAutoDeHoist(this.getBoolean("auto_dehoist_enabled")) - .setFilterInvites(this.getBoolean("invite_filter_enabled")) - .setEnableSpamFilter(this.getBoolean("spam_filter_state")) - .setKickState(this.getBoolean("kick_instead_state")) + .setLogChannel(toLong(this.getString("logChannelId"))) + .setMuteRoleId(toLong(this.getString("muteRoleId"))) + .setEnableSwearFilter(this.getBoolean("enableSwearFilter")) + .setFilterType(this.getString("filterType")) + .setAiSensitivity(this.getFloat("aiSensitivity")) + .setAutoDeHoist(this.getBoolean("autoDeHoist")) + .setFilterInvites(this.getBoolean("filterInvites")) + .setEnableSpamFilter(this.getBoolean("spamFilterState")) + .setKickState(this.getBoolean("kickInsteadState")) .setRatelimits(ratelimmitChecks(this.getString("ratelimits"))) .setSpamThreshold(this.getInt("spam_threshold")) - .setYoungAccountBanEnabled(this.getBoolean("ban_young_account_enabled")) - .setYoungAccountThreshold(this.getInt("ban_young_account_threshold_days")) + .setYoungAccountBanEnabled(this.getBoolean("young_account_ban_enabled")) + .setYoungAccountThreshold(this.getInt("young_account_threshold")) // logging - .setBanLogging(this.getBoolean("ban_logging_enabled")) - .setUnbanLogging(this.getBoolean("unban_logging_enabled")) - .setMuteLogging(this.getBoolean("mute_logging_enabled")) - .setKickLogging(this.getBoolean("kick_logging_enabled")) - .setWarnLogging(this.getBoolean("warn_logging_enabled")) - .setMemberLogging(this.getBoolean("member_logging_enabled")) - .setInviteLogging(this.getBoolean("invite_logging_enabled")) - .setMessageLogging(this.getBoolean("message_logging_enabled")) + .setBanLogging(this.getBoolean("banLogging")) + .setUnbanLogging(this.getBoolean("unbanLogging")) + .setMuteLogging(this.getBoolean("muteLogging")) + .setKickLogging(this.getBoolean("kickLogging")) + .setWarnLogging(this.getBoolean("warnLogging")) + .setMemberLogging(this.getBoolean("memberLogging")) + .setInviteLogging(this.getBoolean("invite_logging")) + .setMessageLogging(this.getBoolean("message_logging")) fun ResultSet.toGuildSetting() = GuildSetting(this.getLong("guild_id")) .setCustomPrefix(this.getString("prefix")) From 362104ae2a300d4d30619f4df7655da353154d2b Mon Sep 17 00:00:00 2001 From: duncte123 Date: Wed, 19 Apr 2023 09:57:17 +0200 Subject: [PATCH 06/20] Bot boots on mysql --- .../listeners/ReadyShutdownListener.java | 2 +- .../skybot/database/MariaDBDatabase.kt | 77 +++++++++++++++++-- .../skybot/database/PostgreDatabase.kt | 12 +-- 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/bot/src/main/java/ml/duncte123/skybot/listeners/ReadyShutdownListener.java b/bot/src/main/java/ml/duncte123/skybot/listeners/ReadyShutdownListener.java index 6e9ac67be..9dd40f945 100644 --- a/bot/src/main/java/ml/duncte123/skybot/listeners/ReadyShutdownListener.java +++ b/bot/src/main/java/ml/duncte123/skybot/listeners/ReadyShutdownListener.java @@ -143,7 +143,7 @@ private void onShutdown() { try { this.variables.getDatabase().close(); } catch (Exception e) { - throw new RuntimeException(e); // hack ;) + LOGGER.error("Failed to close database", e); } LOGGER.info("Bot and JDA shutdown cleanly"); diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt index d1945e847..a64b113f4 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt @@ -249,8 +249,36 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> TODO("Not yet implemented") } - override fun loadAllPatrons(): CompletableFuture { - TODO("Not yet implemented") + override fun loadAllPatrons() = runOnThread { + val patrons = mutableListOf() + val tagPatrons = mutableListOf() + val oneGuildPatrons = mutableListOf() + val guildPatrons = mutableListOf() + + this.connection.use { con -> + con.createStatement().use { smt -> + smt.executeQuery("SELECT * FROM patrons").use { res -> + while (res.next()) { + val idRes = res.getString("guild_id").toLong() + val guildId = if (idRes == 0L) null else idRes + val patron = Patron( + Patron.Type.valueOf(res.getString("type").uppercase()), + res.getString("user_id").toLong(), + guildId + ) + + when (patron.type) { + Patron.Type.NORMAL -> patrons.add(patron) + Patron.Type.TAG -> tagPatrons.add(patron) + Patron.Type.ONE_GUILD -> oneGuildPatrons.add(patron) + Patron.Type.ALL_GUILD -> guildPatrons.add(patron) + } + } + } + } + } + + return@runOnThread AllPatronsData(patrons, tagPatrons, oneGuildPatrons, guildPatrons) } override fun removePatron(userId: Long): CompletableFuture { @@ -323,8 +351,26 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> TODO("Not yet implemented") } - override fun getVcAutoRoles(): CompletableFuture> { - TODO("Not yet implemented") + override fun getVcAutoRoles() = runOnThread { + val roles = mutableListOf() + + this.connection.use { con -> + con.createStatement().use { smt -> + smt.executeQuery("SELECT * FROM vc_auto_roles").use { res -> + while (res.next()) { + roles.add( + VcAutoRole( + res.getString("guild_id").toLong(), + res.getString("voice_channel_id").toLong(), + res.getString("role_id").toLong() + ) + ) + } + } + } + } + + return@runOnThread roles.toList() } override fun setVcAutoRole(guildId: Long, voiceChannelId: Long, roleId: Long): CompletableFuture { @@ -343,8 +389,27 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> TODO("Not yet implemented") } - override fun loadTags(): CompletableFuture> { - TODO("Not yet implemented") + override fun loadTags() = runOnThread { + val tags = mutableListOf() + + this.connection.use { con -> + con.createStatement().use { smt -> + smt.executeQuery("SELECT * FROM tags").use { res -> + while (res.next()) { + tags.add( + Tag( + res.getInt("id"), + res.getString("name"), + res.getString("content"), + res.getString("owner_id").toLong() + ) + ) + } + } + } + } + + return@runOnThread tags.toList() } override fun createTag(tag: Tag): CompletableFuture> { diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt index 94f8ffc6a..1567f5e22 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt @@ -411,10 +411,10 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> } override fun loadAllPatrons() = runOnThread { - val patrons = arrayListOf() - val tagPatrons = arrayListOf() - val oneGuildPatrons = arrayListOf() - val guildPatrons = arrayListOf() + val patrons = mutableListOf() + val tagPatrons = mutableListOf() + val oneGuildPatrons = mutableListOf() + val guildPatrons = mutableListOf() this.connection.use { con -> con.createStatement().use { smt -> @@ -784,7 +784,7 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> } override fun getVcAutoRoles() = runOnThread { - val roles = arrayListOf() + val roles = mutableListOf() this.connection.use { con -> con.createStatement().use { smt -> @@ -853,7 +853,7 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> } override fun loadTags() = runOnThread { - val tags = arrayListOf() + val tags = mutableListOf() this.connection.use { con -> con.createStatement().use { smt -> From f8ee3ea440ea505a40c44a1b27e379dd3e3fcb8b Mon Sep 17 00:00:00 2001 From: duncte123 Date: Sat, 22 Apr 2023 15:19:51 +0200 Subject: [PATCH 07/20] Edit keys in prod --- .../skybot/database/AbstractDatabase.kt | 4 +- .../skybot/database/MariaDBDatabase.kt | 184 ++++++++++++++++-- .../skybot/database/PostgreDatabase.kt | 6 +- 3 files changed, 168 insertions(+), 26 deletions(-) diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt index 301c783ed..b58c9649c 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt @@ -94,7 +94,7 @@ abstract class AbstractDatabase(threads: Int = 2, private val ohShitFn: (Int, In abstract fun loadGuildSetting(guildId: Long): CompletableFuture - abstract fun deleteGuildSetting(guildId: Long): CompletableFuture + open fun deleteGuildSetting(guildId: Long) = purgeGuildSettings(listOf(guildId)) abstract fun purgeGuildSettings(guildIds: List): CompletableFuture @@ -102,7 +102,7 @@ abstract class AbstractDatabase(threads: Int = 2, private val ohShitFn: (Int, In abstract fun registerNewGuild(guildSettings: GuildSetting): CompletableFuture - abstract fun addWordToBlacklist(guildId: Long, word: String): CompletableFuture + open fun addWordToBlacklist(guildId: Long, word: String) = addWordsToBlacklist(guildId, listOf(word)) abstract fun addWordsToBlacklist(guildId: Long, words: List): CompletableFuture diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt index a64b113f4..32e17c9bf 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt @@ -20,14 +20,10 @@ package ml.duncte123.skybot.database import com.dunctebot.models.settings.GuildSetting import com.dunctebot.models.settings.WarnAction +import com.dunctebot.models.utils.Utils import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import io.sentry.Sentry -import liquibase.Contexts -import liquibase.Liquibase -import liquibase.database.jvm.JdbcConnection -import liquibase.resource.ClassLoaderResourceAccessor -import ml.duncte123.skybot.extensions.toGuildSetting import ml.duncte123.skybot.extensions.toGuildSettingMySQL import ml.duncte123.skybot.objects.Tag import ml.duncte123.skybot.objects.api.* @@ -213,28 +209,165 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> return@runOnThread null } - override fun deleteGuildSetting(guildId: Long): CompletableFuture { - TODO("Not yet implemented") - } + override fun purgeGuildSettings(guildIds: List) = runOnThread { + val queries = arrayOf( + // language=MariaDB + "DELETE FROM guildSettings WHERE guildId IN", + // language=MariaDB + "DELETE FROM vc_auto_roles WHERE guild_id IN", + // language=MariaDB + "DELETE FROM guild_blacklists WHERE guild_id IN", + // language=MariaDB + "DELETE FROM warn_actions WHERE guild_id IN", + // language=MariaDB + "DELETE FROM customCommands WHERE guildId IN" + ) - override fun purgeGuildSettings(guildIds: List): CompletableFuture { - TODO("Not yet implemented") - } + val questions = guildIds.joinToString(", ") { "?" } - override fun updateGuildSetting(guildSettings: GuildSetting): CompletableFuture { - TODO("Not yet implemented") + this.connection.use { con -> + queries.forEach { q -> + // language=MariaDB + con.prepareStatement("$q ($questions)").use { smt -> + guildIds.forEachIndexed { index, id -> + smt.setString(index + 1, id.toString()) + } + + smt.execute() + } + } + } } - override fun registerNewGuild(guildSettings: GuildSetting): CompletableFuture { - TODO("Not yet implemented") + override fun updateGuildSetting(guildSettings: GuildSetting) = runOnThread { + this.connection.use { con -> + updateEmbedColor(guildSettings.guildId, guildSettings.embedColor, con) + + // TODO: remove server_description, discord has this feature now + con.prepareStatement( + """UPDATE guildSettings SET + |prefix = ?, + |autoRole = ?, + |leave_timeout = ?, + |announceNextTrack = ?, + |allowAllToStop = ?, + |serverDesc = ?, + | + |welcomeLeaveChannel = ?, + |enableJoinMessage = ?, + |enableLeaveMessage = ?, + |enableJoinMessage = ?, + |customLeaveMessage = ?, + | + |logChannelId = ?, + |muteRoleId = ?, + |enableSwearFilter = ?, + |filterType = ?, + |aiSensitivity = ?, + | + |autoDeHoist = ?, + |filterInvites = ?, + |spamFilterState = ?, + |kickInsteadState = ?, + |ratelimits = ?, + |spam_threshold = ?, + |young_account_ban_enabled = ?, + |young_account_threshold = ?, + | + |banLogging = ?, + |unbanLogging = ?, + |muteLogging = ?, + |warnLogging = ?, + |memberLogging = ?, + |invite_logging = ?, + |message_logging = ? + | + |WHERE guildId = ? + """.trimMargin() + ).use { smt -> + /// + smt.setString(1, guildSettings.customPrefix) + smt.setLong(2, guildSettings.autoroleRole) + smt.setInt(3, guildSettings.leaveTimeout) + smt.setBoolean(4, guildSettings.isAnnounceTracks) + smt.setBoolean(5, guildSettings.isAllowAllToStop) + // TODO: remove, discord has this feature + smt.setString(6, guildSettings.serverDesc) + + smt.setLong(7, guildSettings.welcomeLeaveChannel) + smt.setBoolean(8, guildSettings.isEnableJoinMessage) + smt.setBoolean(9, guildSettings.isEnableLeaveMessage) + smt.setString(10, guildSettings.customJoinMessage) + smt.setString(11, guildSettings.customLeaveMessage) + + smt.setLong(12, guildSettings.logChannel) + smt.setLong(13, guildSettings.muteRoleId) + smt.setBoolean(14, guildSettings.isEnableSwearFilter) + smt.setString(15, guildSettings.filterType.type) + smt.setFloat(16, guildSettings.aiSensitivity) + + smt.setBoolean(17, guildSettings.isAutoDeHoist) + smt.setBoolean(18, guildSettings.isFilterInvites) + smt.setBoolean(19, guildSettings.isEnableSpamFilter) + smt.setBoolean(20, guildSettings.kickState) + smt.setString(21, Utils.convertJ2S(guildSettings.ratelimits)) + smt.setInt(22, guildSettings.spamThreshold) + smt.setBoolean(23, guildSettings.isYoungAccountBanEnabled) + smt.setInt(24, guildSettings.youngAccountThreshold) + + // Logging :) + smt.setBoolean(25, guildSettings.isBanLogging) + smt.setBoolean(26, guildSettings.isUnbanLogging) + smt.setBoolean(27, guildSettings.isMuteLogging) + smt.setBoolean(28, guildSettings.isWarnLogging) + smt.setBoolean(29, guildSettings.isMemberLogging) + smt.setBoolean(30, guildSettings.isInviteLogging) + smt.setBoolean(31, guildSettings.isMessageLogging) + + // What guild? + smt.setString(32, guildSettings.guildId.toString()) + /// + + return@runOnThread smt.execute() + } + } } - override fun addWordToBlacklist(guildId: Long, word: String): CompletableFuture { - TODO("Not yet implemented") + override fun registerNewGuild(guildSettings: GuildSetting) = runOnThread { + this.connection.use { con -> + con.prepareStatement( + """INSERT IGNORE INTO guildSettings(guildId, prefix, customWelcomeMessage, customLeaveMessage) + |VALUES (?, ?, ?, ?); + """.trimMargin() + ).use { smt -> + smt.setLong(1, guildSettings.guildId) + smt.setString(2, guildSettings.customPrefix) + smt.setString(3, guildSettings.customJoinMessage) + smt.setString(4, guildSettings.customLeaveMessage) + + return@runOnThread smt.execute() + } + } } - override fun addWordsToBlacklist(guildId: Long, words: List): CompletableFuture { - TODO("Not yet implemented") + override fun addWordsToBlacklist(guildId: Long, words: List) = runOnThread { + val vals = words.joinToString(", ") { "(?, ?)" } + + this.connection.use { con -> + con.prepareStatement( + "INSERT IGNORE INTO guild_blacklists(guild_id, word) VALUES $vals" + ).use { smt -> + var paramIndex = 0 + words.forEach { word -> + smt.setString(++paramIndex, guildId.toString()) + smt.setString(++paramIndex, word) + } + + smt.execute() + } + } + + return@runOnThread } override fun removeWordFromBlacklist(guildId: Long, word: String): CompletableFuture { @@ -245,6 +378,7 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> TODO("Not yet implemented") } + @Deprecated("Stored in guild settings") override fun updateOrCreateEmbedColor(guildId: Long, color: Int): CompletableFuture { TODO("Not yet implemented") } @@ -475,6 +609,18 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> return -1 } + private fun updateEmbedColor(guildId: Long, color: Int, con: Connection) { + con.prepareStatement( + "INSERT INTO embedSettings (guild_id, embed_color) VALUES(?, ?) ON DUPLICATE KEY UPDATE embed_color = ?" + ).use { smt -> + smt.setString(1, guildId.toString()) + smt.setInt(2, color) + smt.setInt(3, color) + + smt.executeUpdate() + } + } + private fun getBlackListsForGuild(guildId: Long, con: Connection): List { val list = arrayListOf() diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt index 1567f5e22..69de25400 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt @@ -223,8 +223,6 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> return@runOnThread null } - override fun deleteGuildSetting(guildId: Long) = purgeGuildSettings(listOf(guildId)) - override fun purgeGuildSettings(guildIds: List) = runOnThread { val queries = arrayOf( "DELETE FROM guild_settings WHERE guild_id IN", @@ -349,7 +347,7 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> """.trimMargin() ).use { smt -> smt.setLong(1, guildSettings.guildId) - smt.setString(2, "db!") // TODO: bla bla hardcoded + smt.setString(2, guildSettings.customPrefix) smt.setString(3, guildSettings.customJoinMessage) smt.setString(4, guildSettings.customLeaveMessage) @@ -358,8 +356,6 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> } } - override fun addWordToBlacklist(guildId: Long, word: String) = addWordsToBlacklist(guildId, listOf(word)) - override fun addWordsToBlacklist(guildId: Long, words: List) = runOnThread { val vals = words.joinToString(", ") { "(?, ?)" } From eaddf20dbdfe30c693d88ef1ba6b7f73170feb37 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Sat, 22 Apr 2023 15:53:15 +0200 Subject: [PATCH 08/20] Mutes and stuff --- .../skybot/utils/ModerationUtils.java | 2 +- .../skybot/database/MariaDBDatabase.kt | 168 ++++++++++++++++-- .../skybot/database/PostgreDatabase.kt | 13 +- .../skybot/objects/api/WebObjects.kt | 6 +- 4 files changed, 158 insertions(+), 31 deletions(-) diff --git a/bot/src/main/java/ml/duncte123/skybot/utils/ModerationUtils.java b/bot/src/main/java/ml/duncte123/skybot/utils/ModerationUtils.java index 43992bf16..33df2a03a 100644 --- a/bot/src/main/java/ml/duncte123/skybot/utils/ModerationUtils.java +++ b/bot/src/main/java/ml/duncte123/skybot/utils/ModerationUtils.java @@ -197,7 +197,7 @@ public static void handleUnmute(List mutes, AbstractDatabase database, Var final User targetUser = target.getUser(); - LOG.debug("Unmuting " + mute.getUserTag()); + LOG.debug("Unmuting " + mute.getId()); final DunctebotGuild dbGuild = new DunctebotGuild(guild, variables); final long muteRoleId = dbGuild.getSettings().getMuteRoleId(); diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt index 32e17c9bf..b9168757e 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt @@ -31,6 +31,7 @@ import ml.duncte123.skybot.objects.command.CommandResult import ml.duncte123.skybot.objects.command.CustomCommand import java.sql.Connection import java.sql.SQLException +import java.sql.Types import java.time.OffsetDateTime import java.util.concurrent.CompletableFuture @@ -370,17 +371,34 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> return@runOnThread } - override fun removeWordFromBlacklist(guildId: Long, word: String): CompletableFuture { - TODO("Not yet implemented") + override fun removeWordFromBlacklist(guildId: Long, word: String) = runOnThread { + this.connection.use { con -> + con.prepareStatement("DELETE FROM guild_blacklists WHERE guild_id = ? AND word = ?").use { smt -> + smt.setString(1, guildId.toString()) + smt.setString(2, word) + + smt.execute() + } + } + + return@runOnThread } - override fun clearBlacklist(guildId: Long): CompletableFuture { - TODO("Not yet implemented") + override fun clearBlacklist(guildId: Long) = runOnThread { + this.connection.use { con -> + con.prepareStatement("DELETE FROM guild_blacklists WHERE guild_id = ?").use { smt -> + smt.setLong(1, guildId) + smt.execute() + } + } + + return@runOnThread } @Deprecated("Stored in guild settings") - override fun updateOrCreateEmbedColor(guildId: Long, color: Int): CompletableFuture { + override fun updateOrCreateEmbedColor(guildId: Long, color: Int) = runOnThread { TODO("Not yet implemented") + return@runOnThread } override fun loadAllPatrons() = runOnThread { @@ -415,28 +433,102 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> return@runOnThread AllPatronsData(patrons, tagPatrons, oneGuildPatrons, guildPatrons) } - override fun removePatron(userId: Long): CompletableFuture { - TODO("Not yet implemented") + override fun removePatron(userId: Long) = runOnThread { + this.connection.use { con -> + con.prepareStatement("DELETE FROM patrons WHERE user_id = ?").use { smt -> + smt.setLong(1, userId) + + smt.execute() + } + } + + return@runOnThread } - override fun createOrUpdatePatron(patron: Patron): CompletableFuture { - TODO("Not yet implemented") + override fun createOrUpdatePatron(patron: Patron) = runOnThread { + this.createOrUpdatePatronSync(patron) } - override fun addOneGuildPatrons(userId: Long, guildId: Long): CompletableFuture> { - TODO("Not yet implemented") + override fun addOneGuildPatrons(userId: Long, guildId: Long) = runOnThread { + this.createOrUpdatePatronSync(Patron(Patron.Type.ONE_GUILD, userId, guildId)) + + return@runOnThread userId to guildId } - override fun getOneGuildPatron(userId: Long): CompletableFuture { - TODO("Not yet implemented") + private fun createOrUpdatePatronSync(patron: Patron) { + this.connection.use { con -> + con.prepareStatement( + """INSERT INTO patrons(user_id, type, guild_id) + |VALUES (?, ?, ?) ON DUPLICATE KEY + |UPDATE type = ?, guild_id = ? + """.trimMargin() + ).use { smt -> + smt.setString(1, patron.userId.toString()) + smt.setString(2, patron.type.name) + smt.setString(4, patron.type.name) + + if (patron.guildId == null) { + smt.setNull(3, Types.CHAR) + smt.setNull(5, Types.CHAR) + } else { + smt.setString(3, patron.guildId.toString()) + smt.setString(5, patron.guildId.toString()) + } + + smt.execute() + } + } } - override fun createBan(modId: Long, userId: Long, unbanDate: String, guildId: Long): CompletableFuture { - TODO("Not yet implemented") + override fun getOneGuildPatron(userId: Long) = runOnThread { + this.connection.use { con -> + con.prepareStatement("SELECT guild_id FROM patrons WHERE user_id = ? AND type = ?").use { smt -> + smt.setLong(1, userId) + smt.setString(2, Patron.Type.ONE_GUILD.name) + + smt.executeQuery().use { res -> + if (res.next()) { + return@runOnThread res.getLong("guild_id") + } else { + return@runOnThread null + } + } + } + } } - override fun createWarning(modId: Long, userId: Long, guildId: Long, reason: String): CompletableFuture { - TODO("Not yet implemented") + override fun createBan( + modId: Long, + userId: Long, + unbanDate: String, + guildId: Long + ): CompletableFuture = runOnThread { + this.connection.use { con -> + con.prepareStatement( + "INSERT INTO bans (userId, modUserId, guildId, unban_date, ban_date, Username, discriminator) VALUES (?, ?, ?, ?, now(), 'UNUSED', '0000')" + ).use { smt -> + smt.setString(1, userId.toString()) + smt.setString(2, modId.toString()) + smt.setString(3, guildId.toString()) + // TODO: this should be a date datatype + smt.setString(4, unbanDate) + smt.execute() + } + } + } + + override fun createWarning(modId: Long, userId: Long, guildId: Long, reason: String): CompletableFuture = runOnThread { + this.connection.use { con -> + con.prepareStatement( + "INSERT INTO warnings(user_id, mod_id, guild_id, warn_date, reason, expire_date) VALUES (?, ?, ?, now(), ?, now() + interval 6 DAY)" + ).use { smt -> + smt.setLong(1, userId) + smt.setLong(2, modId) + smt.setLong(3, guildId) + smt.setString(4, reason) + smt.execute() + } + } } override fun createMute( @@ -445,8 +537,46 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> userTag: String, unmuteDate: String, guildId: Long - ): CompletableFuture { - TODO("Not yet implemented") + ) = runOnThread { + this.connection.use { con -> + var oldMute: Mute? = null + + con.prepareStatement("SELECT * FROM mutes WHERE guild_id = ? AND user_id = ?").use { smt -> + smt.setString(1, guildId.toString()) + smt.setString(2, userId.toString()) + + smt.executeQuery().use { res -> + if (res.next()) { + oldMute = Mute( + res.getInt("id"), + res.getString("mod_id").toLong(), + res.getString("user_id").toLong(), + "", + res.getString("guild_id").toLong() + ) + } + } + } + + if (oldMute != null) { + con.prepareStatement("DELETE FROM mutes WHERE id = ?").use { smt -> + smt.setInt(1, oldMute!!.id) + smt.execute() + } + } + + con.prepareStatement( + "INSERT INTO mutes(user_id, mod_id, guild_id, unmute_date, user_tag) VALUES (?, ?, ?, ?, 'UNKNOWN#0000')" + ).use { smt -> + smt.setString(1, userId.toString()) + smt.setString(2, modId.toString()) + smt.setString(3, guildId.toString()) + smt.setString(4, unmuteDate) + smt.execute() + } + + return@runOnThread oldMute + } } override fun getWarningsForUser(userId: Long, guildId: Long): CompletableFuture> { diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt index 69de25400..9d2ba48a7 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt @@ -39,6 +39,7 @@ import java.sql.Connection import java.sql.SQLException import java.sql.Types import java.time.OffsetDateTime +import java.util.concurrent.CompletableFuture class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> }) : AbstractDatabase(2, ohShitFn) { private val ds: HikariDataSource @@ -494,12 +495,12 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> smt.executeQuery().use { res -> if (res.next()) { return@runOnThread res.getLong("guild_id") - } else { - return@runOnThread null } } } } + + return@runOnThread null } override fun createBan( @@ -507,7 +508,7 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> userId: Long, unbanDate: String, guildId: Long - ) = runOnThread { + ): CompletableFuture = runOnThread { this.connection.use { con -> con.prepareStatement( "INSERT INTO temp_bans (user_id, mod_id, guild_id, unban_date) VALUES (?, ?, ?, ?)" @@ -520,11 +521,9 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> smt.execute() } } - - return@runOnThread } - override fun createWarning(modId: Long, userId: Long, guildId: Long, reason: String) = runOnThread { + override fun createWarning(modId: Long, userId: Long, guildId: Long, reason: String): CompletableFuture = runOnThread { this.connection.use { con -> con.prepareStatement( "INSERT INTO warnings(user_id, mod_id, guild_id, warn_date, reason) VALUES (?, ?, ?, now(), ?)" @@ -535,8 +534,6 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> smt.setString(4, reason) smt.execute() } - - return@runOnThread } } diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/objects/api/WebObjects.kt b/shared/src/main/kotlin/ml/duncte123/skybot/objects/api/WebObjects.kt index 40f80e2a9..dc0304976 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/objects/api/WebObjects.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/objects/api/WebObjects.kt @@ -42,8 +42,8 @@ data class Ban @JsonProperty("id") val id: Int, @JsonProperty("modUserId") val modId: String, @JsonProperty("userId") val userId: Long, - @JsonProperty("Username") val userName: String, - @JsonProperty("discriminator") val discriminator: String, + @Deprecated("Useless") @JsonProperty("Username") val userName: String, + @Deprecated("Useless") @JsonProperty("discriminator") val discriminator: String, @JsonProperty("guildId") val guildId: String ) @@ -58,7 +58,7 @@ data class Mute @JsonProperty("id") val id: Int, @JsonProperty("mod_id") val modId: Long, @JsonProperty("user_id") val userId: Long, - @JsonProperty("user_tag") val userTag: String, + @Deprecated("Useless") @JsonProperty("user_tag") val userTag: String, @JsonProperty("guild_id") val guildId: Long ) From 2867d6ab434ebaaa4714f1605a993a301c570f25 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Tue, 25 Apr 2023 12:53:28 +0200 Subject: [PATCH 09/20] Most moderator actions --- .../ml/duncte123/skybot/CommandManager.java | 1 + .../commands/music/TestFilterCommand.kt | 43 ++++ .../skybot/database/MariaDBDatabase.kt | 195 ++++++++++++++++-- .../skybot/objects/api/WebObjects.kt | 1 + 4 files changed, 222 insertions(+), 18 deletions(-) create mode 100644 bot/src/main/kotlin/ml/duncte123/skybot/commands/music/TestFilterCommand.kt diff --git a/bot/src/main/java/ml/duncte123/skybot/CommandManager.java b/bot/src/main/java/ml/duncte123/skybot/CommandManager.java index 036b7cae5..8d8ca26fe 100644 --- a/bot/src/main/java/ml/duncte123/skybot/CommandManager.java +++ b/bot/src/main/java/ml/duncte123/skybot/CommandManager.java @@ -283,6 +283,7 @@ public CommandManager(Variables variables) { this.addCommand(new TagCommand(variables)); this.addCommand(new TempBanCommand()); this.addCommand(new TempMuteCommand()); + this.addCommand(new TestFilterCommand()); this.addCommand(new TestTagCommand()); this.addCommand(new TheSearchCommand()); this.addCommand(new ToggleAnnounceTracksCommand()); diff --git a/bot/src/main/kotlin/ml/duncte123/skybot/commands/music/TestFilterCommand.kt b/bot/src/main/kotlin/ml/duncte123/skybot/commands/music/TestFilterCommand.kt new file mode 100644 index 000000000..6fb3e4e2b --- /dev/null +++ b/bot/src/main/kotlin/ml/duncte123/skybot/commands/music/TestFilterCommand.kt @@ -0,0 +1,43 @@ +/* + * Skybot, a multipurpose discord bot + * Copyright (C) 2017 Duncan "duncte123" Sterken & Ramid "ramidzkh" Khan & Maurice R S "Sanduhr32" + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package ml.duncte123.skybot.commands.music + +import lavalink.client.io.filters.Karaoke +import lavalink.client.io.filters.Rotation +import ml.duncte123.skybot.objects.command.CommandContext +import ml.duncte123.skybot.objects.command.MusicCommand + +class TestFilterCommand : MusicCommand() { + init { + this.displayAliasesInHelp = false + } + + override fun run(ctx: CommandContext) { + val player = getLavalinkManager().lavalink.getLink(ctx.guild).player + + player.filters.rotation = Rotation() + player.filters.karaoke = Karaoke().apply { + level = 3f + } + + player.filters.commit() + } + + override fun getName(): String = "testfilter" +} diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt index b9168757e..c7f85b789 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt @@ -579,40 +579,198 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> } } - override fun getWarningsForUser(userId: Long, guildId: Long): CompletableFuture> { - TODO("Not yet implemented") + override fun getWarningsForUser(userId: Long, guildId: Long) = runOnThread { + val warnings = mutableListOf() + + this.connection.use { con -> + con.prepareStatement( + "SELECT * FROM warnings WHERE user_id = ? AND guild_id = ? AND (now() > (warn_date - INTERVAL 6 DAY))" + ).use { smt -> + smt.setString(1, userId.toString()) + smt.setString(2, guildId.toString()) + + smt.executeQuery().use { res -> + while (res.next()) { + warnings.add( + Warning( + res.getInt("id"), + res.getString("warn_date"), + res.getString("mod_id").toLong(), + res.getString("reason"), + res.getString("guild_id").toLong() + ) + ) + } + } + } + } + + return@runOnThread warnings.toList() } - override fun getWarningCountForUser(userId: Long, guildId: Long): CompletableFuture { - TODO("Not yet implemented") + override fun getWarningCountForUser(userId: Long, guildId: Long) = runOnThread { + this.connection.use { con -> + con.prepareStatement( + "SELECT COUNT(id) as amount FROM warnings WHERE user_id = ? AND guild_id = ? AND (now() > (warn_date - INTERVAL 6 DAY))" + ).use { smt -> + smt.setString(1, userId.toString()) + smt.setString(2, guildId.toString()) + + smt.executeQuery().use { res -> + if (res.next()) { + return@runOnThread res.getInt("amount") + } + } + } + } + + return@runOnThread 0 } - override fun deleteLatestWarningForUser(userId: Long, guildId: Long): CompletableFuture { - TODO("Not yet implemented") + override fun deleteLatestWarningForUser(userId: Long, guildId: Long) = runOnThread { + var oldWarning: Warning? = null + + this.connection.use { con -> + con.prepareStatement("SELECT * FROM warnings WHERE user_id = ? AND guild_id = ? ORDER BY id DESC LIMIT 1") + .use { smt -> + smt.setLong(1, userId) + smt.setLong(2, guildId) + + smt.executeQuery().use { res -> + if (res.next()) { + oldWarning = Warning( + res.getInt("id"), + res.getString("warn_date"), + res.getString("mod_id").toLong(), + res.getString("reason"), + res.getString("guild_id").toLong() + ) + } + } + } + + if (oldWarning != null) { + con.prepareStatement("DELETE FROM warnings WHERE id = ?").use { smt -> + smt.setInt(1, oldWarning!!.id) + smt.executeUpdate() + } + } + } + + return@runOnThread oldWarning } - override fun getExpiredBansAndMutes(): CompletableFuture, List>> { - TODO("Not yet implemented") + override fun getExpiredBansAndMutes() = runOnThread { + val bans = mutableListOf() + val mutes = mutableListOf() + + this.connection.use { con -> + con.createStatement().use { smt -> + smt.executeQuery("SELECT * FROM bans WHERE unban_date <= now()").use { res -> + while (res.next()) { + bans.add( + Ban( + res.getInt("id"), + res.getString("modUserId"), + res.getString("userId").toLong(), + "Deleted User", + "0000", + res.getString("guildId") + ) + ) + } + } + } + + con.createStatement().use { smt -> + smt.executeQuery("SELECT * FROM mutes WHERE unmute_date <= now()").use { res -> + while (res.next()) { + mutes.add( + Mute( + res.getInt("id"), + res.getString("mod_id").toLong(), + res.getString("user_id").toLong(), + "Deleted User#0000", + res.getString("guild_id").toLong() + ) + ) + } + } + } + } + + return@runOnThread bans.toList() to mutes.toList() } - override fun purgeBans(ids: List): CompletableFuture { - TODO("Not yet implemented") + override fun purgeBans(ids: List) = runOnThread { + this.connection.use { con -> + val values = ids.joinToString(", ") { "?" } + con.prepareStatement("DELETE FROM bans WHERE id IN ($values)").use { smt -> + ids.forEachIndexed { index, id -> + smt.setInt(index + 1, id) + } + smt.execute() + } + } + + return@runOnThread } - override fun purgeMutes(ids: List): CompletableFuture { - TODO("Not yet implemented") + override fun purgeMutes(ids: List) = runOnThread { + this.connection.use { con -> + val values = ids.joinToString(", ") { "?" } + con.prepareStatement("DELETE FROM mutes WHERE id IN ($values)").use { smt -> + ids.forEachIndexed { index, id -> + smt.setInt(index + 1, id) + } + smt.execute() + } + } + + return@runOnThread } - override fun createBanBypass(guildId: Long, userId: Long): CompletableFuture { - TODO("Not yet implemented") + override fun createBanBypass(guildId: Long, userId: Long) = runOnThread { + this.connection.use { con -> + con.prepareStatement( + "INSERT IGNORE INTO ban_bypasses(guild_id, user_id) VALUES (?, ?)" + ).use { smt -> + smt.setString(1, guildId.toString()) + smt.setString(2, userId.toString()) + smt.execute() + } + } + + return@runOnThread } - override fun getBanBypass(guildId: Long, userId: Long): CompletableFuture { - TODO("Not yet implemented") + override fun getBanBypass(guildId: Long, userId: Long) = runOnThread { + this.connection.use { con -> + con.prepareStatement("SELECT * FROM ban_bypasses WHERE guild_id = ? AND user_id = ?").use { smt -> + smt.setString(1, guildId.toString()) + smt.setString(2, userId.toString()) + + smt.executeQuery().use { res -> + if (res.next()) { + return@runOnThread BanBypas(res.getLong("guild_id"), res.getLong("user_id")) + } + } + } + } + + return@runOnThread null } - override fun deleteBanBypass(banBypass: BanBypas): CompletableFuture { - TODO("Not yet implemented") + override fun deleteBanBypass(banBypass: BanBypas) = runOnThread { + this.connection.use { con -> + con.prepareStatement("DELETE FROM ban_bypasses WHERE guild_id = ? AND user_id = ?").use { smt -> + smt.setString(1, banBypass.guildId.toString()) + smt.setString(2, banBypass.userId.toString()) + smt.execute() + } + } + + return@runOnThread } override fun getVcAutoRoles() = runOnThread { @@ -637,6 +795,7 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> return@runOnThread roles.toList() } + // TODO: constraint in database override fun setVcAutoRole(guildId: Long, voiceChannelId: Long, roleId: Long): CompletableFuture { TODO("Not yet implemented") } diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/objects/api/WebObjects.kt b/shared/src/main/kotlin/ml/duncte123/skybot/objects/api/WebObjects.kt index dc0304976..6c6b7d352 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/objects/api/WebObjects.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/objects/api/WebObjects.kt @@ -37,6 +37,7 @@ data class Warning( val guildId: Long ) +// TODO: make sure id props are longs data class Ban @JsonCreator constructor( @JsonProperty("id") val id: Int, From d43dfe16ded9bf1bb58a85c6780235e9f4c25f87 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Wed, 26 Apr 2023 18:42:50 +0200 Subject: [PATCH 10/20] Finish mysql implementation --- .../listeners/ReadyShutdownListener.java | 7 +- .../skybot/utils/GuildSettingsUtils.java | 6 - .../duncte123/skybot/database/DataTimers.kt | 18 +- .../skybot/entities/jda/DunctebotGuild.kt | 6 +- .../skybot/database/AbstractDatabase.kt | 9 +- .../skybot/database/MariaDBDatabase.kt | 240 ++++++++++++++++-- .../skybot/database/PostgreDatabase.kt | 26 ++ .../duncte123/skybot/database/WebDatabase.kt | 4 + .../skybot/extensions/DatabaseExtensions.kt | 12 + 9 files changed, 287 insertions(+), 41 deletions(-) diff --git a/bot/src/main/java/ml/duncte123/skybot/listeners/ReadyShutdownListener.java b/bot/src/main/java/ml/duncte123/skybot/listeners/ReadyShutdownListener.java index 9dd40f945..3c5c57999 100644 --- a/bot/src/main/java/ml/duncte123/skybot/listeners/ReadyShutdownListener.java +++ b/bot/src/main/java/ml/duncte123/skybot/listeners/ReadyShutdownListener.java @@ -91,9 +91,12 @@ private void onReady(ReadyEvent event) { TimeUnit.DAYS ); - // TODO: mariadb support - if ("psql".equals(this.variables.getConfig().useDatabase)) { + if ( + "psql".equals(this.variables.getConfig().useDatabase) || + "mysql".equals(this.variables.getConfig().useDatabase) + ) { DataTimers.startReminderTimer(this.variables, LOGGER); + DataTimers.startWarningTimer(this.variables, LOGGER); DataTimers.startUnbanTimer(this.variables, LOGGER); } diff --git a/bot/src/main/java/ml/duncte123/skybot/utils/GuildSettingsUtils.java b/bot/src/main/java/ml/duncte123/skybot/utils/GuildSettingsUtils.java index 061a626e2..d2368f912 100644 --- a/bot/src/main/java/ml/duncte123/skybot/utils/GuildSettingsUtils.java +++ b/bot/src/main/java/ml/duncte123/skybot/utils/GuildSettingsUtils.java @@ -100,10 +100,4 @@ private static GuildSetting registerNewGuild(long guildId, Variables variables, return newGuildSettings; } - - public static void updateEmbedColor(long guildId, int color, Variables variables) { - getGuild(guildId, variables).setEmbedColor(color); - // TODO: save guild setting instead, we've deprecated this - variables.getDatabase().updateOrCreateEmbedColor(guildId, color); - } } diff --git a/bot/src/main/kotlin/ml/duncte123/skybot/database/DataTimers.kt b/bot/src/main/kotlin/ml/duncte123/skybot/database/DataTimers.kt index 1f8a7a1b0..5da2a3f0e 100644 --- a/bot/src/main/kotlin/ml/duncte123/skybot/database/DataTimers.kt +++ b/bot/src/main/kotlin/ml/duncte123/skybot/database/DataTimers.kt @@ -28,7 +28,7 @@ import java.util.concurrent.Executors import java.util.concurrent.TimeUnit object DataTimers { - private val pool = Executors.newScheduledThreadPool(2) + private val pool = Executors.newSingleThreadScheduledExecutor() @JvmStatic fun startUnbanTimer(variables: Variables, logger: Logger) { @@ -64,6 +64,22 @@ object DataTimers { ) } + @JvmStatic + fun startWarningTimer(variables: Variables, logger: Logger) { + logger.info("Starting warning timer") + + pool.scheduleAtFixedRate( + { + val db = variables.database + + db.purgeExpiredWarnings() + }, + 0L, + 1L, + TimeUnit.DAYS + ) + } + @JvmStatic private fun checkUnbansAndUnmutes(variables: Variables) { // we're working in a thread here, fuck async :) diff --git a/bot/src/main/kotlin/ml/duncte123/skybot/entities/jda/DunctebotGuild.kt b/bot/src/main/kotlin/ml/duncte123/skybot/entities/jda/DunctebotGuild.kt index d7005a808..c96fd89c8 100644 --- a/bot/src/main/kotlin/ml/duncte123/skybot/entities/jda/DunctebotGuild.kt +++ b/bot/src/main/kotlin/ml/duncte123/skybot/entities/jda/DunctebotGuild.kt @@ -30,10 +30,10 @@ class DunctebotGuild(private val guild: Guild, private val variables: Variables) get() = GuildSettingsUtils.getGuild(this.idLong, this.variables) set(settings) = GuildSettingsUtils.updateGuildSettings(this.idLong, settings, this.variables) - @Deprecated("Stored in settings now") - var color: Int + // @Deprecated("Stored in settings now") + val color: Int get() = EmbedUtils.getColorOrDefault(this.idLong) // TODO: have something that returns default - set(color) = GuildSettingsUtils.updateEmbedColor(this.idLong, color, this.variables) + // set(color) = GuildSettingsUtils.updateEmbedColor(this.idLong, color, this.variables) val hexColor = AirUtils.colorToHex(color) diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt index b58c9649c..ae6ac51eb 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt @@ -163,6 +163,8 @@ abstract class AbstractDatabase(threads: Int = 2, private val ohShitFn: (Int, In abstract fun deleteLatestWarningForUser(userId: Long, guildId: Long): CompletableFuture + abstract fun purgeExpiredWarnings(): CompletableFuture + abstract fun getExpiredBansAndMutes(): CompletableFuture, List>> abstract fun purgeBans(ids: List): CompletableFuture @@ -241,7 +243,12 @@ abstract class AbstractDatabase(threads: Int = 2, private val ohShitFn: (Int, In // Kill the thread after 20 seconds, hopefully this works databaseKiller.schedule({ - runnableFuture.cancel(true) + try { + runnableFuture.cancel(true) + } catch (ex: Throwable) { + Sentry.captureException(ex) + ex.printStackTrace() + } }, 20, TimeUnit.SECONDS) return future diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt index c7f85b789..758ac5003 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt @@ -25,6 +25,9 @@ import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import io.sentry.Sentry import ml.duncte123.skybot.extensions.toGuildSettingMySQL +import ml.duncte123.skybot.extensions.toReminder +import ml.duncte123.skybot.extensions.toReminderMySQL +import ml.duncte123.skybot.extensions.toSQL import ml.duncte123.skybot.objects.Tag import ml.duncte123.skybot.objects.api.* import ml.duncte123.skybot.objects.command.CommandResult @@ -660,6 +663,31 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> return@runOnThread oldWarning } + override fun purgeExpiredWarnings() = runOnThread { + val warningIds = mutableListOf() + + this.connection.use { con -> + con.createStatement().use { smt -> + smt.executeQuery("SELECT * FROM warnings WHERE now() > (warn_date - INTERVAL 6 DAY)").use { res -> + while (res.next()) { + warningIds.add(res.getInt("id")) + } + } + } + + val values = warningIds.joinToString(", ") { "?" } + + con.prepareStatement("DELETE FROM warnings WHERE id in ($values)").use { smt -> + warningIds.forEachIndexed { index, id -> + smt.setInt(index + 1, id) + } + smt.execute() + } + } + + return@runOnThread + } + override fun getExpiredBansAndMutes() = runOnThread { val bans = mutableListOf() val mutes = mutableListOf() @@ -795,21 +823,50 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> return@runOnThread roles.toList() } - // TODO: constraint in database - override fun setVcAutoRole(guildId: Long, voiceChannelId: Long, roleId: Long): CompletableFuture { - TODO("Not yet implemented") - } + override fun setVcAutoRole(guildId: Long, voiceChannelId: Long, roleId: Long) = + setVcAutoRoleBatch(guildId, listOf(voiceChannelId), roleId) - override fun setVcAutoRoleBatch(guildId: Long, voiceChannelIds: List, roleId: Long): CompletableFuture { - TODO("Not yet implemented") + override fun setVcAutoRoleBatch(guildId: Long, voiceChannelIds: List, roleId: Long) = runOnThread { + val values = voiceChannelIds.joinToString(", ") { "(?, ?, ?)" } + + this.connection.use { con -> + con.prepareStatement( + """INSERT IGNORE INTO vc_auto_roles (guild_id, voice_channel_id, role_id) + |VALUES $values + """.trimMargin() + ).use { smt -> + var paramIndex = 0 + voiceChannelIds.forEach { voiceChannelId -> + smt.setString(++paramIndex, guildId.toString()) + smt.setString(++paramIndex, voiceChannelId.toString()) + smt.setString(++paramIndex, roleId.toString()) + } + smt.execute() + } + } + + return@runOnThread } - override fun removeVcAutoRole(voiceChannelId: Long): CompletableFuture { - TODO("Not yet implemented") + override fun removeVcAutoRole(voiceChannelId: Long) = runOnThread { + this.connection.use { con -> + con.prepareStatement("DELETE FROM vc_auto_roles WHERE voice_channel_id = ?").use { smt -> + smt.setString(1, voiceChannelId.toString()) + smt.execute() + } + } + + return@runOnThread } - override fun removeVcAutoRoleForGuild(guildId: Long): CompletableFuture { - TODO("Not yet implemented") + override fun removeVcAutoRoleForGuild(guildId: Long) = runOnThread { + this.connection.use { con -> + con.prepareStatement("DELETE FROM vc_auto_roles WHERE guild_id = ?").use { smt -> + smt.setString(1, guildId.toString()) + smt.execute() + } + } + return@runOnThread } override fun loadTags() = runOnThread { @@ -835,12 +892,36 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> return@runOnThread tags.toList() } - override fun createTag(tag: Tag): CompletableFuture> { - TODO("Not yet implemented") + override fun createTag(tag: Tag) = runOnThread { + this.connection.use { con -> + con.prepareStatement("INSERT INTO tags(owner_id, name, content) VALUES(?, ?, ?)").use { smt -> + smt.setString(1, tag.ownerId.toString()) + smt.setString(2, tag.name) + smt.setString(3, tag.content) + + try { + smt.execute() + return@runOnThread true to "" + } catch (e: SQLException) { + return@runOnThread false to (e.message ?: "Unknown failure") + } + } + } } - override fun deleteTag(tag: Tag): CompletableFuture> { - TODO("Not yet implemented") + override fun deleteTag(tag: Tag) = runOnThread { + this.connection.use { con -> + con.prepareStatement("DELETE FROM tags WHERE id = ?").use { smt -> + smt.setInt(1, tag.id) + + try { + smt.execute() + return@runOnThread true to "" + } catch (e: SQLException) { + return@runOnThread false to (e.message ?: "Unknown failure") + } + } + } } override fun createReminder( @@ -851,32 +932,135 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> messageId: Long, guildId: Long, inChannel: Boolean - ): CompletableFuture> { - TODO("Not yet implemented") + ) = runOnThread { + this.connection.use { con -> + con.prepareStatement( + "INSERT INTO reminders(user_id, guild_id, channel_id, message_id, in_channel, reminder, remind_date) VALUES (?, ?, ?, ?, ?, ?, ?)", + arrayOf("id") // cols to return + ).use { smt -> + smt.setString(1, userId.toString()) + smt.setString(2, guildId.toString()) + smt.setString(3, channelId.toString()) + smt.setString(4, messageId.toString()) + smt.setBoolean(5, inChannel) + smt.setString(6, reminder) + smt.setDate(7, expireDate.toSQL()) + + try { + smt.execute() + + smt.generatedKeys.use { res -> + if (res.next()) { + return@runOnThread true to res.getInt("id") + } + } + } catch (ex: SQLException) { + Sentry.captureException(ex) + } + } + } + + return@runOnThread false to -1 } - override fun removeReminder(reminderId: Int, userId: Long): CompletableFuture { - TODO("Not yet implemented") + override fun removeReminder(reminderId: Int, userId: Long) = runOnThread { + this.connection.use { con -> + con.prepareStatement("DELETE FROM reminders WHERE id = ? AND user_id = ?").use { smt -> + smt.setInt(1, reminderId) + smt.setString(2, userId.toString()) + smt.execute() + } + } + + return@runOnThread true } - override fun showReminder(reminderId: Int, userId: Long): CompletableFuture { - TODO("Not yet implemented") + override fun showReminder(reminderId: Int, userId: Long) = runOnThread { + this.connection.use { con -> + con.prepareStatement("SELECT * FROM reminders WHERE id = ? AND user_id = ?").use { smt -> + smt.setInt(1, reminderId) + smt.setString(2, userId.toString()) + + smt.executeQuery().use { res -> + if (res.next()) { + return@runOnThread res.toReminderMySQL() + } + } + } + } + + return@runOnThread null } - override fun listReminders(userId: Long): CompletableFuture> { - TODO("Not yet implemented") + override fun listReminders(userId: Long) = runOnThread { + val reminders = arrayListOf() + this.connection.use { con -> + con.prepareStatement("SELECT * FROM reminders WHERE user_id = ?").use { smt -> + smt.setString(1, userId.toString()) + smt.executeQuery().use { res -> + while (res.next()) { + reminders.add(res.toReminderMySQL()) + } + } + } + } + + return@runOnThread reminders.toList() } - override fun getExpiredReminders(): CompletableFuture> { - TODO("Not yet implemented") + override fun getExpiredReminders() = runOnThread { + val reminders = mutableListOf() + + this.connection.use { con -> + con.createStatement().executeQuery("SELECT * FROM reminders WHERE now() >= remind_date").use { res -> + while (res.next()) { + reminders.add(res.toReminderMySQL()) + } + } + } + + return@runOnThread reminders.toList() } - override fun purgeReminders(ids: List): CompletableFuture { - TODO("Not yet implemented") + override fun purgeReminders(ids: List) = runOnThread { + val question = ids.joinToString(", ") { "?" } + + this.connection.use { con -> + con.prepareStatement("DELETE FROM reminders WHERE id IN ($question)").use { smt -> + ids.forEachIndexed { index, id -> + smt.setInt(index + 1, id) + } + smt.execute() + } + } + + return@runOnThread } - override fun setWarnActions(guildId: Long, actions: List): CompletableFuture { - TODO("Not yet implemented") + override fun setWarnActions(guildId: Long, actions: List) = runOnThread { + this.connection.use { con -> + con.prepareStatement("DELETE FROM warn_actions WHERE guild_id = ?").use { smt -> + smt.setString(1, guildId.toString()) + smt.execute() + } + + val spots = actions.joinToString(", ") { "(?, ?, ?, ?)" } + con.prepareStatement("INSERT INTO warn_actions(guild_id, type, threshold, duration) VALUES $spots") + .use { smt -> + var paramIndex = 0 + + actions.forEach { + smt.setString(++paramIndex, guildId.toString()) + smt.setString(++paramIndex, it.type.name) + smt.setInt(++paramIndex, it.threshold) + smt.setInt(++paramIndex, it.duration) + } + + smt.execute() + } + } + + return@runOnThread } override fun close() { diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt index 9d2ba48a7..2f7117b3f 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt @@ -664,6 +664,31 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> return@runOnThread oldWarning } + override fun purgeExpiredWarnings() = runOnThread { + val warningIds = mutableListOf() + + this.connection.use { con -> + con.createStatement().use { smt -> + smt.executeQuery("SELECT * FROM warnings WHERE now() > (warn_date - '6 day'::interval)").use { res -> + while (res.next()) { + warningIds.add(res.getInt("id")) + } + } + } + + val values = warningIds.joinToString(", ") { "?" } + + con.prepareStatement("DELETE FROM warnings WHERE id in ($values)").use { smt -> + warningIds.forEachIndexed { index, id -> + smt.setInt(index + 1, id) + } + smt.execute() + } + } + + return@runOnThread + } + override fun getExpiredBansAndMutes() = runOnThread { val bans = mutableListOf() val mutes = mutableListOf() @@ -893,6 +918,7 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> } } + // TODO: figure out what I meant by the statement below // TODO: failures to not work return@runOnThread true to "" } diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/WebDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/WebDatabase.kt index 9c2065d6c..8ce94a677 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/WebDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/WebDatabase.kt @@ -349,6 +349,10 @@ class WebDatabase(private val apis: DuncteApis, private val jackson: ObjectMappe return@runOnThread } + override fun purgeExpiredWarnings(): CompletableFuture { + TODO("Not Supported") + } + override fun close() { // Nothing to close } diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt b/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt index 329438e27..0db13dbff 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt @@ -46,6 +46,18 @@ fun ResultSet.toReminder() = Reminder( this.getBoolean("in_channel") ) +fun ResultSet.toReminderMySQL() = Reminder( + this.getInt("id"), + this.getString("user_id").toLong(), + this.getString("reminder"), + this.getDate("remind_create_date").asInstant(), + this.getDate("remind_date").asInstant(), + this.getString("channel_id").toLong(), + this.getString("message_id").toLong(), + this.getString("guild_id").toLong(), + this.getBoolean("in_channel") +) + fun ResultSet.toGuildSettingMySQL() = GuildSetting(this.getString("guildId").toLong()) .setCustomPrefix(this.getString("prefix")) .setAutoroleRole(toLong(this.getString("autoRole"))) From cc3b67245ea9ce4e72a328fbe4b45adc7e709f57 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Wed, 26 Apr 2023 18:53:24 +0200 Subject: [PATCH 11/20] Strip out web database --- .../main/java/ml/duncte123/skybot/SkyBot.java | 2 - .../java/ml/duncte123/skybot/Variables.java | 2 - .../skybot/database/AbstractDatabase.kt | 6 - .../skybot/database/MariaDBDatabase.kt | 7 - .../skybot/database/PostgreDatabase.kt | 6 - .../duncte123/skybot/database/WebDatabase.kt | 359 --------- .../skybot/objects/api/DuncteApis.kt | 716 ------------------ 7 files changed, 1098 deletions(-) delete mode 100644 shared/src/main/kotlin/ml/duncte123/skybot/database/WebDatabase.kt diff --git a/bot/src/main/java/ml/duncte123/skybot/SkyBot.java b/bot/src/main/java/ml/duncte123/skybot/SkyBot.java index 47efde6d8..7ebd53d60 100644 --- a/bot/src/main/java/ml/duncte123/skybot/SkyBot.java +++ b/bot/src/main/java/ml/duncte123/skybot/SkyBot.java @@ -78,8 +78,6 @@ private SkyBot() throws LoginException { if ("psql".equals(useDatabase)) { logger.info("Using PostgreSQL as database impl"); - } else if ("web".equals(useDatabase)) { - logger.warn("Using web api for all connections, please migrate to PostgreSQL"); } else if ("mysql".equals(useDatabase)) { logger.warn("Using native MariaDB connection, please migrate to PostgreSQL"); } else { diff --git a/bot/src/main/java/ml/duncte123/skybot/Variables.java b/bot/src/main/java/ml/duncte123/skybot/Variables.java index 2a3cd4f1f..0b5f97c2c 100644 --- a/bot/src/main/java/ml/duncte123/skybot/Variables.java +++ b/bot/src/main/java/ml/duncte123/skybot/Variables.java @@ -34,7 +34,6 @@ import ml.duncte123.skybot.database.AbstractDatabase; import ml.duncte123.skybot.database.MariaDBDatabase; import ml.duncte123.skybot.database.PostgreDatabase; -import ml.duncte123.skybot.database.WebDatabase; import ml.duncte123.skybot.objects.DBMap; import ml.duncte123.skybot.objects.api.DuncteApis; import ml.duncte123.skybot.objects.apis.BlargBot; @@ -176,7 +175,6 @@ public AbstractDatabase getDatabase() { this.database = switch (this.config.useDatabase) { case "psql" -> new PostgreDatabase(this.config.jdbcURI, ohShitFn); case "mysql" -> new MariaDBDatabase(this.config.jdbcURI, ohShitFn); - case "web" -> new WebDatabase(this.getApis(), this.getJackson(), ohShitFn); default -> throw new IllegalArgumentException("Unknown database engine: " + this.config.useDatabase); }; } diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt index ae6ac51eb..13d6fc3b5 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt @@ -110,12 +110,6 @@ abstract class AbstractDatabase(threads: Int = 2, private val ohShitFn: (Int, In abstract fun clearBlacklist(guildId: Long): CompletableFuture - // /////////////// - // Embed settings - - @Deprecated("Stored in guild settings") - abstract fun updateOrCreateEmbedColor(guildId: Long, color: Int): CompletableFuture - // ///////////// // Patron stuff diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt index 758ac5003..b0c6a7632 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt @@ -25,7 +25,6 @@ import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import io.sentry.Sentry import ml.duncte123.skybot.extensions.toGuildSettingMySQL -import ml.duncte123.skybot.extensions.toReminder import ml.duncte123.skybot.extensions.toReminderMySQL import ml.duncte123.skybot.extensions.toSQL import ml.duncte123.skybot.objects.Tag @@ -398,12 +397,6 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> return@runOnThread } - @Deprecated("Stored in guild settings") - override fun updateOrCreateEmbedColor(guildId: Long, color: Int) = runOnThread { - TODO("Not yet implemented") - return@runOnThread - } - override fun loadAllPatrons() = runOnThread { val patrons = mutableListOf() val tagPatrons = mutableListOf() diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt index 2f7117b3f..d10cc95d9 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt @@ -401,12 +401,6 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> return@runOnThread } - @Deprecated("Stored in guild settings") - override fun updateOrCreateEmbedColor(guildId: Long, color: Int) = runOnThread { - TODO("Not yet implemented") - return@runOnThread - } - override fun loadAllPatrons() = runOnThread { val patrons = mutableListOf() val tagPatrons = mutableListOf() diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/WebDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/WebDatabase.kt deleted file mode 100644 index 8ce94a677..000000000 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/WebDatabase.kt +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Skybot, a multipurpose discord bot - * Copyright (C) 2017 Duncan "duncte123" Sterken & Ramid "ramidzkh" Khan & Maurice R S "Sanduhr32" - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package ml.duncte123.skybot.database - -import com.dunctebot.models.settings.GuildSetting -import com.dunctebot.models.settings.WarnAction -import com.dunctebot.models.utils.DateUtils -import com.dunctebot.models.utils.Utils -import com.fasterxml.jackson.core.type.TypeReference -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.node.ObjectNode -import ml.duncte123.skybot.objects.Tag -import ml.duncte123.skybot.objects.api.* -import ml.duncte123.skybot.objects.command.CustomCommand -import java.time.OffsetDateTime -import java.util.concurrent.CompletableFuture - -class WebDatabase(private val apis: DuncteApis, private val jackson: ObjectMapper, ohShitFn: (Int, Int) -> Unit = { _, _ -> }) : AbstractDatabase(2, ohShitFn) { - - override fun getCustomCommands() = runOnThread { - val array = apis.getCustomCommands() - - jackson.readValue(array.traverse(), object : TypeReference>() {}) - } - - override fun createCustomCommand(guildId: Long, invoke: String, message: String) = runOnThread { - apis.createCustomCommand(guildId, invoke, message) - } - - override fun updateCustomCommand(guildId: Long, invoke: String, message: String, autoresponse: Boolean) = runOnThread { - apis.updateCustomCommand(guildId, invoke, message, autoresponse) - } - - override fun deleteCustomCommand(guildId: Long, invoke: String) = runOnThread { - apis.deleteCustomCommand(guildId, invoke) - } - - override fun getGuildSettings() = runOnThread { - val array = apis.getGuildSettings() - - jackson.readValue(array.traverse(), object : TypeReference>() {}) - } - - override fun loadGuildSetting(guildId: Long) = runOnThread { - val item = apis.getGuildSetting(guildId) ?: return@runOnThread null - - jackson.readValue(item.traverse(), GuildSetting::class.java) - } - - override fun updateGuildSetting(guildSettings: GuildSetting) = runOnThread { - apis.updateGuildSettings(guildSettings) - } - - override fun deleteGuildSetting(guildId: Long) = runOnThread { - apis.deleteGuildSetting(guildId) - } - - override fun purgeGuildSettings(guildIds: List) = runOnThread { - apis.purgeGuildSettings(guildIds) - } - - override fun registerNewGuild(guildSettings: GuildSetting) = runOnThread { - apis.registerNewGuildSettings(guildSettings) - } - - override fun addWordToBlacklist(guildId: Long, word: String) = runOnThread { - apis.addWordToBlacklist(guildId, word) - } - - override fun addWordsToBlacklist(guildId: Long, words: List) = runOnThread { - apis.addBatchToBlacklist(guildId, words) - } - - override fun removeWordFromBlacklist(guildId: Long, word: String) = runOnThread { - apis.removeWordFromBlacklist(guildId, word) - } - - override fun clearBlacklist(guildId: Long) = runOnThread { - apis.clearBlacklist(guildId) - } - - @Deprecated("Stored in guild settings") - override fun updateOrCreateEmbedColor(guildId: Long, color: Int) = runOnThread { - apis.updateOrCreateEmbedColor(guildId, color) - } - - override fun loadAllPatrons() = runOnThread { - val patrons = arrayListOf() - val tagPatrons = arrayListOf() - val oneGuildPatrons = arrayListOf() - val guildPatrons = arrayListOf() - - apis.loadAllPatrons() - .map { jackson.readValue(it.traverse(), Patron::class.java) } - .forEach { patron -> - when (patron.type) { - Patron.Type.NORMAL -> patrons.add(patron) - Patron.Type.TAG -> tagPatrons.add(patron) - Patron.Type.ONE_GUILD -> oneGuildPatrons.add(patron) - Patron.Type.ALL_GUILD -> guildPatrons.add(patron) - } - } - - return@runOnThread AllPatronsData(patrons, tagPatrons, oneGuildPatrons, guildPatrons) - } - - override fun removePatron(userId: Long) = runOnThread { - apis.deletePatron(userId) - } - - override fun createOrUpdatePatron(patron: Patron) = runOnThread { - apis.createOrUpdatePatron(patron) - } - - override fun addOneGuildPatrons(userId: Long, guildId: Long) = runOnThread { - apis.updateOrCreateOneGuildPatron(userId, guildId) - - return@runOnThread userId to guildId - } - - override fun getOneGuildPatron(userId: Long) = runOnThread { - val patron = apis.getOneGuildPatron(userId) ?: return@runOnThread null - - return@runOnThread patron["guild_id"].asLong() - } - - override fun createBan( - modId: Long, - userId: Long, - unbanDate: String, - guildId: Long - ) = runOnThread { - val json = jackson.createObjectNode() - .put("modUserId", modId.toString()) - .put("Username", "Deleted User") - .put("discriminator", "0000") - .put("userId", userId.toString()) - .put("guildId", guildId.toString()) - .put("unban_date", unbanDate) - - apis.createBan(json) - } - - override fun createWarning(modId: Long, userId: Long, guildId: Long, reason: String) = runOnThread { - apis.createWarning(modId, userId, guildId, reason) - } - - override fun createMute(modId: Long, userId: Long, userTag: String, unmuteDate: String, guildId: Long) = runOnThread { - val json = jackson.createObjectNode() - .put("mod_id", modId.toString()) - .put("user_id", userId.toString()) - .put("user_tag", userTag) - .put("guild_id", guildId.toString()) - .put("unmute_date", unmuteDate) - - val muteData = apis.createMute(json) - - if (muteData.isEmpty) { - return@runOnThread null - } - - val mute: Mute = jackson.readValue(muteData.traverse(), Mute::class.java) - - return@runOnThread mute - } - - override fun deleteLatestWarningForUser(userId: Long, guildId: Long) = runOnThread { - val json = apis.removeLatestWarningForUser(userId, guildId) - - if (json == null) { - return@runOnThread null - } - - return@runOnThread Warning( - json["id"].asInt(), - json["warn_date"].asText(), - json["mod_id"].asLong(), - json["reason"].asText(), - json["guild_id"].asLong() - ) - } - - override fun getWarningsForUser(userId: Long, guildId: Long) = runOnThread { - val data = apis.getWarningsForUser(userId, guildId) - val items = arrayListOf() - - val regex = "\\s+".toRegex() - data.forEach { json -> - items.add( - Warning( - json["id"].asInt(), - json["warn_date"].asText().split(regex)[0], - json["mod_id"].asLong(), - json["reason"].asText(), - json["guild_id"].asLong() - ) - ) - } - - return@runOnThread items.toList() - } - - override fun getWarningCountForUser(userId: Long, guildId: Long) = runOnThread { - apis.getWarningCountForUser(userId, guildId) - } - - override fun getExpiredBansAndMutes(): CompletableFuture, List>> = runOnThread { - TODO("Not supported") - } - - override fun purgeBans(ids: List) = runOnThread { apis.purgeBans(ids) } - - override fun purgeMutes(ids: List) = runOnThread { apis.purgeMutes(ids) } - - override fun getVcAutoRoles() = runOnThread { - val storedData = apis.getVcAutoRoles() - val converted = arrayListOf() - - for (item in storedData) { - converted.add( - VcAutoRole( - item["guild_id"].asLong(), - item["voice_channel_id"].asLong(), - item["role_id"].asLong() - ) - ) - } - - return@runOnThread converted.toList() - } - - override fun setVcAutoRole(guildId: Long, voiceChannelId: Long, roleId: Long) = runOnThread { - apis.setVcAutoRole(guildId, voiceChannelId, roleId) - } - - override fun setVcAutoRoleBatch(guildId: Long, voiceChannelIds: List, roleId: Long) = runOnThread { - apis.setVcAutoRoleBatch(guildId, voiceChannelIds, roleId) - } - - override fun removeVcAutoRole(voiceChannelId: Long) = runOnThread { - apis.removeVcAutoRole(voiceChannelId) - } - - override fun removeVcAutoRoleForGuild(guildId: Long) = runOnThread { - apis.removeVcAutoRoleForGuild(guildId) - } - - override fun loadTags() = runOnThread { - val allTags = apis.getAllTags() - - jackson.readValue(allTags.traverse(), object : TypeReference>() {}) - } - - override fun createTag(tag: Tag) = runOnThread { - val json = jackson.valueToTree(tag) as ObjectNode - json.put("owner_id", json["owner_id"].asText()) - - val response = apis.createTag(json) - - return@runOnThread response.first to response.second - } - - override fun deleteTag(tag: Tag) = runOnThread { - val response = apis.deleteTag(tag.name) - - return@runOnThread response.first to response.second - } - - override fun createReminder( - userId: Long, - reminder: String, - expireDate: OffsetDateTime, - channelId: Long, - messageId: Long, - guildId: Long, - inChannel: Boolean - ) = runOnThread { - val date = DateUtils.getDatabaseDateFormat(expireDate) - val (res, reminderId) = apis.createReminder( - userId, - reminder, - date, - channelId, - messageId, - guildId, - inChannel - ) - - return@runOnThread res to reminderId - } - - override fun removeReminder(reminderId: Int, userId: Long) = runOnThread { - apis.deleteReminder(userId, reminderId) - } - - override fun showReminder(reminderId: Int, userId: Long) = runOnThread { - val reminderJson = apis.showReminder(userId, reminderId) - val reminder: Reminder? = jackson.readValue(reminderJson.traverse(), Reminder::class.java) - - return@runOnThread reminder - } - - override fun listReminders(userId: Long) = runOnThread { - val remindersJson = apis.listReminders(userId) - val reminders = jackson.readValue(remindersJson.traverse(), object : TypeReference>() {}) - - return@runOnThread reminders - } - - override fun getExpiredReminders(): CompletableFuture> = runOnThread { - TODO("Not supported :(") - } - - override fun purgeReminders(ids: List) = runOnThread { apis.purgeReminders(ids) } - - override fun setWarnActions(guildId: Long, actions: List) = runOnThread { - apis.setWarnActions(guildId, actions) - } - - override fun createBanBypass(guildId: Long, userId: Long) = runOnThread { - apis.createBanBypass(guildId, userId) - } - - override fun getBanBypass(guildId: Long, userId: Long) = runOnThread { - val bypassJson = apis.getBanBypass(guildId, userId) - val bypass: BanBypas? = jackson.readValue(bypassJson.traverse(), BanBypas::class.java) - - return@runOnThread bypass - } - - override fun deleteBanBypass(banBypass: BanBypas) = runOnThread { - apis.deleteBanBypass(banBypass.guildId, banBypass.userId) - return@runOnThread - } - - override fun purgeExpiredWarnings(): CompletableFuture { - TODO("Not Supported") - } - - override fun close() { - // Nothing to close - } -} diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/objects/api/DuncteApis.kt b/shared/src/main/kotlin/ml/duncte123/skybot/objects/api/DuncteApis.kt index 71d046e7b..7046e49f7 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/objects/api/DuncteApis.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/objects/api/DuncteApis.kt @@ -18,65 +18,25 @@ package ml.duncte123.skybot.objects.api -import com.dunctebot.models.settings.GuildSetting -import com.dunctebot.models.settings.WarnAction -import com.dunctebot.models.utils.DateUtils -import com.dunctebot.models.utils.Utils import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.node.ArrayNode -import com.fasterxml.jackson.databind.node.NullNode -import com.fasterxml.jackson.databind.node.ObjectNode import com.github.natanbc.reliqua.limiter.RateLimiter import me.duncte123.botcommons.web.ContentType.JSON import me.duncte123.botcommons.web.WebParserUtils import me.duncte123.botcommons.web.WebUtils import me.duncte123.botcommons.web.WebUtils.urlEncodeString import me.duncte123.weebJava.helpers.IOHelper -import ml.duncte123.skybot.objects.command.CommandResult import ml.duncte123.skybot.objects.command.CustomCommand import net.dv8tion.jda.api.sharding.ShardManager import okhttp3.Request -import okhttp3.RequestBody import okhttp3.RequestBody.Companion.toRequestBody import org.slf4j.LoggerFactory -import java.time.OffsetDateTime -import java.time.ZoneOffset import java.util.* class DuncteApis(val apiKey: String, private val mapper: ObjectMapper) { private val logger = LoggerFactory.getLogger(javaClass) - fun getCustomCommands(): ArrayNode { - return paginateData("customcommands") - } - - fun createCustomCommand(guildId: Long, invoke: String, message: String): CommandResult { - val json = mapper.createObjectNode().put("invoke", invoke).put("message", message) - val response = postJSON("customcommands/$guildId", json) - - return parseTripleResponse(response) - } - - fun updateCustomCommand( - guildId: Long, - invoke: String, - message: String, - autoresponse: Boolean - ): CommandResult { - val json = mapper.createObjectNode().put("message", message).put("autoresponse", autoresponse) - val response = patchJSON("customcommands/$guildId/$invoke", json) - - return parseTripleResponse(response) - } - - fun deleteCustomCommand(guildId: Long, invoke: String): Boolean { - val request = defaultRequest("customcommands/$guildId/$invoke").delete() - - return executeRequest(request)["success"].asBoolean() - } - fun restoreCustomCommand(commandId: Int): Pair { val request = defaultRequest("customcommands/$commandId") .put("{}".toRequestBody(null)) @@ -96,409 +56,6 @@ class DuncteApis(val apiKey: String, private val mapper: ObjectMapper) { ) } - fun getGuildSettings(): ArrayNode { - return paginateData("guildsettings") - } - - fun getGuildSetting(guildId: Long): JsonNode? { - val res = executeRequest(defaultRequest("guildsettings/$guildId")) - - if (!res["success"].asBoolean()) { - return null - } - - return res["data"] - } - - fun updateGuildSettings(guildSettings: GuildSetting): Boolean { - val json = guildSettings.toJson(mapper) - val response = patchJSON("guildsettings/${guildSettings.guildId}", json) - - return response["success"].asBoolean() - } - - fun deleteGuildSetting(guildId: Long) { - val response = executeRequest(defaultRequest("guildsettings/$guildId").delete()) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to delete guild setting\n" + - "Response: {}", - response["error"].toString() - ) - } - } - - fun purgeGuildSettings(guildIds: List) { - val json = mapper.createObjectNode() - val arr = json.putArray("ids") - - guildIds.forEach { arr.add(it) } - - val response = deleteJSON("guildsettings/purge", json) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to purge guild settings\n" + - "Response: {}", - response["error"].toString() - ) - } - } - - fun registerNewGuildSettings(guildSettings: GuildSetting): Boolean { - val json = guildSettings.toJson(mapper) - val response = postJSON("guildsettings", json) - val success = response["success"].asBoolean() - - if (!success) { - logger.error( - "Failed to register new guild\n" + - "Response: {}", - response["error"].toString() - ) - } - - return success - } - - fun addWordToBlacklist(guildId: Long, word: String) { - val json = mapper.createObjectNode().put("word", word) - val response = postJSON("guildsettings/$guildId/blacklist", json) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to add word to blacklist for guild {}\nResponse: {}", - guildId, - response["error"].toString() - ) - } - } - - fun addBatchToBlacklist(guildId: Long, words: List) { - val json = mapper.createObjectNode() - val array = json.putArray("words") - words.forEach { array.add(it) } - val response = postJSON("guildsettings/$guildId/blacklist/batch", json) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to batch add to blacklist for guild {}\nResponse: {}", - guildId, - response["error"].toString() - ) - } - } - - fun removeWordFromBlacklist(guildId: Long, word: String) { - val json = mapper.createObjectNode().put("word", word) - val response = deleteJSON("guildsettings/$guildId/blacklist", json) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to remove word from blacklist for guild {}\nResponse: {}", - guildId, - response["error"].toString() - ) - } - } - - fun clearBlacklist(guildId: Long) { - val request = defaultRequest("guildsettings/$guildId/blacklist/all").delete() - val response = executeRequest(request) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to clear blacklist for guild {}\nResponse: {}", - guildId, - response["error"].toString() - ) - } - } - - fun updateOrCreateEmbedColor(guildId: Long, color: Int) { - val json = mapper.createObjectNode().put("embed_color", color) - val response = postJSON("embedsettings/$guildId", json) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to save embed data\n" + - "Response: {}", - response["error"].toString() - ) - } - } - - fun loadAllPatrons(): ArrayNode { - return paginateData("patrons") - } - - fun createOrUpdatePatron(patron: Patron) { - val json = mapper.createObjectNode() - .put("user_id", patron.userId.toString()) - .put("type", patron.type.name) - - if (patron.guildId != null) { - json.put("guild_id", patron.guildId.toString()) - } - - val response = postJSON("patrons", json) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to create or update a patron\n" + - "Response: {}", - response["error"].toString() - ) - } - } - - fun deletePatron(userId: Long) { - val request = defaultRequest("patrons/$userId").delete() - val response = executeRequest(request) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to delete a patron\n" + - "Response: {}", - response["error"].toString() - ) - } - } - - fun updateOrCreateOneGuildPatron(userId: Long, guildId: Long): Boolean { - val json = mapper.createObjectNode() - .put("user_id", userId.toString()).put("guild_id", guildId.toString()) - val response = postJSON("patrons/oneguild", json) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to add one guild patron\n" + - "Response: {}", - response["error"].toString() - ) - } - - return response["success"].asBoolean() - } - - fun getOneGuildPatron(userId: Long): JsonNode? { - val response = executeRequest(defaultRequest("patrons/oneguild/$userId")) - - if (!response["success"].asBoolean()) { - return null - } - - val patrons = response["data"] - - if (patrons.isEmpty) { - return null - } - - return patrons[0] - } - - fun createBan(json: JsonNode) { - val response = postJSON("bans", json) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to create a ban\n" + - "Response: {}", - response["error"].toString() - ) - } - } - - fun createWarning(modId: Long, userId: Long, guildId: Long, reason: String) { - val json = mapper.createObjectNode() - .put("mod_id", modId.toString()) - .put("user_id", userId.toString()) - .put("guild_id", guildId.toString()) - .put("reason", reason) - - val response = postJSON("warns", json) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to create a warning\n" + - "Response: {}", - response["error"].toString() - ) - } - } - - fun createMute(json: JsonNode): JsonNode { - val response = postJSON("mutes", json) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to create a mute\n" + - "Response: {}", - response["error"].toString() - ) - } - - return response["data"] - } - - fun getWarningsForUser(userId: Long, guildId: Long): ArrayNode { - val response = executeRequest(defaultRequest("warns/$userId/$guildId")) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to fetch warnings\n" + - "Response: {}", - response["error"].toString() - ) - - // dummy array node - return mapper.createArrayNode() - } - - return response["data"] as ArrayNode - } - - fun getWarningCountForUser(userId: Long, guildId: Long): Int { - val response = executeRequest(defaultRequest("warns/$userId/$guildId/count")) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to fetch warning count\n" + - "Response: {}", - response["error"].toString() - ) - return 0 - } - - return response["data"].asInt(0) - } - - fun removeLatestWarningForUser(userId: Long, guildId: Long): JsonNode? { - val response = executeRequest(defaultRequest("warns/$userId/$guildId/latest").delete()) - - if (!response["success"].asBoolean() && response["error"]["type"].asText() == "WarningNotFoundException") { - return null - } - - return response["data"] - } - - fun setWarnActions(guildId: Long, warnActions: List) { - val json = mapper.createObjectNode() - - json.putArray("warn_actions") - .addAll(mapper.valueToTree(warnActions)) - - val response = postJSON("guildsettings/$guildId/warn-actions", json) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to set warn actions for $guildId\n" + - "Response: {}", - response["error"].toString() - ) - } - } - - fun purgeBans(ids: List) { - val json = mapper.createObjectNode() - val arr = json.putArray("ids") - - ids.forEach { arr.add(it) } - - val response = deleteJSON("bans", json) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to purge bans\n" + - "Response: {}", - response["error"].toString() - ) - } - } - - fun purgeMutes(ids: List) { - val json = mapper.createObjectNode() - val arr = json.putArray("ids") - - ids.forEach { arr.add(it) } - - val response = deleteJSON("mutes", json) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to purge mutes\n" + - "Response: {}", - response["error"].toString() - ) - } - } - - fun getVcAutoRoles(): ArrayNode { - return paginateData("vcautoroles") - } - - fun setVcAutoRole(guildId: Long, voiceChannelId: Long, roleId: Long) { - val json = mapper.createObjectNode() - .put("guild_id", guildId.toString()) - .put("voice_channel_id", voiceChannelId.toString()) - .put("role_id", roleId.toString()) - - val response = postJSON("vcautoroles", json) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to set vc autorole\n" + - "Response: {}", - response["error"].toString() - ) - } - } - - fun setVcAutoRoleBatch(guildId: Long, voiceChannelIds: List, roleId: Long) { - val json = mapper.createObjectNode() - .put("role_id", roleId.toString()) - val array = json.putArray("voice_channel_ids") - voiceChannelIds.forEach { array.add(it) } - - val response = postJSON("vcautoroles/$guildId", json) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to set vc autorole in batch\n" + - "Response: {}", - response["error"].toString() - ) - } - } - - fun removeVcAutoRole(voiceChannelId: Long) { - val request = defaultRequest("vcautoroles/$voiceChannelId").delete() - val response = executeRequest(request) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to remove vc autorole\n" + - "Response: {}", - response["error"].toString() - ) - } - } - - fun removeVcAutoRoleForGuild(guildId: Long) { - val request = defaultRequest("vcautoroles/guild/$guildId").delete() - val response = executeRequest(request) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to remove vc autorole\n" + - "Response: {}", - response["error"].toString() - ) - } - } - fun decodeToken(token: String): JsonNode { val json = mapper.createObjectNode().put("token", token) @@ -600,156 +157,6 @@ class DuncteApis(val apiKey: String, private val mapper: ObjectMapper) { return postJSONBytes("memes/drakememe", json) } - fun getAllTags(): ArrayNode { - return paginateData("tags") - } - - fun createTag(tag: ObjectNode): Pair { - val response = postJSON("tags", tag) - - if (!response["success"].asBoolean()) { - val error = response["error"] as ObjectNode - - if (error["type"].asText() == "ValidationException") { - return false to buildValidationErrorString(error) - } - - logger.error( - "Failed to create a tag\n" + - "Response: {}", - error.toString() - ) - - return false to error["message"].asText() - } - - return true to "" - } - - fun deleteTag(tagName: String): Pair { - val response = executeRequest(defaultRequest("tags/$tagName").delete()) - - if (!response["success"].asBoolean()) { - val error = response["error"] - - logger.error( - "Failed to create a tag\n" + - "Response: {}", - error.toString() - ) - - return false to error["message"].asText() - } - - return true to "" - } - - fun createReminder( - userId: Long, - reminder: String, - expireDate: String, - channelId: Long, - messageId: Long, - guildId: Long, - inChannel: Boolean - ): Pair { - val obj = mapper.createObjectNode() - .put("user_id", userId.toString()) - .put("channel_id", channelId.toString()) - .put("guild_id", guildId.toString()) - .put("message_id", messageId.toString()) - .put("in_channel", inChannel) - .put("reminder", reminder) - .put("remind_date", expireDate) - .put("remind_create_date", DateUtils.getDatabaseDateFormat(OffsetDateTime.now(ZoneOffset.UTC))) - - val response = postJSON("reminders", obj) - - if (!response["success"].asBoolean()) { - val error = response["error"] - - logger.error( - "Failed to create a reminder\n" + - "Response: {}", - error.toString() - ) - - return false to -1 - } - - return true to response["data"]["id"].asInt() - } - - fun listReminders(userId: Long): JsonNode { - val response = executeRequest(defaultRequest("reminders/$userId")) - - if (!response["success"].asBoolean()) { - val error = response["error"] - - logger.error( - "Failed to get reminders for user\n" + - "Response: {}", - error.toString() - ) - - // Can't use that as jackson will make the list null -// return NullNode.instance - return mapper.createArrayNode() - } - - return response["data"] - } - - fun showReminder(userId: Long, reminderId: Int): JsonNode { - val response = executeRequest(defaultRequest("reminders/$userId/$reminderId")) - - if (!response["success"].asBoolean()) { - val error = response["error"] - - logger.error( - "Failed to get reminders for user\n" + - "Response: {}", - error.toString() - ) - - // NOTE: Jackson will make this null when we parse it - return NullNode.instance - } - - return response["data"] - } - - fun purgeReminders(ids: List) { - val json = mapper.createObjectNode() - val arr = json.putArray("ids") - - ids.forEach { arr.add(it) } - - val response = deleteJSON("reminders/purge", json) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to purge reminders\n" + - "Response: {}", - response["error"].toString() - ) - } - } - - fun deleteReminder(userId: Long, reminderId: Int): Boolean { - val response = executeRequest(defaultRequest("reminders/$userId/$reminderId").delete()) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to delete reminder\n" + - "Response: {}", - response["error"].toString() - ) - } - - return response["success"].asBoolean() - } - fun getAnimal(type: String): JsonNode { return executeDefaultGetRequest("animal/$type", false)["data"] } @@ -775,46 +182,6 @@ class DuncteApis(val apiKey: String, private val mapper: ObjectMapper) { } } - fun createBanBypass(guildId: Long, userId: Long) { - val json = mapper.createObjectNode() - .put("user_id", userId.toString()) - .put("guild_id", guildId.toString()) - - val response = postJSON("bans/bypass", json) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to create ban bypass\n" + - "Response: {}", - response["error"].toString() - ) - } - } - - fun getBanBypass(guildId: Long, userId: Long): JsonNode { - val response = executeRequest(defaultRequest("bans/bypass/$guildId/$userId")) - - if (!response["success"].asBoolean()) { - return NullNode.instance - } - - return response["data"] - } - - fun deleteBanBypass(guildId: Long, userId: Long): Boolean { - val response = executeRequest(defaultRequest("bans/bypass/$guildId/$userId").delete()) - - if (!response["success"].asBoolean()) { - logger.error( - "Failed to delete ban bypass\n" + - "Response: {}", - response["error"].toString() - ) - } - - return response["success"].asBoolean() - } - fun getRCGUrl(): Pair? { val response = executeRequest(defaultRequest("images/rcg/random-v2", false)) @@ -827,42 +194,6 @@ class DuncteApis(val apiKey: String, private val mapper: ObjectMapper) { return data["image"].asText() to data["page"].asText() } - private fun buildValidationErrorString(error: ObjectNode): String { - val errors = error["errors"] - - return buildString { - errors.fieldNames().forEach { - errors[it].forEach { er -> - appendLine(er.toString()) - } - } - } - } - - private fun paginateData(path: String): ArrayNode { - val res = executeRequest(defaultRequest("$path?page=1")) - - val page1 = res["data"] - - val data = page1["data"] as ArrayNode - - val totalPages = page1["last_page"].asInt() + 1 - - for (i in 2 until totalPages) { - val page = executeRequest(defaultRequest("$path?page=$i"))["data"] - - val pageData = page["data"] as ArrayNode - - data.addAll(pageData) - - /*for (i2 in 0 until pageData.length()) { - data.addAll(pageData[i2]) - }*/ - } - - return data - } - private fun postJSONBytes(path: String, json: JsonNode): Pair { val body = json.toJsonString().toRequestBody(null) val request = defaultRequest(path, false) @@ -879,45 +210,6 @@ class DuncteApis(val apiKey: String, private val mapper: ObjectMapper) { .execute() } - private fun parseTripleResponse(response: JsonNode): CommandResult { - val success = response["success"].asBoolean() - - if (success) { - return CommandResult.SUCCESS - } - - val error = response["error"] - val type = error["type"].asText() - - if (type == "AmountException") { - return CommandResult.LIMIT_REACHED - } - - if (type !== "ValidationException") { - return CommandResult.UNKNOWN - } - - val errors = response["error"]["errors"] - - for (key in errors.fieldNames()) { - errors[key].forEach { reason -> - if (reason.asText().contains("The invoke has already been taken.")) { - return CommandResult.COMMAND_EXISTS - } - } - } - - return CommandResult.UNKNOWN - } - - private fun patchJSON(path: String, json: JsonNode, prefixBot: Boolean = true): JsonNode { - val body = json.toJsonString().toRequestBody(null) - val request = defaultRequest(path, prefixBot) - .patch(body).addHeader("Content-Type", JSON.type) - - return executeRequest(request) - } - private fun postJSON(path: String, json: JsonNode, prefixBot: Boolean = true): JsonNode { val body = json.toJsonString().toRequestBody(null) val request = defaultRequest(path, prefixBot) @@ -926,14 +218,6 @@ class DuncteApis(val apiKey: String, private val mapper: ObjectMapper) { return executeRequest(request) } - private fun deleteJSON(path: String, json: JsonNode, prefixBot: Boolean = true): JsonNode { - val body = json.toJsonString().toRequestBody(null) - val request = defaultRequest(path, prefixBot) - .delete(body).addHeader("Content-Type", JSON.type) - - return executeRequest(request) - } - private fun executeRequest(request: Request.Builder): JsonNode { return WebUtils.ins.prepareBuilder( request, From c249d229abd38a64f009a61c9df69b4be3fe95ce Mon Sep 17 00:00:00 2001 From: duncte123 Date: Wed, 26 Apr 2023 18:57:17 +0200 Subject: [PATCH 12/20] Lint code --- .../kotlin/ml/duncte123/skybot/entities/jda/DunctebotGuild.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bot/src/main/kotlin/ml/duncte123/skybot/entities/jda/DunctebotGuild.kt b/bot/src/main/kotlin/ml/duncte123/skybot/entities/jda/DunctebotGuild.kt index c96fd89c8..2a41404e5 100644 --- a/bot/src/main/kotlin/ml/duncte123/skybot/entities/jda/DunctebotGuild.kt +++ b/bot/src/main/kotlin/ml/duncte123/skybot/entities/jda/DunctebotGuild.kt @@ -30,10 +30,8 @@ class DunctebotGuild(private val guild: Guild, private val variables: Variables) get() = GuildSettingsUtils.getGuild(this.idLong, this.variables) set(settings) = GuildSettingsUtils.updateGuildSettings(this.idLong, settings, this.variables) - // @Deprecated("Stored in settings now") val color: Int - get() = EmbedUtils.getColorOrDefault(this.idLong) // TODO: have something that returns default - // set(color) = GuildSettingsUtils.updateEmbedColor(this.idLong, color, this.variables) + get() = EmbedUtils.getColorOrDefault(this.idLong) val hexColor = AirUtils.colorToHex(color) From f9f8864a401b73078edb1b41147e1dc2efc47651 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Wed, 26 Apr 2023 20:55:50 +0200 Subject: [PATCH 13/20] When you tell java to use UTC but it is still in local time --- .../guild/owner/CustomCommandCommand.java | 29 ++++++++----------- .../ml/duncte123/skybot/utils/AirUtils.java | 5 +++- .../com/dunctebot/models/utils/DateUtils.java | 17 +++++++++-- .../skybot/database/MariaDBDatabase.kt | 24 ++++++++------- .../skybot/database/PostgreDatabase.kt | 16 +++++----- .../skybot/extensions/DatabaseExtensions.kt | 13 +++++---- 6 files changed, 59 insertions(+), 45 deletions(-) diff --git a/bot/src/main/java/ml/duncte123/skybot/commands/guild/owner/CustomCommandCommand.java b/bot/src/main/java/ml/duncte123/skybot/commands/guild/owner/CustomCommandCommand.java index b69393303..4888e55f2 100644 --- a/bot/src/main/java/ml/duncte123/skybot/commands/guild/owner/CustomCommandCommand.java +++ b/bot/src/main/java/ml/duncte123/skybot/commands/guild/owner/CustomCommandCommand.java @@ -95,17 +95,19 @@ private void deleteOrShowCustomCommand(List args, CommandContext ctx, Co //Check for deleting if ("raw".equalsIgnoreCase(args.get(0))) { - if (!commandExists(commandName, guildId, manager)) { + final var cmd = manager.getCustomCommand(name, guildId); + + if (cmd == null) { sendMsg(ctx, "No command was found for this name"); return; } - final CustomCommand cmd = manager.getCustomCommand(commandName, guildId); final String escaped = cmd.getMessage().replaceAll("`", ""); sendMsg(ctx, "Raw data for `" + commandName + "`:```pascal\n" + escaped + "\n```"); } else if ("delete".equalsIgnoreCase(args.get(0)) || "remove".equalsIgnoreCase(args.get(0))) { + final var cmd = manager.getCustomCommand(name, guildId); - if (!commandExists(commandName, guildId, manager)) { + if (cmd == null) { sendMsg(ctx, "No command was found for this name"); return; } @@ -138,9 +140,10 @@ private void addOrEditCustomCommand(List args, CommandContext ctx, Comma final String commandAction = String.join(" ", args.subList(2, args.size())); final long guildId = ctx.getGuild().getIdLong(); + final var cmd = manager.getCustomCommand(name, guildId); - if (commandExists(commandName, guildId, manager)) { - editCustomCommand(args, ctx, manager, commandName, commandAction, guildId); + if (cmd != null) { + editCustomCommand(args, ctx, manager, cmd, commandAction); return; } @@ -150,7 +153,7 @@ private void addOrEditCustomCommand(List args, CommandContext ctx, Comma private void createCustomCommand(CommandContext ctx, CommandManager manager, String commandName, String commandAction, long guildId) { try { - final CommandResult result = registerCustomCommand(commandName, commandAction, guildId, manager); + final CommandResult result = manager.registerCustomCommand(new CustomCommand(commandName, commandAction, guildId, false)); if (result == CommandResult.SUCCESS) { sendMsg(ctx, "Command added."); @@ -176,22 +179,18 @@ private void createCustomCommand(CommandContext ctx, CommandManager manager, Str } } - private void editCustomCommand(List args, CommandContext ctx, CommandManager manager, String commandName, String commandAction, long guildId) { + private void editCustomCommand(List args, CommandContext ctx, CommandManager manager, CustomCommand cmd, String newAction) { if (!"edit".equalsIgnoreCase(args.get(0)) && !"change".equalsIgnoreCase(args.get(0))) { - sendMsg(ctx, "A command already exists for this server."); + sendMsg(ctx, "A command with this name already exists for this server."); return; } - if (editCustomCommand(manager.getCustomCommand(commandName, guildId), commandAction, manager)) { + if (editCustomCommand(cmd, newAction, manager)) { sendMsg(ctx, "The command has been updated."); } } - private CommandResult registerCustomCommand(String name, String action, long guildId, CommandManager manager) { - return manager.registerCustomCommand(new CustomCommand(name, action, guildId, false)); - } - private boolean editCustomCommand(@Nullable CustomCommand customCommand, String newMessage, CommandManager manager) { if (customCommand == null) { return false; @@ -206,8 +205,4 @@ private boolean editCustomCommand(@Nullable CustomCommand customCommand, String return manager.editCustomCommand(cmd); } - - private boolean commandExists(String name, long guild, CommandManager manager) { - return manager.getCustomCommand(name, guild) != null; - } } diff --git a/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java b/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java index ae913d7d3..68b577e9b 100644 --- a/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java +++ b/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java @@ -237,6 +237,7 @@ public static void handleExpiredReminders(List reminders, AbstractData final List toPurge = new ArrayList<>(); for (final Reminder reminder : reminders) { + System.out.println("Expire date " + reminder.getReminder_date()); // The reminder message template final String message = String.format( "%s you asked me to remind you about \"%s\"", @@ -285,7 +286,9 @@ public static void handleExpiredReminders(List reminders, AbstractData // we cannot dm this user (has dms blocked?) errorResponse == ErrorResponse.CANNOT_SEND_TO_USER ) { - toPurge.add(reminder.getId()); + // toPurge.add(reminder.getId()); + } else { + errorResponseEx.printStackTrace(); } } catch (Exception e) { diff --git a/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java b/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java index 127c20244..8b1fba713 100644 --- a/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java +++ b/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java @@ -28,8 +28,7 @@ import me.duncte123.durationparser.ParsedDuration; import net.dv8tion.jda.api.utils.TimeFormat; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; +import java.time.*; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalAccessor; @@ -39,6 +38,18 @@ public static String makeDatePretty(TemporalAccessor accessor) { return TimeFormat.DATE_TIME_LONG.format(accessor); } + public static OffsetDateTime fromMysqlFormat(String date) { + try { + System.out.println(date.replace(" ", "T") + ZoneOffset.UTC.getId()); + return OffsetDateTime.parse(date.replace(" ", "T") + ZoneOffset.UTC.getId()); + } + catch (DateTimeParseException e) { + e.printStackTrace(); + + return OffsetDateTime.now(ZoneOffset.UTC); + } + } + public static OffsetDateTime fromDatabaseFormat(String date) { try { return OffsetDateTime.parse(date); @@ -59,6 +70,6 @@ public static String getDatabaseDateFormat(OffsetDateTime date) { } public static OffsetDateTime getDatabaseDate(ParsedDuration duration) { - return OffsetDateTime.now(ZoneOffset.UTC).plus(duration.getMilis(), ChronoUnit.MILLIS); + return OffsetDateTime.now(ZoneId.of("+00:00")).plus(duration.getMilis(), ChronoUnit.MILLIS); } } diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt index b0c6a7632..33b8c2607 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt @@ -24,9 +24,7 @@ import com.dunctebot.models.utils.Utils import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import io.sentry.Sentry -import ml.duncte123.skybot.extensions.toGuildSettingMySQL -import ml.duncte123.skybot.extensions.toReminderMySQL -import ml.duncte123.skybot.extensions.toSQL +import ml.duncte123.skybot.extensions.* import ml.duncte123.skybot.objects.Tag import ml.duncte123.skybot.objects.api.* import ml.duncte123.skybot.objects.command.CommandResult @@ -35,6 +33,7 @@ import java.sql.Connection import java.sql.SQLException import java.sql.Types import java.time.OffsetDateTime +import java.time.ZoneOffset import java.util.concurrent.CompletableFuture class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> }) : AbstractDatabase(2, ohShitFn) { @@ -668,13 +667,15 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> } } - val values = warningIds.joinToString(", ") { "?" } + if (warningIds.isNotEmpty()) { + val values = warningIds.joinToString(", ") { "?" } - con.prepareStatement("DELETE FROM warnings WHERE id in ($values)").use { smt -> - warningIds.forEachIndexed { index, id -> - smt.setInt(index + 1, id) + con.prepareStatement("DELETE FROM warnings WHERE id in ($values)").use { smt -> + warningIds.forEachIndexed { index, id -> + smt.setInt(index + 1, id) + } + smt.execute() } - smt.execute() } } @@ -929,7 +930,7 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> this.connection.use { con -> con.prepareStatement( "INSERT INTO reminders(user_id, guild_id, channel_id, message_id, in_channel, reminder, remind_date) VALUES (?, ?, ?, ?, ?, ?, ?)", - arrayOf("id") // cols to return + arrayOf("insert_id") // cols to return ).use { smt -> smt.setString(1, userId.toString()) smt.setString(2, guildId.toString()) @@ -937,18 +938,19 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> smt.setString(4, messageId.toString()) smt.setBoolean(5, inChannel) smt.setString(6, reminder) - smt.setDate(7, expireDate.toSQL()) + smt.setTimestamp(7, expireDate.toSQLTimestamp()) try { smt.execute() smt.generatedKeys.use { res -> if (res.next()) { - return@runOnThread true to res.getInt("id") + return@runOnThread true to res.getInt("insert_id") } } } catch (ex: SQLException) { Sentry.captureException(ex) + ex.printStackTrace() } } } diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt index d10cc95d9..f3dc19075 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt @@ -30,7 +30,7 @@ import liquibase.database.jvm.JdbcConnection import liquibase.resource.ClassLoaderResourceAccessor import ml.duncte123.skybot.extensions.toGuildSetting import ml.duncte123.skybot.extensions.toReminder -import ml.duncte123.skybot.extensions.toSQL +import ml.duncte123.skybot.extensions.toSQLTimestamp import ml.duncte123.skybot.objects.Tag import ml.duncte123.skybot.objects.api.* import ml.duncte123.skybot.objects.command.CommandResult @@ -670,13 +670,15 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> } } - val values = warningIds.joinToString(", ") { "?" } + if (warningIds.isNotEmpty()) { + val values = warningIds.joinToString(", ") { "?" } - con.prepareStatement("DELETE FROM warnings WHERE id in ($values)").use { smt -> - warningIds.forEachIndexed { index, id -> - smt.setInt(index + 1, id) + con.prepareStatement("DELETE FROM warnings WHERE id in ($values)").use { smt -> + warningIds.forEachIndexed { index, id -> + smt.setInt(index + 1, id) + } + smt.execute() } - smt.execute() } } @@ -937,7 +939,7 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> smt.setLong(4, messageId) smt.setBoolean(5, inChannel) smt.setString(6, reminder) - smt.setDate(7, expireDate.toSQL()) + smt.setTimestamp(7, expireDate.toSQLTimestamp()) try { smt.execute() diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt b/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt index 0db13dbff..73492f842 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt @@ -20,7 +20,6 @@ package ml.duncte123.skybot.extensions import com.dunctebot.models.settings.GuildSetting import com.dunctebot.models.utils.DateUtils -import com.dunctebot.models.utils.Utils import com.dunctebot.models.utils.Utils.ratelimmitChecks import com.dunctebot.models.utils.Utils.toLong import ml.duncte123.skybot.objects.api.Reminder @@ -31,15 +30,17 @@ import java.time.ZoneOffset import java.time.temporal.TemporalAccessor fun TemporalAccessor.toSQL() = java.sql.Date(Instant.from(this).toEpochMilli()) +fun TemporalAccessor.toSQLTimestamp() = java.sql.Timestamp(Instant.from(this).toEpochMilli()) fun java.sql.Date.asInstant() = OffsetDateTime.ofInstant(Instant.ofEpochMilli(this.time), ZoneOffset.UTC) -fun String.toDate() = DateUtils.fromDatabaseFormat(this).toSQL() +fun java.sql.Timestamp.asInstant() = OffsetDateTime.ofInstant(Instant.ofEpochMilli(this.time), ZoneOffset.UTC) +fun String.toDate() = DateUtils.fromMysqlFormat(this).toSQL() fun ResultSet.toReminder() = Reminder( this.getInt("id"), this.getLong("user_id"), this.getString("reminder"), - this.getDate("created_at").asInstant(), - this.getDate("remind_on").asInstant(), + this.getTimestamp("created_at").asInstant(), + this.getTimestamp("remind_on").asInstant(), this.getLong("channel_id"), this.getLong("message_id"), this.getLong("guild_id"), @@ -50,8 +51,8 @@ fun ResultSet.toReminderMySQL() = Reminder( this.getInt("id"), this.getString("user_id").toLong(), this.getString("reminder"), - this.getDate("remind_create_date").asInstant(), - this.getDate("remind_date").asInstant(), + this.getTimestamp("remind_create_date").asInstant(), + this.getTimestamp("remind_date").asInstant(), this.getString("channel_id").toLong(), this.getString("message_id").toLong(), this.getString("guild_id").toLong(), From 55c5d1561545272c4bda8a4bb8498f47de6124b0 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Wed, 26 Apr 2023 21:28:57 +0200 Subject: [PATCH 14/20] getting closer --- .../commands/essentials/RemindmeCommand.java | 2 ++ .../ml/duncte123/skybot/utils/AirUtils.java | 1 + .../com/dunctebot/models/utils/DateUtils.java | 24 +++++++++++++++---- .../skybot/database/MariaDBDatabase.kt | 4 ++-- .../skybot/database/PostgreDatabase.kt | 4 ++-- .../skybot/extensions/DatabaseExtensions.kt | 11 ++++----- 6 files changed, 31 insertions(+), 15 deletions(-) diff --git a/bot/src/main/java/ml/duncte123/skybot/commands/essentials/RemindmeCommand.java b/bot/src/main/java/ml/duncte123/skybot/commands/essentials/RemindmeCommand.java index 0abb97cd6..5a569acbb 100644 --- a/bot/src/main/java/ml/duncte123/skybot/commands/essentials/RemindmeCommand.java +++ b/bot/src/main/java/ml/duncte123/skybot/commands/essentials/RemindmeCommand.java @@ -113,6 +113,8 @@ public void execute(@Nonnull CommandContext ctx) { final OffsetDateTime expireDate = getDatabaseDate(duration); + System.out.println(expireDate); + createReminder(ctx, expireDate, reminder, flags, duration); } diff --git a/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java b/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java index 68b577e9b..55a55bde6 100644 --- a/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java +++ b/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java @@ -238,6 +238,7 @@ public static void handleExpiredReminders(List reminders, AbstractData for (final Reminder reminder : reminders) { System.out.println("Expire date " + reminder.getReminder_date()); + System.out.println("Crate date " + reminder.getCreate_date()); // The reminder message template final String message = String.format( "%s you asked me to remind you about \"%s\"", diff --git a/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java b/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java index 8b1fba713..3b9864e93 100644 --- a/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java +++ b/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java @@ -28,28 +28,42 @@ import me.duncte123.durationparser.ParsedDuration; import net.dv8tion.jda.api.utils.TimeFormat; +import java.sql.Timestamp; import java.time.*; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalAccessor; public class DateUtils { + public static final ZoneId DB_ZONE_ID = ZoneId.of("Europe/London"); + public static String makeDatePretty(TemporalAccessor accessor) { return TimeFormat.DATE_TIME_LONG.format(accessor); } public static OffsetDateTime fromMysqlFormat(String date) { try { - System.out.println(date.replace(" ", "T") + ZoneOffset.UTC.getId()); - return OffsetDateTime.parse(date.replace(" ", "T") + ZoneOffset.UTC.getId()); + System.out.println(date.replace(" ", "T") + DB_ZONE_ID.getId()); + return OffsetDateTime.parse(date.replace(" ", "T") + DB_ZONE_ID.getId()); } catch (DateTimeParseException e) { e.printStackTrace(); - return OffsetDateTime.now(ZoneOffset.UTC); + return OffsetDateTime.now(DB_ZONE_ID); } } + // TODO: use UTC in the future + public static Timestamp getSqlTimestamp(OffsetDateTime date) { + final var zonedDate = date.toZonedDateTime().withZoneSameInstant(DB_ZONE_ID); + final var shouldWork = zonedDate.toString() + .replace("Z", "") + .replace("T", " ") + .split("\\+")[0]; + + return Timestamp.valueOf(shouldWork); + } + public static OffsetDateTime fromDatabaseFormat(String date) { try { return OffsetDateTime.parse(date); @@ -57,7 +71,7 @@ public static OffsetDateTime fromDatabaseFormat(String date) { catch (DateTimeParseException e) { e.printStackTrace(); - return OffsetDateTime.now(ZoneOffset.UTC); + return OffsetDateTime.now(DB_ZONE_ID); } } @@ -70,6 +84,6 @@ public static String getDatabaseDateFormat(OffsetDateTime date) { } public static OffsetDateTime getDatabaseDate(ParsedDuration duration) { - return OffsetDateTime.now(ZoneId.of("+00:00")).plus(duration.getMilis(), ChronoUnit.MILLIS); + return OffsetDateTime.now(DB_ZONE_ID).plus(duration.getMilis(), ChronoUnit.MILLIS); } } diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt index 33b8c2607..1d7ac62d7 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt @@ -33,7 +33,6 @@ import java.sql.Connection import java.sql.SQLException import java.sql.Types import java.time.OffsetDateTime -import java.time.ZoneOffset import java.util.concurrent.CompletableFuture class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> }) : AbstractDatabase(2, ohShitFn) { @@ -932,13 +931,14 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> "INSERT INTO reminders(user_id, guild_id, channel_id, message_id, in_channel, reminder, remind_date) VALUES (?, ?, ?, ?, ?, ?, ?)", arrayOf("insert_id") // cols to return ).use { smt -> + println(expireDate.toSQL()) smt.setString(1, userId.toString()) smt.setString(2, guildId.toString()) smt.setString(3, channelId.toString()) smt.setString(4, messageId.toString()) smt.setBoolean(5, inChannel) smt.setString(6, reminder) - smt.setTimestamp(7, expireDate.toSQLTimestamp()) + smt.setTimestamp(7, expireDate.toSQL()) try { smt.execute() diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt index f3dc19075..de589d855 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt @@ -30,7 +30,7 @@ import liquibase.database.jvm.JdbcConnection import liquibase.resource.ClassLoaderResourceAccessor import ml.duncte123.skybot.extensions.toGuildSetting import ml.duncte123.skybot.extensions.toReminder -import ml.duncte123.skybot.extensions.toSQLTimestamp +import ml.duncte123.skybot.extensions.toSQL import ml.duncte123.skybot.objects.Tag import ml.duncte123.skybot.objects.api.* import ml.duncte123.skybot.objects.command.CommandResult @@ -939,7 +939,7 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> smt.setLong(4, messageId) smt.setBoolean(5, inChannel) smt.setString(6, reminder) - smt.setTimestamp(7, expireDate.toSQLTimestamp()) + smt.setTimestamp(7, expireDate.toSQL()) try { smt.execute() diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt b/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt index 73492f842..9890732ff 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt @@ -20,19 +20,18 @@ package ml.duncte123.skybot.extensions import com.dunctebot.models.settings.GuildSetting import com.dunctebot.models.utils.DateUtils +import com.dunctebot.models.utils.DateUtils.DB_ZONE_ID +import com.dunctebot.models.utils.DateUtils.getSqlTimestamp import com.dunctebot.models.utils.Utils.ratelimmitChecks import com.dunctebot.models.utils.Utils.toLong import ml.duncte123.skybot.objects.api.Reminder import java.sql.ResultSet import java.time.Instant import java.time.OffsetDateTime -import java.time.ZoneOffset -import java.time.temporal.TemporalAccessor -fun TemporalAccessor.toSQL() = java.sql.Date(Instant.from(this).toEpochMilli()) -fun TemporalAccessor.toSQLTimestamp() = java.sql.Timestamp(Instant.from(this).toEpochMilli()) -fun java.sql.Date.asInstant() = OffsetDateTime.ofInstant(Instant.ofEpochMilli(this.time), ZoneOffset.UTC) -fun java.sql.Timestamp.asInstant() = OffsetDateTime.ofInstant(Instant.ofEpochMilli(this.time), ZoneOffset.UTC) +fun OffsetDateTime.toSQL() = getSqlTimestamp(this) +// TODO: still an hour in the past? +fun java.sql.Timestamp.asInstant() = OffsetDateTime.ofInstant(Instant.ofEpochMilli(this.time), DB_ZONE_ID) fun String.toDate() = DateUtils.fromMysqlFormat(this).toSQL() fun ResultSet.toReminder() = Reminder( From 755d9880f99adb147a9765c17554737ecf898cff Mon Sep 17 00:00:00 2001 From: duncte123 Date: Thu, 27 Apr 2023 09:00:45 +0200 Subject: [PATCH 15/20] It works --- .../src/main/java/com/dunctebot/models/utils/DateUtils.java | 5 ++++- .../ml/duncte123/skybot/extensions/DatabaseExtensions.kt | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java b/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java index 3b9864e93..628a42c05 100644 --- a/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java +++ b/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java @@ -30,6 +30,7 @@ import java.sql.Timestamp; import java.time.*; +import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalAccessor; @@ -44,7 +45,9 @@ public static String makeDatePretty(TemporalAccessor accessor) { public static OffsetDateTime fromMysqlFormat(String date) { try { System.out.println(date.replace(" ", "T") + DB_ZONE_ID.getId()); - return OffsetDateTime.parse(date.replace(" ", "T") + DB_ZONE_ID.getId()); + return LocalDateTime.parse(date.replace(" ", "T"), DateTimeFormatter.ISO_DATE_TIME) + .atZone(DB_ZONE_ID) + .toOffsetDateTime(); } catch (DateTimeParseException e) { e.printStackTrace(); diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt b/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt index 9890732ff..3b513670a 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt @@ -28,11 +28,13 @@ import ml.duncte123.skybot.objects.api.Reminder import java.sql.ResultSet import java.time.Instant import java.time.OffsetDateTime +import java.time.ZoneOffset fun OffsetDateTime.toSQL() = getSqlTimestamp(this) // TODO: still an hour in the past? fun java.sql.Timestamp.asInstant() = OffsetDateTime.ofInstant(Instant.ofEpochMilli(this.time), DB_ZONE_ID) fun String.toDate() = DateUtils.fromMysqlFormat(this).toSQL() +fun String.toJavaDate() = DateUtils.fromMysqlFormat(this) fun ResultSet.toReminder() = Reminder( this.getInt("id"), @@ -50,8 +52,8 @@ fun ResultSet.toReminderMySQL() = Reminder( this.getInt("id"), this.getString("user_id").toLong(), this.getString("reminder"), - this.getTimestamp("remind_create_date").asInstant(), - this.getTimestamp("remind_date").asInstant(), + this.getString("remind_create_date").toJavaDate(), + this.getString("remind_date").toJavaDate(), this.getString("channel_id").toLong(), this.getString("message_id").toLong(), this.getString("guild_id").toLong(), From 0afdc3fcbc95069fc1122722369c0a49cc119e86 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Thu, 27 Apr 2023 11:38:31 +0200 Subject: [PATCH 16/20] Cleanup --- .../ml/duncte123/skybot/CommandManager.java | 10 +++---- .../commands/essentials/RemindmeCommand.java | 6 ++--- .../ml/duncte123/skybot/utils/AirUtils.java | 4 +-- .../skybot/commands/music/SaveCommand.kt | 4 +-- .../com/dunctebot/models/utils/DateUtils.java | 27 ++++++++++--------- .../skybot/database/AbstractDatabase.kt | 5 ++-- .../skybot/database/MariaDBDatabase.kt | 8 +++--- .../skybot/database/PostgreDatabase.kt | 4 +-- .../skybot/extensions/DatabaseExtensions.kt | 9 +++---- .../skybot/objects/api/WebObjects.kt | 7 +++-- 10 files changed, 42 insertions(+), 42 deletions(-) diff --git a/bot/src/main/java/ml/duncte123/skybot/CommandManager.java b/bot/src/main/java/ml/duncte123/skybot/CommandManager.java index 8d8ca26fe..6788a1d4f 100644 --- a/bot/src/main/java/ml/duncte123/skybot/CommandManager.java +++ b/bot/src/main/java/ml/duncte123/skybot/CommandManager.java @@ -76,8 +76,8 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.time.Instant; -import java.time.OffsetDateTime; import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.concurrent.*; @@ -414,7 +414,7 @@ public void runCommand(MessageReceivedEvent event, String customPrefix) { } public void setCooldown(String key, int seconds) { - COOLDOWNS.put(key, OffsetDateTime.now(ZoneOffset.UTC).plusSeconds(seconds).toEpochSecond()); + COOLDOWNS.put(key, ZonedDateTime.now(ZoneOffset.UTC).plusSeconds(seconds).toEpochSecond()); } public long getRemainingCooldown(String key) { @@ -704,9 +704,9 @@ private void addCommand(ICommand command) { } private static long calcTimeRemaining(long startTime) { - // Get the start time as an OffsetDateTime - final OffsetDateTime startTimeOffset = Instant.ofEpochSecond(startTime).atOffset(ZoneOffset.UTC); + // Get the start time as an ZonedDateTime + final ZonedDateTime startTimeOffset = Instant.ofEpochSecond(startTime).atZone(ZoneOffset.UTC); // get the time that is left for the cooldown - return OffsetDateTime.now(ZoneOffset.UTC).until(startTimeOffset, ChronoUnit.SECONDS); + return ZonedDateTime.now(ZoneOffset.UTC).until(startTimeOffset, ChronoUnit.SECONDS); } } diff --git a/bot/src/main/java/ml/duncte123/skybot/commands/essentials/RemindmeCommand.java b/bot/src/main/java/ml/duncte123/skybot/commands/essentials/RemindmeCommand.java index 5a569acbb..59db19c66 100644 --- a/bot/src/main/java/ml/duncte123/skybot/commands/essentials/RemindmeCommand.java +++ b/bot/src/main/java/ml/duncte123/skybot/commands/essentials/RemindmeCommand.java @@ -26,7 +26,7 @@ import ml.duncte123.skybot.objects.command.Flag; import javax.annotation.Nonnull; -import java.time.OffsetDateTime; +import java.time.ZonedDateTime; import java.util.List; import java.util.Map; import java.util.Optional; @@ -111,7 +111,7 @@ public void execute(@Nonnull CommandContext ctx) { return; } - final OffsetDateTime expireDate = getDatabaseDate(duration); + final ZonedDateTime expireDate = getDatabaseDate(duration); System.out.println(expireDate); @@ -127,7 +127,7 @@ private Optional getDuration(Map> flags) { } } - private void createReminder(CommandContext ctx, OffsetDateTime expireDate, String reminder, Map> flags, ParsedDuration duration) { + private void createReminder(CommandContext ctx, ZonedDateTime expireDate, String reminder, Map> flags, ParsedDuration duration) { final boolean inChannel = flags.containsKey("c"); final String where = inChannel ? " here" : ""; diff --git a/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java b/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java index 55a55bde6..e83fb23e4 100644 --- a/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java +++ b/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java @@ -54,8 +54,8 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.time.OffsetDateTime; import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; @@ -298,7 +298,7 @@ public static void handleExpiredReminders(List reminders, AbstractData } // get a date that is 2 days in the future - final OffsetDateTime plusTwoDays = OffsetDateTime.now(ZoneOffset.UTC).plus(2L, ChronoUnit.DAYS); + final ZonedDateTime plusTwoDays = ZonedDateTime.now(ZoneOffset.UTC).plus(2L, ChronoUnit.DAYS); // Remove any reminders that have not been removed after 2 days final List extraRemoval = reminders.stream() diff --git a/bot/src/main/kotlin/ml/duncte123/skybot/commands/music/SaveCommand.kt b/bot/src/main/kotlin/ml/duncte123/skybot/commands/music/SaveCommand.kt index 9cbc1531d..1a33bf14c 100644 --- a/bot/src/main/kotlin/ml/duncte123/skybot/commands/music/SaveCommand.kt +++ b/bot/src/main/kotlin/ml/duncte123/skybot/commands/music/SaveCommand.kt @@ -27,7 +27,7 @@ import ml.duncte123.skybot.objects.command.MusicCommand import ml.duncte123.skybot.utils.AudioUtils import net.dv8tion.jda.api.entities.Guild import net.dv8tion.jda.api.utils.FileUpload -import java.time.OffsetDateTime +import java.time.ZonedDateTime class SaveCommand : MusicCommand() { @@ -41,7 +41,7 @@ class SaveCommand : MusicCommand() { .addFiles( FileUpload.fromData( toByteArray(ctx.guild, ctx.audioUtils, ctx.variables.jackson), - "playlist-${getDatabaseDateFormat(OffsetDateTime.now())}.json" + "playlist-${getDatabaseDateFormat(ZonedDateTime.now())}.json" ) ) .queue() diff --git a/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java b/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java index 628a42c05..ff877b8e3 100644 --- a/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java +++ b/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java @@ -29,7 +29,9 @@ import net.dv8tion.jda.api.utils.TimeFormat; import java.sql.Timestamp; -import java.time.*; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoUnit; @@ -42,23 +44,22 @@ public static String makeDatePretty(TemporalAccessor accessor) { return TimeFormat.DATE_TIME_LONG.format(accessor); } - public static OffsetDateTime fromMysqlFormat(String date) { + public static ZonedDateTime fromMysqlFormat(String date) { try { System.out.println(date.replace(" ", "T") + DB_ZONE_ID.getId()); return LocalDateTime.parse(date.replace(" ", "T"), DateTimeFormatter.ISO_DATE_TIME) - .atZone(DB_ZONE_ID) - .toOffsetDateTime(); + .atZone(DB_ZONE_ID); } catch (DateTimeParseException e) { e.printStackTrace(); - return OffsetDateTime.now(DB_ZONE_ID); + return ZonedDateTime.now(DB_ZONE_ID); } } // TODO: use UTC in the future - public static Timestamp getSqlTimestamp(OffsetDateTime date) { - final var zonedDate = date.toZonedDateTime().withZoneSameInstant(DB_ZONE_ID); + public static Timestamp getSqlTimestamp(ZonedDateTime date) { + final var zonedDate = date.withZoneSameInstant(DB_ZONE_ID); final var shouldWork = zonedDate.toString() .replace("Z", "") .replace("T", " ") @@ -67,14 +68,14 @@ public static Timestamp getSqlTimestamp(OffsetDateTime date) { return Timestamp.valueOf(shouldWork); } - public static OffsetDateTime fromDatabaseFormat(String date) { + public static ZonedDateTime fromDatabaseFormat(String date) { try { - return OffsetDateTime.parse(date); + return ZonedDateTime.parse(date); } catch (DateTimeParseException e) { e.printStackTrace(); - return OffsetDateTime.now(DB_ZONE_ID); + return ZonedDateTime.now(DB_ZONE_ID); } } @@ -82,11 +83,11 @@ public static String getDatabaseDateFormat(ParsedDuration duration) { return getDatabaseDateFormat(getDatabaseDate(duration)); } - public static String getDatabaseDateFormat(OffsetDateTime date) { + public static String getDatabaseDateFormat(ZonedDateTime date) { return date.truncatedTo(ChronoUnit.MILLIS).toString(); } - public static OffsetDateTime getDatabaseDate(ParsedDuration duration) { - return OffsetDateTime.now(DB_ZONE_ID).plus(duration.getMilis(), ChronoUnit.MILLIS); + public static ZonedDateTime getDatabaseDate(ParsedDuration duration) { + return ZonedDateTime.now(DB_ZONE_ID).plus(duration.getMilis(), ChronoUnit.MILLIS); } } diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt index 13d6fc3b5..1eb17ceec 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/AbstractDatabase.kt @@ -21,12 +21,11 @@ package ml.duncte123.skybot.database import com.dunctebot.models.settings.GuildSetting import com.dunctebot.models.settings.WarnAction import io.sentry.Sentry -// import ml.duncte123.skybot.SkyBot import ml.duncte123.skybot.objects.Tag import ml.duncte123.skybot.objects.api.* import ml.duncte123.skybot.objects.command.CommandResult import ml.duncte123.skybot.objects.command.CustomCommand -import java.time.OffsetDateTime +import java.time.ZonedDateTime import java.util.concurrent.CompletableFuture import java.util.concurrent.Executors import java.util.concurrent.ThreadPoolExecutor @@ -198,7 +197,7 @@ abstract class AbstractDatabase(threads: Int = 2, private val ohShitFn: (Int, In abstract fun createReminder( userId: Long, reminder: String, - expireDate: OffsetDateTime, + expireDate: ZonedDateTime, channelId: Long, messageId: Long, guildId: Long, diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt index 1d7ac62d7..1d486e5a4 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt @@ -24,7 +24,9 @@ import com.dunctebot.models.utils.Utils import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import io.sentry.Sentry -import ml.duncte123.skybot.extensions.* +import ml.duncte123.skybot.extensions.toGuildSettingMySQL +import ml.duncte123.skybot.extensions.toReminderMySQL +import ml.duncte123.skybot.extensions.toSQL import ml.duncte123.skybot.objects.Tag import ml.duncte123.skybot.objects.api.* import ml.duncte123.skybot.objects.command.CommandResult @@ -32,7 +34,7 @@ import ml.duncte123.skybot.objects.command.CustomCommand import java.sql.Connection import java.sql.SQLException import java.sql.Types -import java.time.OffsetDateTime +import java.time.ZonedDateTime import java.util.concurrent.CompletableFuture class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> }) : AbstractDatabase(2, ohShitFn) { @@ -920,7 +922,7 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> override fun createReminder( userId: Long, reminder: String, - expireDate: OffsetDateTime, + expireDate: ZonedDateTime, channelId: Long, messageId: Long, guildId: Long, diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt index de589d855..e1ed1408f 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt @@ -38,7 +38,7 @@ import ml.duncte123.skybot.objects.command.CustomCommand import java.sql.Connection import java.sql.SQLException import java.sql.Types -import java.time.OffsetDateTime +import java.time.ZonedDateTime import java.util.concurrent.CompletableFuture class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> }) : AbstractDatabase(2, ohShitFn) { @@ -922,7 +922,7 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> override fun createReminder( userId: Long, reminder: String, - expireDate: OffsetDateTime, + expireDate: ZonedDateTime, channelId: Long, messageId: Long, guildId: Long, diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt b/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt index 3b513670a..d3fb3b480 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt @@ -27,14 +27,13 @@ import com.dunctebot.models.utils.Utils.toLong import ml.duncte123.skybot.objects.api.Reminder import java.sql.ResultSet import java.time.Instant -import java.time.OffsetDateTime -import java.time.ZoneOffset +import java.time.ZonedDateTime -fun OffsetDateTime.toSQL() = getSqlTimestamp(this) +fun ZonedDateTime.toSQL() = getSqlTimestamp(this) // TODO: still an hour in the past? -fun java.sql.Timestamp.asInstant() = OffsetDateTime.ofInstant(Instant.ofEpochMilli(this.time), DB_ZONE_ID) -fun String.toDate() = DateUtils.fromMysqlFormat(this).toSQL() +fun java.sql.Timestamp.asInstant() = ZonedDateTime.ofInstant(Instant.ofEpochMilli(this.time), DB_ZONE_ID) fun String.toJavaDate() = DateUtils.fromMysqlFormat(this) +fun String.toDate() = this.toJavaDate().toSQL() fun ResultSet.toReminder() = Reminder( this.getInt("id"), diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/objects/api/WebObjects.kt b/shared/src/main/kotlin/ml/duncte123/skybot/objects/api/WebObjects.kt index 6c6b7d352..832ead989 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/objects/api/WebObjects.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/objects/api/WebObjects.kt @@ -19,11 +19,10 @@ package ml.duncte123.skybot.objects.api import com.dunctebot.models.utils.DateUtils -import com.dunctebot.models.utils.Utils import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty import net.dv8tion.jda.api.utils.TimeFormat -import java.time.OffsetDateTime +import java.time.ZonedDateTime data class KpopObject(val id: Int, val name: String, val band: String, val image: String) @@ -69,8 +68,8 @@ data class Reminder( val id: Int, val user_id: Long, val reminder: String, - val create_date: OffsetDateTime, - val reminder_date: OffsetDateTime, + val create_date: ZonedDateTime, + val reminder_date: ZonedDateTime, val channel_id: Long, val message_id: Long, val guild_id: Long, From ce5654a39cbc72989661d74817606ef85e0b8700 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Thu, 27 Apr 2023 11:39:35 +0200 Subject: [PATCH 17/20] Remove sout --- .../duncte123/skybot/commands/essentials/RemindmeCommand.java | 2 -- bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java | 2 -- shared/src/main/java/com/dunctebot/models/utils/DateUtils.java | 1 - .../kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt | 1 - 4 files changed, 6 deletions(-) diff --git a/bot/src/main/java/ml/duncte123/skybot/commands/essentials/RemindmeCommand.java b/bot/src/main/java/ml/duncte123/skybot/commands/essentials/RemindmeCommand.java index 59db19c66..4ead405c6 100644 --- a/bot/src/main/java/ml/duncte123/skybot/commands/essentials/RemindmeCommand.java +++ b/bot/src/main/java/ml/duncte123/skybot/commands/essentials/RemindmeCommand.java @@ -113,8 +113,6 @@ public void execute(@Nonnull CommandContext ctx) { final ZonedDateTime expireDate = getDatabaseDate(duration); - System.out.println(expireDate); - createReminder(ctx, expireDate, reminder, flags, duration); } diff --git a/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java b/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java index e83fb23e4..3f7fa2e5d 100644 --- a/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java +++ b/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java @@ -237,8 +237,6 @@ public static void handleExpiredReminders(List reminders, AbstractData final List toPurge = new ArrayList<>(); for (final Reminder reminder : reminders) { - System.out.println("Expire date " + reminder.getReminder_date()); - System.out.println("Crate date " + reminder.getCreate_date()); // The reminder message template final String message = String.format( "%s you asked me to remind you about \"%s\"", diff --git a/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java b/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java index ff877b8e3..7e76e3882 100644 --- a/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java +++ b/shared/src/main/java/com/dunctebot/models/utils/DateUtils.java @@ -46,7 +46,6 @@ public static String makeDatePretty(TemporalAccessor accessor) { public static ZonedDateTime fromMysqlFormat(String date) { try { - System.out.println(date.replace(" ", "T") + DB_ZONE_ID.getId()); return LocalDateTime.parse(date.replace(" ", "T"), DateTimeFormatter.ISO_DATE_TIME) .atZone(DB_ZONE_ID); } diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt b/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt index d3fb3b480..0841151b9 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/extensions/DatabaseExtensions.kt @@ -30,7 +30,6 @@ import java.time.Instant import java.time.ZonedDateTime fun ZonedDateTime.toSQL() = getSqlTimestamp(this) -// TODO: still an hour in the past? fun java.sql.Timestamp.asInstant() = ZonedDateTime.ofInstant(Instant.ofEpochMilli(this.time), DB_ZONE_ID) fun String.toJavaDate() = DateUtils.fromMysqlFormat(this) fun String.toDate() = this.toJavaDate().toSQL() From 0cebff55512a483194fb146f234dda675f0a146d Mon Sep 17 00:00:00 2001 From: duncte123 Date: Thu, 27 Apr 2023 18:02:07 +0200 Subject: [PATCH 18/20] Undo one change --- bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java b/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java index 3f7fa2e5d..abfa89336 100644 --- a/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java +++ b/bot/src/main/java/ml/duncte123/skybot/utils/AirUtils.java @@ -285,7 +285,7 @@ public static void handleExpiredReminders(List reminders, AbstractData // we cannot dm this user (has dms blocked?) errorResponse == ErrorResponse.CANNOT_SEND_TO_USER ) { - // toPurge.add(reminder.getId()); + toPurge.add(reminder.getId()); } else { errorResponseEx.printStackTrace(); } From c08591fd36910c2b00758fd6ef0896eb43793be8 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Fri, 28 Apr 2023 15:41:40 +0200 Subject: [PATCH 19/20] Cleanup --- bot/src/main/java/ml/duncte123/skybot/CommandManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/src/main/java/ml/duncte123/skybot/CommandManager.java b/bot/src/main/java/ml/duncte123/skybot/CommandManager.java index 6788a1d4f..d018d0a05 100644 --- a/bot/src/main/java/ml/duncte123/skybot/CommandManager.java +++ b/bot/src/main/java/ml/duncte123/skybot/CommandManager.java @@ -283,7 +283,7 @@ public CommandManager(Variables variables) { this.addCommand(new TagCommand(variables)); this.addCommand(new TempBanCommand()); this.addCommand(new TempMuteCommand()); - this.addCommand(new TestFilterCommand()); +// this.addCommand(new TestFilterCommand()); this.addCommand(new TestTagCommand()); this.addCommand(new TheSearchCommand()); this.addCommand(new ToggleAnnounceTracksCommand()); From 76d20dcb380f9506cc61fc8fd15ef4c8a4db9eb1 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Fri, 28 Apr 2023 15:42:10 +0200 Subject: [PATCH 20/20] Cleanup --- .../main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt index 1d486e5a4..254ba44c7 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/MariaDBDatabase.kt @@ -933,7 +933,6 @@ class MariaDBDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> "INSERT INTO reminders(user_id, guild_id, channel_id, message_id, in_channel, reminder, remind_date) VALUES (?, ?, ?, ?, ?, ?, ?)", arrayOf("insert_id") // cols to return ).use { smt -> - println(expireDate.toSQL()) smt.setString(1, userId.toString()) smt.setString(2, guildId.toString()) smt.setString(3, channelId.toString())