diff --git a/build.gradle.kts b/build.gradle.kts index 16f02e2e..fa430ee0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,7 +16,7 @@ plugins { } group = "org.hyacinthbots.lilybot" -version = "4.8.4" +version = "4.8.5" repositories { mavenCentral() diff --git a/docs/changelogs/4.x.x/4.8.5.md b/docs/changelogs/4.x.x/4.8.5.md new file mode 100644 index 00000000..df051109 --- /dev/null +++ b/docs/changelogs/4.x.x/4.8.5.md @@ -0,0 +1,19 @@ +# LilyBot 4.8.5 + +This update fixes a bug and deprecate log uploading. +You can find the full changelog below + +New: +* Tags can now be 4096 characters long, quite why you'd want a tag that's 4kB long I don't know, but you can do that now +* Lily will send a message in a gallery channel when permissions are broken for her + +Change: +* Role menu buttons are now GuildButtons +* Upgradle to 8.1.1 +* The role mention check now takes into account the `Mention @everyone, @here and All Roles` permission + +Fix: +* Old tags are no longer deleted before the new tag is validated fixing wierd issues in editing +* Hopefully stop reminder randomly disappearing and subsequently multi-pinging as we're properly checking reminders before deleting them now + +You can find a list of all the commits in this update [here](https://github.com/hyacinthbots/LilyBot/compare/v4.8.4...v4.8.5) diff --git a/gradle.properties b/gradle.properties index cefb4964..0d3bb75f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ # suppress inspection "UnusedProperty" for whole file # Gradle props -org.gradle.jvmargs=-Xmx1536m -XX:MaxMetaspaceSize=1536m +org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=2048m org.gradle.parallel=true kotlin.incremental=true kotlin.code.style=official diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index ccebba77..c1962a79 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bdc9a83b..37aef8d3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 79a61d42..aeb74cbb 100755 --- a/gradlew +++ b/gradlew @@ -85,9 +85,6 @@ done APP_BASE_NAME=${0##*/} APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -197,6 +194,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in diff --git a/libs.versions.toml b/libs.versions.toml index 6bde7aad..9823bcb7 100644 --- a/libs.versions.toml +++ b/libs.versions.toml @@ -1,18 +1,18 @@ [versions] # Plugins -kotlin = "1.8.10" +kotlin = "1.8.21" shadow = "8.1.1" detekt = "1.22.0" git-hooks = "0.0.2" -grgit = "5.0.0" +grgit = "5.2.0" blossom = "1.3.1" # Libraries -kord-extensions = "1.5.7-20230325.173116-4" +kord-extensions = "1.5.7-20230430.120015-9" logging = "3.0.5" -logback = "1.4.6" +logback = "1.4.7" github-api = "1.314" -kmongo = "4.8.0" +kmongo = "4.9.0" cozy-welcome = "1.0.1-SNAPSHOT" dma = "0.2.0-SNAPSHOT" docgenerator = "0.1.2-SNAPSHOT" diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/database/collections/ReminderCollection.kt b/src/main/kotlin/org/hyacinthbots/lilybot/database/collections/ReminderCollection.kt index ba23a1d5..90e719d2 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/database/collections/ReminderCollection.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/database/collections/ReminderCollection.kt @@ -74,11 +74,13 @@ class ReminderCollection : KordExKoinComponent { /** * Removes a reminder from the database. * + * @param userId The ID of the user the reminder belongs too * @param number The reminder to remove * @author NoComment1105 * @since 4.2.0 */ - suspend fun removeReminder(number: Long) = collection.deleteOne(ReminderData::id eq number) + suspend fun removeReminder(userId: Snowflake, number: Long) = + collection.deleteOne(ReminderData::userId eq userId, ReminderData::id eq number) /** * Removes all the reminders for a given guild. @@ -98,10 +100,7 @@ class ReminderCollection : KordExKoinComponent { * @since 4.5.0 */ suspend fun repeatReminder(originalData: ReminderData, repeatingInterval: DateTimePeriod) { - collection.deleteOne( - ReminderData::id eq originalData.id, - ReminderData::userId eq originalData.userId - ) + removeReminder(originalData.userId, originalData.id) collection.insertOne( ReminderData( diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/config/Config.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/config/Config.kt index c74d4a08..5781e346 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/config/Config.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/config/Config.kt @@ -99,7 +99,7 @@ class Config : Extension() { return@action } - if (!canPingRole(arguments.moderatorRole) && arguments.moderatorRole != null) { + if (!canPingRole(arguments.moderatorRole, guild!!.id, this@ephemeralSubCommand.kord)) { respond { content = "I cannot use the role: ${arguments.moderatorRole!!.mention}, because it is not mentionable by " + @@ -332,7 +332,7 @@ class Config : Extension() { footer { text = "Configured by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } } @@ -453,7 +453,7 @@ class Config : Extension() { footer { text = "Configured by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } } @@ -508,7 +508,7 @@ class Config : Extension() { }" footer { text = "Config cleared by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } } } @@ -531,7 +531,7 @@ class Config : Extension() { title = "Config cleared: Moderation" footer { text = "Config cleared by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } } } @@ -553,7 +553,7 @@ class Config : Extension() { title = "Config cleared: Logging" footer { text = "Config cleared by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } } } @@ -575,7 +575,7 @@ class Config : Extension() { title = "Config cleared: Utility" footer { text = "Config cleared by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } } } @@ -590,7 +590,7 @@ class Config : Extension() { title = "All configs cleared" footer { text = "Configs cleared by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } } } diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/AutoThreading.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/AutoThreading.kt index aff5a664..5b5c136d 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/AutoThreading.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/AutoThreading.kt @@ -53,6 +53,7 @@ import org.hyacinthbots.lilybot.database.collections.ThreadsCollection import org.hyacinthbots.lilybot.database.entities.AutoThreadingData import org.hyacinthbots.lilybot.extensions.config.ConfigOptions import org.hyacinthbots.lilybot.utils.botHasChannelPerms +import org.hyacinthbots.lilybot.utils.canPingRole import org.hyacinthbots.lilybot.utils.getLoggingChannelWithPerms class AutoThreading : Extension() { @@ -90,7 +91,7 @@ class AutoThreading : Extension() { } // Check if the role can be pinged - if (arguments.role?.mentionable == false) { + if (canPingRole(arguments.role, guild!!.id, this@unsafeSubCommand.kord)) { ackEphemeral() respondEphemeral { content = "Lily cannot mention this role. Please fix the role's permissions and try again." @@ -183,7 +184,7 @@ class AutoThreading : Extension() { } footer { text = user.asUser().tag - icon = user.asUser().avatar?.url + icon = user.asUser().avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() color = DISCORD_BLACK @@ -235,7 +236,7 @@ class AutoThreading : Extension() { } footer { text = user.asUser().tag - icon = user.asUser().avatar?.url + icon = user.asUser().avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() color = DISCORD_BLACK diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/LogUploading.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/LogUploading.kt index 4dd2801d..429f9bbe 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/LogUploading.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/LogUploading.kt @@ -121,9 +121,13 @@ class LogUploading : Extension() { val thread = event.getGuildOrNull()?.getChannelOfOrNull(it.threadId) ?: return@forEach if (thread.parentId == autoThreadingConfig?.channelId) { - uploadChannel = - event.getGuildOrNull()?.getChannelOfOrNull(it.threadId) - ?: return@forEach + try { + uploadChannel = + event.getGuildOrNull()?.getChannelOfOrNull(it.threadId) + ?: return@forEach + } catch (_: IllegalArgumentException) { + return@forEach + } return@forEach } } @@ -162,7 +166,7 @@ class LogUploading : Extension() { "(i.e. log or crash report) if the issue persists.\n\n$DEPRECATION_MESSAGE" footer { text = eventMessage.author?.tag ?: "" - icon = eventMessage.author?.avatar?.url + icon = eventMessage.author?.avatar?.cdnUrl?.toUrl() } color = DISCORD_PINK } @@ -181,7 +185,7 @@ class LogUploading : Extension() { text = "Uploaded by ${eventMessage.author?.tag ?: eventMember?.asUserOrNull()?.tag}" icon = - eventMessage.author?.avatar?.url ?: eventMember?.asUserOrNull()?.avatar?.url + eventMessage.author?.avatar?.cdnUrl?.toUrl() ?: eventMember?.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } color = DISCORD_PINK } @@ -202,8 +206,8 @@ class LogUploading : Extension() { footer { text = "Uploaded by ${eventMessage.author?.tag ?: eventMember.asUserOrNull()?.tag}" - icon = eventMessage.author?.avatar?.url - ?: eventMember.asUserOrNull()?.avatar?.url + icon = eventMessage.author?.avatar?.cdnUrl?.toUrl() + ?: eventMember.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() color = DISCORD_PINK @@ -219,8 +223,8 @@ class LogUploading : Extension() { footer { text = "Uploaded by ${eventMessage.author?.tag ?: eventMember.asUserOrNull()?.tag}" - icon = eventMessage.author?.avatar?.url - ?: eventMember.asUserOrNull()?.avatar?.url + icon = eventMessage.author?.avatar?.cdnUrl?.toUrl() + ?: eventMember.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() color = DISCORD_PINK @@ -242,8 +246,8 @@ class LogUploading : Extension() { footer { text = "Uploaded by ${eventMessage.author?.tag ?: eventMember.asUserOrNull()?.tag}" - icon = eventMessage.author?.avatar?.url - ?: eventMember.asUserOrNull()?.avatar?.url + icon = eventMessage.author?.avatar?.cdnUrl?.toUrl() + ?: eventMember.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() color = DISCORD_RED @@ -323,7 +327,7 @@ class LogUploading : Extension() { color = DISCORD_RED footer { text = "Disabled by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } } } @@ -364,7 +368,7 @@ class LogUploading : Extension() { color = DISCORD_GREEN footer { text = "Enabled by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } } } diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/MemberLogging.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/MemberLogging.kt index a73f8780..f2f031b8 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/MemberLogging.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/MemberLogging.kt @@ -46,7 +46,7 @@ class MemberLogging : Extension() { memberLog?.createEmbed { author { name = "User joined the server!" - icon = event.member.avatar?.url + icon = event.member.avatar?.cdnUrl?.toUrl() } field { name = "Welcome:" @@ -77,7 +77,7 @@ class MemberLogging : Extension() { embed { author { name = "Welcome ${event.member.username}" - icon = event.member.avatar?.url + icon = event.member.avatar?.cdnUrl?.toUrl() } description = if (config.publicMemberLogData?.joinMessage != null) { config.publicMemberLogData.joinMessage @@ -110,7 +110,7 @@ class MemberLogging : Extension() { memberLog?.createEmbed { author { name = "User left the server!" - icon = event.user.avatar?.url + icon = event.user.avatar?.cdnUrl?.toUrl() } field { name = "Goodbye:" @@ -138,7 +138,7 @@ class MemberLogging : Extension() { publicLog?.createEmbed { author { name = "Goodbye ${event.user.username}" - icon = event.user.avatar?.url + icon = event.user.avatar?.cdnUrl?.toUrl() } description = if (config.publicMemberLogData?.leaveMessage != null) { config.publicMemberLogData.leaveMessage diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/MessageDelete.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/MessageDelete.kt index e85b4c0c..45a6873e 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/MessageDelete.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/MessageDelete.kt @@ -75,7 +75,6 @@ class MessageDelete : Extension() { } } - @Suppress("RemoveExplicitTypeArguments") // It is used you absolute buffoon event { check { anyGuild() @@ -169,7 +168,7 @@ class MessageDelete : Extension() { messageLog.createEmbed { author { name = "Message deleted" - icon = proxiedMessage?.member?.avatarUrl ?: message.author?.avatar?.url + icon = proxiedMessage?.member?.avatarUrl ?: message.author?.avatar?.cdnUrl?.toUrl() } description = "Location: ${message.channel.mention} " + diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/MessageEdit.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/MessageEdit.kt index 9e4505e3..acae881b 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/MessageEdit.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/MessageEdit.kt @@ -88,7 +88,7 @@ class MessageEdit : Extension() { color = DISCORD_YELLOW author { name = "Message Edited" - icon = proxiedMessage?.member?.avatarUrl ?: message.author?.avatar?.url + icon = proxiedMessage?.member?.avatarUrl ?: message.author?.avatar?.cdnUrl?.toUrl() } description = "Location: ${message.channel.mention} " + diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/ModThreadInviting.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/ModThreadInviting.kt index 2458ddcc..0bb51484 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/ModThreadInviting.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/events/ModThreadInviting.kt @@ -10,6 +10,7 @@ import dev.kord.core.supplier.EntitySupplyStrategy import kotlinx.coroutines.delay import org.hyacinthbots.lilybot.database.collections.AutoThreadingCollection import org.hyacinthbots.lilybot.database.collections.ModerationConfigCollection +import org.hyacinthbots.lilybot.utils.canPingRole class ModThreadInviting : Extension() { override val name: String = "mod-thread-inviting" @@ -41,7 +42,7 @@ class ModThreadInviting : Extension() { val moderatorRole = channel.guild.getRoleOrNull(config.role) ?: return@action - if (!moderatorRole.mentionable) return@action + if (!canPingRole(moderatorRole, event.channel.guildId, kord)) return@action val message = channel.createMessage { content = "Placeholder message" diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/moderation/LockingCommands.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/moderation/LockingCommands.kt index 60445d34..705fb135 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/moderation/LockingCommands.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/moderation/LockingCommands.kt @@ -104,7 +104,7 @@ class LockingCommands : Extension() { description = "${targetChannel.mention} has been locked.\n\n**Reason:** ${arguments.reason}" footer { text = user.asUserOrNull()?.tag ?: "Unable to get tag" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() color = DISCORD_RED @@ -159,7 +159,7 @@ class LockingCommands : Extension() { description = "**Reason:** ${arguments.reason}" footer { text = user.asUserOrNull()?.tag ?: "Unable to get user tag" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() color = DISCORD_RED @@ -243,7 +243,7 @@ class LockingCommands : Extension() { description = "${targetChannel.mention} has been unlocked." footer { text = user.asUserOrNull()?.tag ?: "Unable to get user tag" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() color = DISCORD_GREEN @@ -296,7 +296,7 @@ class LockingCommands : Extension() { title = "Server unlocked" footer { text = user.asUserOrNull()?.tag ?: "Unable to get user tag" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() color = DISCORD_GREEN diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/moderation/ModerationCommands.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/moderation/ModerationCommands.kt index 25a8909e..fcad7f10 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/moderation/ModerationCommands.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/moderation/ModerationCommands.kt @@ -640,7 +640,7 @@ class ModerationCommands : Extension() { } footer { text = user.asUserOrNull()?.tag ?: "Unable to get user tag" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() color = DISCORD_GREEN @@ -767,7 +767,7 @@ class ModerationCommands : Extension() { description = "Action occurred in ${textChannel.mention}" footer { text = user.asUserOrNull()?.tag ?: "Unable to get user tag" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } color = DISCORD_BLACK } @@ -869,7 +869,7 @@ class ModerationCommands : Extension() { } footer { text = "Requested by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() color = DISCORD_BLACK @@ -1312,7 +1312,7 @@ private fun EmbedBuilder.warnTimeoutLog(timeoutNumber: Int, moderator: User, tar } footer { text = moderator.tag - icon = moderator.avatar?.url + icon = moderator.avatar?.cdnUrl?.toUrl() } color = DISCORD_BLACK timestamp = Clock.System.now() diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/moderation/Report.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/moderation/Report.kt index 3fe392e0..daa78d2f 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/moderation/Report.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/moderation/Report.kt @@ -199,7 +199,7 @@ class Report : Extension() { } footer { text = "Reported by: ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() color = DISCORD_RED diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/GalleryChannel.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/GalleryChannel.kt index c50de7d0..22a360a6 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/GalleryChannel.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/GalleryChannel.kt @@ -11,11 +11,15 @@ import com.kotlindiscord.kord.extensions.extensions.ephemeralSlashCommand import com.kotlindiscord.kord.extensions.extensions.event import com.kotlindiscord.kord.extensions.types.respond import com.kotlindiscord.kord.extensions.utils.delete +import com.kotlindiscord.kord.extensions.utils.permissionsForMember import com.kotlindiscord.kord.extensions.utils.respond import dev.kord.common.entity.MessageType import dev.kord.common.entity.Permission import dev.kord.common.entity.Permissions +import dev.kord.core.behavior.channel.asChannelOf import dev.kord.core.behavior.channel.createEmbed +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.entity.channel.GuildMessageChannel import dev.kord.core.event.message.MessageCreateEvent import dev.kord.core.exception.EntityNotFoundException import dev.kord.rest.builder.message.create.embed @@ -83,7 +87,7 @@ class GalleryChannel : Extension() { description = "${channel.mention} was added as a Gallery channel" footer { text = "Requested by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } color = DISCORD_GREEN } @@ -128,7 +132,7 @@ class GalleryChannel : Extension() { description = "${channel.mention} was removed as a Gallery channel" footer { text = "Requested by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } color = DISCORD_RED } @@ -190,6 +194,16 @@ class GalleryChannel : Extension() { GalleryChannelCollection().getChannels(event.guildId!!).forEach { // If there are no attachments to the message and the channel we're in is an image channel if (event.message.channelId == it.channelId && event.message.attachments.isEmpty()) { + if (!event.message.channel.asChannelOf().permissionsForMember(kord.selfId) + .contains(Permission.ManageMessages) + ) { + event.message.channel.createMessage { + "Hi! This is a gallery channel, but I don't have Manage Messages for this " + + "channel, therefore I cannot delete messages that don't contain images! Could " + + "someone ask staff fix it please? Thanks!" + } + return@forEach + } // We delay to give the message a chance to populate with an embed, if it is a link to imgur etc. delay(0.25.seconds.inWholeMilliseconds) if (event.message.embeds.isEmpty()) { // If there is still no embed, we delete the message diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/InfoCommands.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/InfoCommands.kt index d7b59510..6f47de43 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/InfoCommands.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/InfoCommands.kt @@ -41,7 +41,7 @@ class InfoCommands : Extension() { respond { embed { thumbnail { - url = event.kord.getSelf().avatar!!.url + url = event.kord.getSelf().avatar?.cdnUrl!!.toUrl() } title = "What is LilyBot?" description = "Lily is a FOSS multi-purpose bot for Discord created by " + @@ -103,7 +103,7 @@ class InfoCommands : Extension() { respond { embed { thumbnail { - url = event.kord.getSelf().avatar!!.url + url = event.kord.getSelf().avatar?.cdnUrl!!.toUrl() } title = "Info about LilyBot" description = "Lily is a FOSS multi-purpose bot for Discord created by " + diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/ModUtilities.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/ModUtilities.kt index 0e85ff99..8d92eaea 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/ModUtilities.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/ModUtilities.kt @@ -143,7 +143,7 @@ class ModUtilities : Extension() { } footer { text = user.asUserOrNull()?.tag ?: "Unable to get user tag" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() if (arguments.embed) { @@ -239,7 +239,7 @@ class ModUtilities : Extension() { } footer { text = "Edited by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } color = DISCORD_WHITE timestamp = Clock.System.now() @@ -310,7 +310,7 @@ class ModUtilities : Extension() { } footer { text = "Edited by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() color = DISCORD_WHITE @@ -369,7 +369,7 @@ class ModUtilities : Extension() { description = "Lily's presence has been set to `${arguments.presenceArgument}`" footer { text = user.asUserOrNull()?.tag ?: "Unable to get user tag" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } color = DISCORD_BLACK } @@ -407,7 +407,7 @@ class ModUtilities : Extension() { } footer { text = user.asUserOrNull()?.tag ?: "Unable to get user tag" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } color = DISCORD_BLACK } diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/NewsChannelPublishing.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/NewsChannelPublishing.kt index e75ab70c..946b1713 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/NewsChannelPublishing.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/NewsChannelPublishing.kt @@ -16,6 +16,7 @@ import com.kotlindiscord.kord.extensions.pagination.pages.Page import com.kotlindiscord.kord.extensions.pagination.pages.Pages import com.kotlindiscord.kord.extensions.types.respond import dev.kord.common.Locale +import dev.kord.common.asJavaLocale import dev.kord.common.entity.ChannelType import dev.kord.common.entity.Permission import dev.kord.common.entity.Permissions @@ -111,7 +112,7 @@ class NewsChannelPublishing : Extension() { } footer { text = "Set by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() color = DISCORD_YELLOW @@ -156,7 +157,7 @@ class NewsChannelPublishing : Extension() { } footer { text = "Removed by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() color = DISCORD_YELLOW diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/PublicUtilities.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/PublicUtilities.kt index 35f34efe..80560eac 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/PublicUtilities.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/PublicUtilities.kt @@ -223,7 +223,7 @@ class PublicUtilities : Extension() { footer { text = "Nickname accepted by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() @@ -272,7 +272,7 @@ class PublicUtilities : Extension() { footer { text = "Nickname denied by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/Reminders.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/Reminders.kt index 82eb6390..d4b0ca55 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/Reminders.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/Reminders.kt @@ -45,7 +45,7 @@ import kotlinx.datetime.TimeZone import org.hyacinthbots.lilybot.database.collections.ReminderCollection import org.hyacinthbots.lilybot.database.entities.ReminderData import org.hyacinthbots.lilybot.utils.botHasChannelPerms -import org.hyacinthbots.lilybot.utils.fitsEmbed +import org.hyacinthbots.lilybot.utils.fitsEmbedField import org.hyacinthbots.lilybot.utils.interval class Reminders : Extension() { @@ -86,7 +86,7 @@ class Reminders : Extension() { val setTime = Clock.System.now() val remindTime = Clock.System.now().plus(arguments.time.toDuration(TimeZone.UTC)) - if (arguments.customMessage != null && arguments.customMessage.fitsEmbed() == false) { + if (arguments.customMessage != null && arguments.customMessage.fitsEmbedField() == false) { respond { content = "Custom Message is too long. Message must be 1024 characters or fewer." } return@action } @@ -245,7 +245,7 @@ class Reminders : Extension() { } } - ReminderCollection().removeReminder(arguments.reminder) + ReminderCollection().removeReminder(user.id, arguments.reminder) markReminderCompleteOrCancelled(reminder.guildId, reminder.channelId, reminder.messageId, true) } } @@ -280,7 +280,7 @@ class Reminders : Extension() { when (arguments.type) { "all" -> { reminders.forEach { - ReminderCollection().removeReminder(it.id) + ReminderCollection().removeReminder(it.userId, it.id) markReminderCompleteOrCancelled(it.guildId, it.channelId, it.messageId, true) } @@ -292,7 +292,7 @@ class Reminders : Extension() { "repeating" -> { reminders.forEach { if (it.repeating) { - ReminderCollection().removeReminder(it.id) + ReminderCollection().removeReminder(it.userId, it.id) markReminderCompleteOrCancelled(it.guildId, it.channelId, it.messageId, true) } } @@ -305,7 +305,7 @@ class Reminders : Extension() { "non-repeating" -> { reminders.forEach { if (!it.repeating) { - ReminderCollection().removeReminder(it.id) + ReminderCollection().removeReminder(it.userId, it.id) markReminderCompleteOrCancelled(it.guildId, it.channelId, it.messageId, true) } } @@ -385,7 +385,7 @@ class Reminders : Extension() { } } - ReminderCollection().removeReminder(arguments.reminder) + ReminderCollection().removeReminder(user.id, arguments.reminder) markReminderCompleteOrCancelled( reminder.guildId, reminder.channelId, reminder.messageId, wasCancelled = true, @@ -428,7 +428,7 @@ class Reminders : Extension() { when (arguments.type) { "all" -> { reminders.forEach { - ReminderCollection().removeReminder(it.id) + ReminderCollection().removeReminder(it.userId, it.id) markReminderCompleteOrCancelled( it.guildId, it.channelId, it.messageId, wasCancelled = true, @@ -446,7 +446,7 @@ class Reminders : Extension() { "repeating" -> { reminders.forEach { if (it.repeating) { - ReminderCollection().removeReminder(it.id) + ReminderCollection().removeReminder(it.userId, it.id) markReminderCompleteOrCancelled( it.guildId, it.channelId, it.messageId, wasCancelled = true, @@ -465,7 +465,7 @@ class Reminders : Extension() { "non-repeating" -> { reminders.forEach { if (!it.repeating) { - ReminderCollection().removeReminder(it.id) + ReminderCollection().removeReminder(it.userId, it.id) markReminderCompleteOrCancelled( it.guildId, it.channelId, it.messageId, wasCancelled = true, @@ -502,18 +502,18 @@ class Reminders : Extension() { try { guild = kord.getGuildOrNull(it.guildId) } catch (_: KtorRequestException) { - ReminderCollection().removeReminder(it.id) + ReminderCollection().removeReminder(it.userId, it.id) continue } if (guild == null) { - ReminderCollection().removeReminder(it.id) + ReminderCollection().removeReminder(it.userId, it.id) continue } val channel = guild.getChannelOfOrNull(it.channelId) if (channel == null) { - ReminderCollection().removeReminder(it.id) + ReminderCollection().removeReminder(it.userId, it.id) continue } @@ -540,7 +540,7 @@ class Reminders : Extension() { if (it.repeating) { ReminderCollection().repeatReminder(it, it.repeatingInterval!!) } else { - ReminderCollection().removeReminder(it.id) + ReminderCollection().removeReminder(it.userId, it.id) } } } diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/RoleMenu.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/RoleMenu.kt index 63555f67..fe176a22 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/RoleMenu.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/RoleMenu.kt @@ -34,7 +34,7 @@ import dev.kord.core.behavior.edit import dev.kord.core.behavior.interaction.respondEphemeral import dev.kord.core.entity.Message import dev.kord.core.entity.Role -import dev.kord.core.event.interaction.ButtonInteractionCreateEvent +import dev.kord.core.event.interaction.GuildButtonInteractionCreateEvent import dev.kord.rest.builder.message.create.embed import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.firstOrNull @@ -149,7 +149,7 @@ class RoleMenu : Extension() { } footer { text = "Created by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } } components { @@ -225,7 +225,7 @@ class RoleMenu : Extension() { "${channel.mention}." footer { text = "Added by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } } components { @@ -291,7 +291,7 @@ class RoleMenu : Extension() { "${channel.mention}." footer { text = "Removed by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } } components { @@ -402,7 +402,7 @@ class RoleMenu : Extension() { description = "A pronoun role menu was created in ${channel.mention}." footer { text = "Created by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } } components { @@ -419,7 +419,7 @@ class RoleMenu : Extension() { /** * The button event that allows the user to select roles. */ - event { + event { check { anyGuild() failIfNot { @@ -481,7 +481,7 @@ class RoleMenu : Extension() { .toList() .associateBy { it.id } val member = event.interaction.user.asMemberOrNull(guild.id) - val userRoles = member?.roleIds?.filter { it in guildRoles.keys } + val userRoles = member.roleIds.filter { it in guildRoles.keys } event.interaction.respondEphemeral { content = "Use the menu below to select roles." @@ -496,9 +496,7 @@ class RoleMenu : Extension() { label = "@${it.name}", value = it.id.toString() ) { - if (userRoles != null) { - default = it.id in userRoles - } + default = it.id in userRoles } } @@ -507,7 +505,7 @@ class RoleMenu : Extension() { .filter { it in guildRoles.keys } if (event.interaction.values.isEmpty()) { - member?.edit { + member.edit { roles.forEach { member.removeRole(it.id) } @@ -516,26 +514,22 @@ class RoleMenu : Extension() { return@SelectMenu } - val rolesToAdd = if (userRoles != null) { - selectedRoles.filterNot { it in userRoles } - } else { - emptyList() - } - val rolesToRemove = userRoles?.filterNot { it in selectedRoles } + val rolesToAdd = selectedRoles.filterNot { it in userRoles } + val rolesToRemove = userRoles.filterNot { it in selectedRoles } - if (rolesToAdd.isEmpty() && rolesToRemove?.isEmpty() == true) { + if (rolesToAdd.isEmpty() && rolesToRemove.isEmpty()) { respond { content = "You didn't select any different roles, so no changes were made." } return@SelectMenu } - member?.edit { + member.edit { this@edit.roles = member.roleIds.toMutableSet() // toSet() to increase performance. Idea advised this. this@edit.roles!!.addAll(rolesToAdd.toSet()) - rolesToRemove?.toSet()?.let { it1 -> this@edit.roles!!.removeAll(it1) } + this@edit.roles!!.removeAll(rolesToRemove.toSet()) } respond { content = "Your roles have been adjusted." } } @@ -684,7 +678,7 @@ class RoleMenu : Extension() { description = "${arguments.role.mention} was added as a subscribable role" footer { text = "Added by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } } } @@ -740,7 +734,7 @@ class RoleMenu : Extension() { description = "${arguments.role.mention} was removed as a subscribable role" footer { text = "Removed by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } } } diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/StatusPing.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/StatusPing.kt index 3dd34f84..2422aacd 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/StatusPing.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/StatusPing.kt @@ -1,12 +1,12 @@ package org.hyacinthbots.lilybot.extensions.util import com.kotlindiscord.kord.extensions.extensions.Extension -import com.kotlindiscord.kord.extensions.utils.envOrNull import com.kotlindiscord.kord.extensions.utils.scheduling.Scheduler import com.kotlindiscord.kord.extensions.utils.scheduling.Task import io.ktor.client.HttpClient -import io.ktor.client.request.post +import io.ktor.client.request.get import mu.KotlinLogging +import org.hyacinthbots.lilybot.utils.ENV import kotlin.time.Duration.Companion.seconds class StatusPing : Extension() { @@ -18,18 +18,18 @@ class StatusPing : Extension() { private val client = HttpClient {} - private val env = envOrNull("STATUS_URL") - private val logger = KotlinLogging.logger("Status ping") override suspend fun setup() { - if (env != null) { + if (ENV != null) { task = scheduler.schedule(30.seconds, repeat = true, callback = ::post) } } private suspend fun post() { logger.debug { "Pinging!" } - client.post(env!!) + if (ENV != null) { + client.get(ENV) + } } } diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/Tags.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/Tags.kt index e318375f..272498f6 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/Tags.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/Tags.kt @@ -21,12 +21,15 @@ import com.kotlindiscord.kord.extensions.pagination.pages.Pages import com.kotlindiscord.kord.extensions.types.respond import com.kotlindiscord.kord.extensions.utils.suggestStringMap import dev.kord.common.Locale +import dev.kord.common.asJavaLocale import dev.kord.common.entity.Permission import dev.kord.common.entity.Permissions +import dev.kord.core.behavior.UserBehavior import dev.kord.core.behavior.channel.createEmbed import dev.kord.core.behavior.channel.createMessage import dev.kord.core.behavior.getChannelOfOrNull import dev.kord.core.entity.channel.GuildMessageChannel +import dev.kord.rest.builder.message.EmbedBuilder import dev.kord.rest.builder.message.create.embed import kotlinx.datetime.Clock import org.hyacinthbots.lilybot.database.collections.TagsCollection @@ -34,6 +37,7 @@ import org.hyacinthbots.lilybot.database.collections.UtilityConfigCollection import org.hyacinthbots.lilybot.extensions.config.ConfigOptions import org.hyacinthbots.lilybot.utils.botHasChannelPerms import org.hyacinthbots.lilybot.utils.getLoggingChannelWithPerms +import org.hyacinthbots.lilybot.utils.trimmedContents /** * The class that holds the commands to create tags commands. @@ -63,16 +67,16 @@ class Tags : Extension() { val tagFromDatabase = TagsCollection().getTag(guild!!.id, arguments.tagName) ?: run { respond { content = "Unable to find tag `${arguments.tagName}` for preview. " + - "Be sure it exists and you've typed it correctly." + "Be sure it exists and you've typed it correctly." } return@action } - if (tagFromDatabase.tagValue.length > 1024) { + if (tagFromDatabase.tagValue.length > 4096) { respond { content = "The body of this tag is too long! Somehow this tag has a body of 1024 characters or" + - "more, which is above the Discord limit. Please re-create this tag!" + "more, which is above the Discord limit. Please re-create this tag!" } return@action } @@ -114,16 +118,16 @@ class Tags : Extension() { val tagFromDatabase = TagsCollection().getTag(guild!!.id, arguments.tagName) ?: run { respond { content = "Unable to find tag `${arguments.tagName}`. " + - "Be sure it exists and you've typed it correctly." + "Be sure it exists and you've typed it correctly." } return@action } - if (tagFromDatabase.tagValue.length > 1024) { + if (tagFromDatabase.tagValue.length > 4096) { respond { content = - "The body of this tag is too long! Somehow this tag has a body of 1024 characters or" + - "more, which is above the Discord limit. Please re-create this tag!" + "The body of this tag is too long! Somehow this tag has a body of 4096 characters or" + + "more, which is above the Discord limit. Please re-create this tag!" } return@action } @@ -140,7 +144,7 @@ class Tags : Extension() { description = tagFromDatabase.tagValue footer { text = "Tag requested by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } color = DISCORD_BLURPLE } @@ -170,7 +174,7 @@ class Tags : Extension() { } footer { text = "User ID: ${user.asUserOrNull()?.id}" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } timestamp = Clock.System.now() } @@ -200,24 +204,24 @@ class Tags : Extension() { title = "How does the tag system work?" description = "The tag command allows users to add guild specific 'tag' commands at runtime to their " + - "guild. **Tags are like custom commands**, they can do say what ever you want " + - "them to say.\n\n**To create a tag**, if you have the Moderate Members " + - "permission, run the following command:\n`/tag-create <value>`\n " + - "You will be prompted to enter a name for the tag, a title for the tag, and the " + - "value for the tag. This is what will appear in the embed of your tag. You can " + - "enter any character you like into all of these inputs.\n\n**To use a tag**, " + - "run the following command:\n`/tag <name>`\nYou will be prompted to enter a " + - "tag name, but will have an autocomplete window to aid you. The window will " + - "list all the tags that the guild has.\n\n**To delete a tag**, if you have " + - "the Moderate Members permission, run the following command:\n" + - "`/tag-delete <name>`\nYou will be prompted to enter the name of the tag, " + - "again aided by autocomplete.\n`/tag-edit`\nYou will be prompted to enter a " + - "tag name, but will have an autocomplete window to aid you. The window will " + - "list all the tags that the guild has. From there you can enter a new name, title " + - "or value. None of these are mandatory.\n`/tag-list`\nDisplays a paginated list " + - "of all tags for this guild. There are 10 tags on each page.\n\n**Guilds can " + - "have any number of tags they like.** The limit on `tagValue` for tags is 1024 " + - "characters, which is the embed description limit enforced by Discord." + "guild. **Tags are like custom commands**, they can do say what ever you want " + + "them to say.\n\n**To create a tag**, if you have the Moderate Members " + + "permission, run the following command:\n`/tag-create <name> <title> <value>`\n " + + "You will be prompted to enter a name for the tag, a title for the tag, and the " + + "value for the tag. This is what will appear in the embed of your tag. You can " + + "enter any character you like into all of these inputs.\n\n**To use a tag**, " + + "run the following command:\n`/tag <name>`\nYou will be prompted to enter a " + + "tag name, but will have an autocomplete window to aid you. The window will " + + "list all the tags that the guild has.\n\n**To delete a tag**, if you have " + + "the Moderate Members permission, run the following command:\n" + + "`/tag-delete <name>`\nYou will be prompted to enter the name of the tag, " + + "again aided by autocomplete.\n`/tag-edit`\nYou will be prompted to enter a " + + "tag name, but will have an autocomplete window to aid you. The window will " + + "list all the tags that the guild has. From there you can enter a new name, title " + + "or value. None of these are mandatory.\n`/tag-list`\nDisplays a paginated list " + + "of all tags for this guild. There are 10 tags on each page.\n\n**Guilds can " + + "have any number of tags they like.** The limit on `tagValue` for tags is 1024 " + + "characters, which is the embed description limit enforced by Discord." color = DISCORD_BLURPLE timestamp = Clock.System.now() } @@ -250,12 +254,18 @@ class Tags : Extension() { return@action } - if (arguments.tagValue.length > 1024) { + if (arguments.tagValue.length > 4096) { respond { - content = "That tag is body is too long! Due to Discord limitations tag bodies can only be " + - "1024 characters or less!" + content = + "That tag's body is too long! Due to Discord limitations tag bodies can only be " + + "4096 characters or less!" } return@action + } else if (arguments.tagTitle.length > 256) { + respond { + content = "That tag's title is too long! Due to Discord limitations tag titles can only be " + + "256 characters or less" + } } TagsCollection().setTag( @@ -268,29 +278,44 @@ class Tags : Extension() { val utilityLog = getLoggingChannelWithPerms(ConfigOptions.UTILITY_LOG, this.getGuild()!!) ?: return@action - utilityLog.createEmbed { - title = "Tag created!" - description = "The tag `${arguments.tagName}` has been created" - field { - name = "Tag title:" - value = "`${arguments.tagTitle}`" - inline = false - } - field { - name = "Tag value:" - value = "```${arguments.tagValue}```" - inline = false - } - field { - name = "Tag appearance" - value = arguments.tagAppearance + if (arguments.tagValue.length <= 1024) { + utilityLog.createEmbed { + title = "Tag created!" + description = "The tag `${arguments.tagName}` has been created" + field { + name = "Tag title:" + value = "`${arguments.tagTitle}`" + inline = false + } + field { + name = "Tag value:" + value = "```${arguments.tagValue}```" + inline = false + } + appearanceFooter(arguments.tagAppearance, user) } - footer { - icon = user.asUserOrNull()?.avatar?.url - text = "Requested by ${user.asUserOrNull()?.tag}" + } else { + utilityLog.createMessage { + embed { + title = "Tag created!" + description = "The tag `${arguments.tagName}` has been created" + field { + name = "Tag title:" + value = "`${arguments.tagTitle}`" + inline = false + } + field { + name = "Tag value:" + value = "${arguments.tagValue.trimmedContents(1024)}" + inline = false + } + color = DISCORD_GREEN + } + embed { + description = arguments.tagValue.substring(1018) + appearanceFooter(arguments.tagAppearance, user) + } } - timestamp = Clock.System.now() - color = DISCORD_GREEN } respond { @@ -336,7 +361,7 @@ class Tags : Extension() { description = "The tag ${arguments.tagName} was deleted" footer { text = user.asUserOrNull()?.tag ?: "Unable to get user tag" - icon = user.asUserOrNull()?.avatar?.url + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } color = DISCORD_RED } @@ -360,27 +385,33 @@ class Tags : Extension() { } action { - if (TagsCollection().getTag(guild!!.id, arguments.tagName) == null) { + val originalTag = TagsCollection().getTag(guild!!.id, arguments.tagName) + if (originalTag == null) { respond { content = "Unable to find tag `${arguments.tagName}`! Does this tag exist?" } return@action } - val originalName = TagsCollection().getTag(guild!!.id, arguments.tagName)!!.name - val originalTitle = TagsCollection().getTag(guild!!.id, arguments.tagName)!!.tagTitle - val originalValue = TagsCollection().getTag(guild!!.id, arguments.tagName)!!.tagValue - val originalAppearance = TagsCollection().getTag(guild!!.id, arguments.tagName)!!.tagAppearance - - TagsCollection().removeTag(guild!!.id, arguments.tagName) + val originalName = originalTag.name + val originalTitle = originalTag.tagTitle + val originalValue = originalTag.tagValue + val originalAppearance = originalTag.tagAppearance - if (arguments.newValue != null && arguments.newValue!!.length > 1024) { + if (arguments.newValue != null && arguments.newValue!!.length > 4096) { respond { content = - "That tag is body is too long! Due to Discord limitations tag bodies can only be " + - "1024 characters or less!" + "That tag's body is too long! Due to Discord limitations tag bodies can only be " + + "4096 characters or less!" } return@action + } else if (arguments.newTitle != null && arguments.newTitle!!.length > 256) { + respond { + content = "That tag's title is too long! Due to Discord limitations tag titles can only be " + + "256 characters or less" + } } + TagsCollection().removeTag(guild!!.id, arguments.tagName) + TagsCollection().setTag( guild!!.id, arguments.newName ?: originalName, @@ -414,14 +445,6 @@ class Tags : Extension() { "${arguments.newTitle} -> ${arguments.newTitle!!}" } } - field { - name = "Value" - value = if (arguments.newValue.isNullOrEmpty()) { - originalValue - } else { - "$originalValue -> ${arguments.newValue!!}" - } - } field { name = "Tag appearance" value = if (arguments.newAppearance.isNullOrEmpty()) { @@ -430,13 +453,36 @@ class Tags : Extension() { "$originalAppearance -> ${arguments.newAppearance}" } } - footer { - text = "Edited by ${user.asUserOrNull()?.tag}" - icon = user.asUserOrNull()?.avatar?.url - } - timestamp = Clock.System.now() color = DISCORD_YELLOW } + if (arguments.newValue.isNullOrEmpty()) { + utilityLog.createEmbed { + title = "Value" + description = originalValue + footer { + text = "Edited by ${user.asUserOrNull()?.tag}" + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() + } + timestamp = Clock.System.now() + color = DISCORD_YELLOW + } + } else { + utilityLog.createEmbed { + title = "Old value" + description = originalValue + color = DISCORD_YELLOW + } + utilityLog.createEmbed { + title = "New value" + description = arguments.newValue + footer { + text = "Edited by ${user.asUserOrNull()?.tag}" + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() + } + timestamp = Clock.System.now() + color = DISCORD_YELLOW + } + } } } @@ -501,6 +547,19 @@ class Tags : Extension() { } } + private suspend fun EmbedBuilder.appearanceFooter(tagAppearance: String, user: UserBehavior) { + field { + name = "Tag appearance" + value = tagAppearance + } + footer { + icon = user.asUserOrNull()?.avatar?.cdnUrl?.toUrl() + text = "Requested by ${user.asUserOrNull()?.tag}" + } + timestamp = Clock.System.now() + color = DISCORD_GREEN + } + inner class CallTagArgs : Arguments() { /** The named identifier of the tag the user would like. */ val tagName by string { diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/ThreadControl.kt b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/ThreadControl.kt index 9557255c..ee38a39b 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/ThreadControl.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/extensions/util/ThreadControl.kt @@ -202,7 +202,7 @@ class ThreadControl : Extension() { if (member != oldOwner) { footer { text = "Transferred by ${member.mention}" - icon = member.avatar?.url + icon = member.avatar?.cdnUrl?.toUrl() } } timestamp = Clock.System.now() diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/utils/ResponseHelper.kt b/src/main/kotlin/org/hyacinthbots/lilybot/utils/ResponseHelper.kt index fbf03b84..8a3d3386 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/utils/ResponseHelper.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/utils/ResponseHelper.kt @@ -31,7 +31,7 @@ suspend inline fun EmbedBuilder.baseModerationEmbed(reason: String?, targetUser: } footer { text = "Requested by ${commandUser.asUserOrNull()?.tag}" - icon = commandUser.asUserOrNull()?.avatar?.url + icon = commandUser.asUserOrNull()?.avatar?.cdnUrl?.toUrl() } } diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/utils/_Constants.kt b/src/main/kotlin/org/hyacinthbots/lilybot/utils/_Constants.kt index ac439015..4bebc87d 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/utils/_Constants.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/utils/_Constants.kt @@ -22,6 +22,8 @@ val SENTRY_DSN = envOrNull("SENTRY_DSN") /** The environment the bot is being run in. production or development. */ val ENVIRONMENT = env("ENVIRONMENT") +val ENV = envOrNull("STATUS_URL") + const val BUILD_ID: String = "@build_id@" const val LILY_VERSION: String = "@version@" diff --git a/src/main/kotlin/org/hyacinthbots/lilybot/utils/_Utils.kt b/src/main/kotlin/org/hyacinthbots/lilybot/utils/_Utils.kt index 7b4ec581..4ef3df16 100644 --- a/src/main/kotlin/org/hyacinthbots/lilybot/utils/_Utils.kt +++ b/src/main/kotlin/org/hyacinthbots/lilybot/utils/_Utils.kt @@ -2,7 +2,11 @@ package org.hyacinthbots.lilybot.utils import com.kotlindiscord.kord.extensions.builders.ExtensibleBotBuilder import com.kotlindiscord.kord.extensions.extensions.Extension +import com.kotlindiscord.kord.extensions.utils.hasPermission import com.kotlindiscord.kord.extensions.utils.loadModule +import dev.kord.common.entity.Permission +import dev.kord.common.entity.Snowflake +import dev.kord.core.Kord import dev.kord.core.behavior.GuildBehavior import dev.kord.core.behavior.RoleBehavior import dev.kord.core.entity.Message @@ -47,8 +51,12 @@ internal val utilsLogger = KotlinLogging.logger("Checks Logger") * @author NoComment1105 * @since 4.1.0 */ -suspend inline fun canPingRole(role: RoleBehavior?) = - role != null && role.guild.getRoleOrNull(role.id)?.mentionable == true +suspend inline fun canPingRole(role: RoleBehavior?, guildId: Snowflake, kord: Kord) = + if (kord.getSelf().asMemberOrNull(guildId)?.hasPermission(Permission.MentionEveryone) == true) { + true + } else { + role != null && role.guild.getRoleOrNull(role.id)?.mentionable == true + } /** * Get the number of guilds the bot is in. @@ -92,7 +100,7 @@ fun getDmResult(shouldDm: Boolean, dm: Message?): DmResult = * @author NoComment1105 * @since 4.2.0 */ -fun String?.fitsEmbed(): Boolean? { +fun String?.fitsEmbedField(): Boolean? { this ?: return null return this.length <= 1024 } @@ -122,7 +130,7 @@ fun String?.ifNullOrEmpty(defaultValue: () -> String): String = fun Message?.trimmedContents(): String? { this ?: return null return if (this.content.length > 1024) { - this.content.substring(0, 1020) + " ..." + this.content.substring(0, 1021) + "..." } else { this.content } @@ -136,7 +144,7 @@ fun Message?.trimmedContents(): String? { fun String?.trimmedContents(): String? { this ?: return null return if (this.length > 1024) { - this.substring(0, 1020) + " ..." + this.substring(0, 1021) + "..." } else { this } @@ -167,7 +175,7 @@ fun Message?.trimmedContents(desiredLength: Int): String? { this ?: return null val useRegularLength = this.content.length < desiredLength.coerceIn(1, 1020) return if (this.content.length > desiredLength.coerceIn(1, 1020)) { - this.content.substring(0, if (useRegularLength) this.content.length else desiredLength) + "..." + this.content.substring(0, if (useRegularLength) this.content.length else desiredLength.minus(3)) + "..." } else { this.content } @@ -182,7 +190,7 @@ fun String?.trimmedContents(desiredLength: Int): String? { this ?: return null val useRegularLength = this.length < desiredLength.coerceIn(1, 1020) return if (this.length > desiredLength.coerceIn(1, 1020)) { - this.substring(0, if (useRegularLength) this.length else desiredLength) + "..." + this.substring(0, if (useRegularLength) this.length else desiredLength.minus(3)) + "..." } else { this } @@ -215,11 +223,11 @@ suspend inline fun Extension.updateDefaultPresence() { fun generateBulkDeleteFile(messages: Set<Message>): String? = if (messages.isNotEmpty()) { "# Messages\n\n**Total:** ${messages.size}\n\n" + - messages.reversed().joinToString("\n") { // Reversed for chronology - "* [${ - it.timestamp.toLocalDateTime(TimeZone.UTC).toString().replace("T", " @ ") - } UTC] **${it.author?.username}** (${it.author?.id}) » ${it.content}" - } + messages.reversed().joinToString("\n") { // Reversed for chronology + "* [${ + it.timestamp.toLocalDateTime(TimeZone.UTC).toString().replace("T", " @ ") + } UTC] **${it.author?.username}** (${it.author?.id}) » ${it.content}" + } } else { null }