diff --git a/Dockerfile b/Dockerfile index c4dac15..4edcdd9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,6 +5,6 @@ RUN gradle shadowJar --no-daemon FROM openjdk:11.0.8-jre-slim RUN mkdir /config/ -COPY --from=build /keeper/build/libs/*.jar / +COPY --from=build /keeper/build/libs/Keeper.jar / ENTRYPOINT ["java", "-jar", "/Keeper.jar"] \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index a0140d4..de3b041 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,6 +12,7 @@ plugins { repositories { mavenCentral() jcenter() + maven("https://oss.sonatype.org/content/repositories/snapshots/") } dependencies { @@ -36,5 +37,5 @@ tasks { object Versions { const val BOT = "1.2.0" - const val DISCORDKT = "0.19.1" + const val DISCORDKT = "0.22.0-SNAPSHOT" } \ No newline at end of file diff --git a/commands.md b/commands.md index bc795de..ebae07d 100644 --- a/commands.md +++ b/commands.md @@ -3,15 +3,15 @@ ## Key | Symbol | Meaning | | ----------- | ------------------------------ | -| (Argument) | Argument is not required. | +| (Argument) | Argument is not required. | ## Configuration -| Commands | Arguments | Description | -| ----------- | ------------- | ---------------------------------------------------------- | -| configure | | Configure a guild to use Keeper. | -| setPrefix | Prefix | Set the prefix required for the bot to register a command. | -| setReaction | Unicode Emote | Set the reaction used to save messages | -| setRole | Role | Set the role required to use this bot. | +| Commands | Arguments | Description | +| ----------- | --------- | ---------------------------------------------------------- | +| configure | | Configure a guild to use Keeper. | +| setPrefix | Prefix | Set the prefix required for the bot to register a command. | +| setReaction | Emoji | Set the reaction used to save messages | +| setRole | Role | Set the role required to use this bot. | ## General | Commands | Arguments | Description | diff --git a/docker-compose.yml b/docker-compose.yml index dae0abf..20224fb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,10 +1,8 @@ version: '3.7' services: - keeper: - container_name: Keeper - build: - dockerfile: Dockerfile - context: . + bot: + container_name: keeper + image: ddivad195/keeper:latest volumes: - type: bind source: ./config/config.json diff --git a/src/main/kotlin/me/ddivad/keeper/Main.kt b/src/main/kotlin/me/ddivad/keeper/Main.kt index cab2353..5eab0ea 100644 --- a/src/main/kotlin/me/ddivad/keeper/Main.kt +++ b/src/main/kotlin/me/ddivad/keeper/Main.kt @@ -1,84 +1,80 @@ package me.ddivad.keeper -import com.google.gson.Gson +import com.gitlab.kordlib.common.entity.Snowflake +import com.gitlab.kordlib.gateway.Intent +import com.gitlab.kordlib.gateway.PrivilegedIntent import me.ddivad.keeper.dataclasses.Configuration import me.ddivad.keeper.extensions.requiredPermissionLevel import me.ddivad.keeper.services.PermissionsService import me.ddivad.keeper.services.StatisticsService import me.jakejmattson.discordkt.api.dsl.bot -import me.jakejmattson.discordkt.api.extensions.jda.fullName -import me.jakejmattson.discordkt.api.extensions.jda.profileLink -import me.jakejmattson.discordkt.api.extensions.jda.toMember +import me.jakejmattson.discordkt.api.extensions.addField +import me.jakejmattson.discordkt.api.extensions.addInlineField +import me.jakejmattson.discordkt.api.extensions.profileLink +import me.jakejmattson.discordkt.api.extensions.toSnowflake import java.awt.Color -import java.util.* -data class Properties(val author: String, val version: String, val discordKt: String, val repository: String) - -val startTime = Date() - -fun main(args: Array) { +@PrivilegedIntent +suspend fun main(args: Array) { val token = System.getenv("BOT_TOKEN") ?: null - val prefix = System.getenv("DEFAULT_PREFIX") ?: "" + val defaultPrefix = System.getenv("DEFAULT_PREFIX") ?: "" require(token != null) { "Expected the bot token as an environment variable" } bot(token) { - configure { - val (configuration, permissionsService, statsService: StatisticsService) - = it.getInjectionObjects(Configuration::class, PermissionsService::class, StatisticsService::class) + prefix { + val configuration = discord.getInjectionObjects(Configuration::class) + guild?.let { configuration[guild!!.id.longValue]?.prefix } ?: defaultPrefix + } + configure { commandReaction = null allowMentionPrefix = true + theme = Color(0x00BFFF) + } - prefix { - it.guild?.let { configuration[it.idLong]?.prefix } ?: prefix + mentionEmbed { + val (configuration, statsService) = it.discord.getInjectionObjects(Configuration::class, StatisticsService::class) + val guild = it.guild ?: return@mentionEmbed + val guildConfiguration = configuration[it.guild!!.id.longValue] ?: return@mentionEmbed + val self = it.channel.kord.getSelf() + val liveRole = guild.getRole(guildConfiguration.requiredRoleId.toSnowflake()) + author { + val user = guild.kord.getUser(Snowflake(394484823944593409)) + icon = user?.avatar?.url + name = user?.username + url = user?.profileLink } - colors { - infoColor = Color(0x00BFFF) + title = "Keeper" + thumbnail { + url = self.avatar.url } - - mentionEmbed { - val guild = it.guild ?: return@mentionEmbed - val jda = it.discord.jda - val prefix = it.relevantPrefix - val role = configuration[guild.idLong]?.getLiveRole(jda)?.takeUnless { it == guild.publicRole }?.asMention - ?: "" - - author { - jda.retrieveUserById(394484823944593409).queue { user -> - iconUrl = user.effectiveAvatarUrl - name = user.fullName() - url = user.profileLink - } - } - - simpleTitle = "Keeper" - thumbnail = jda.selfUser.effectiveAvatarUrl - color = infoColor - description = "A bot for saving useful messages to a DM by reacting to them." - addInlineField("Required role", role) - addInlineField("Prefix", prefix) - addField("Config Info", "```" + - "Enabled: ${configuration[it.guild!!.idLong]?.enabled}\n" + - "Reaction: ${configuration[it.guild!!.idLong]?.bookmarkReaction}\n" + - "```") - addField("Bot Info", "```" + - "Version: 1.2.0\n" + - "DiscordKt: 0.19.0\n" + - "Kotlin: ${KotlinVersion.CURRENT}\n" + - "Uptime: ${statsService.uptime}" + - "```") - addInlineField("Source", "http://github.com/ddivad195/keeper") - } + color = it.discord.configuration.theme + description = "A bot for saving useful messages to a DM by reacting to them." + addInlineField("Required role", liveRole.mention) + addInlineField("Prefix", it.prefix()) + addField("Config Info", "```" + + "Enabled: ${guildConfiguration.enabled}\n" + + "Reaction: ${guildConfiguration.bookmarkReaction}\n" + + "```") + addField("Bot Info", "```" + + "Version: 1.3.0\n" + + "DiscordKt: 0.19.0\n" + + "Kotlin: ${KotlinVersion.CURRENT}\n" + + "```") + addField("Uptime", statsService.uptime) + addField("Source", "http://github.com/ddivad195/keeper") + } - visibilityPredicate { - val guild = it.guild ?: return@visibilityPredicate false - val member = it.user.toMember(guild)!! - val permission = it.command.requiredPermissionLevel + permissions { + val requiredPermissionLevel = command.requiredPermissionLevel + val guild = guild ?: return@permissions false + val member = user.asMember(guild.id) - permissionsService.hasClearance(guild, it.user, permission) - } + val permissionsService = discord.getInjectionObjects(PermissionsService::class) + return@permissions permissionsService.hasClearance(member, requiredPermissionLevel) } + } -} \ No newline at end of file +} diff --git a/src/main/kotlin/me/ddivad/keeper/commands/GeneralCommands.kt b/src/main/kotlin/me/ddivad/keeper/commands/GeneralCommands.kt index bdb5490..5b0c5fe 100644 --- a/src/main/kotlin/me/ddivad/keeper/commands/GeneralCommands.kt +++ b/src/main/kotlin/me/ddivad/keeper/commands/GeneralCommands.kt @@ -3,24 +3,20 @@ package me.ddivad.keeper.commands import me.ddivad.keeper.dataclasses.Configuration import me.ddivad.keeper.extensions.requiredPermissionLevel import me.ddivad.keeper.services.Permission -import me.jakejmattson.discordkt.api.annotations.CommandSet import me.jakejmattson.discordkt.api.arguments.MessageArg -import me.jakejmattson.discordkt.api.dsl.command.commands -import me.jakejmattson.discordkt.api.services.ConversationService +import me.jakejmattson.discordkt.api.dsl.commands -@CommandSet("General") -fun generalCommands(configuration: Configuration) = commands { - command("delete") { +fun generalCommands(configuration: Configuration) = commands("General") { + dmCommand("delete") { description = "Delete a Keeper bookmark by ID inside of DM channel" - requiresGuild = false - requiredPermissionLevel = Permission.EVERYONE + requiredPermissionLevel = Permission.USER execute(MessageArg) { - val message = it.args.first + val message = args.first - if (message.author == it.discord.jda.selfUser && it.guild == null) { - message.delete().queue() + if (message.author == this.channel.kord.getSelf().asUser()) { + message.delete() } else { - it.unsafeRespond("Can only delete messages sent by ${it.discord.jda.selfUser.asMention} in direct message channels.") + respond("Can only delete messages sent by ${this.channel.kord.getSelf().mention} in direct message channels.") } } } diff --git a/src/main/kotlin/me/ddivad/keeper/commands/GuildConfigurationCommands.kt b/src/main/kotlin/me/ddivad/keeper/commands/GuildConfigurationCommands.kt index 04aad2e..10f6bb4 100644 --- a/src/main/kotlin/me/ddivad/keeper/commands/GuildConfigurationCommands.kt +++ b/src/main/kotlin/me/ddivad/keeper/commands/GuildConfigurationCommands.kt @@ -2,66 +2,66 @@ package me.ddivad.keeper.commands import me.ddivad.keeper.conversations.ConfigurationConversation import me.ddivad.keeper.dataclasses.Configuration -import me.jakejmattson.discordkt.api.annotations.CommandSet import me.jakejmattson.discordkt.api.arguments.* -import me.jakejmattson.discordkt.api.dsl.command.commands -import me.jakejmattson.discordkt.api.services.ConversationService +import me.jakejmattson.discordkt.api.dsl.commands -@CommandSet("Configuration") -fun guildConfigurationCommands(configuration: Configuration, conversationService: ConversationService) = commands { - command("configure") { +fun guildConfigurationCommands(configuration: Configuration) = commands("Configuration") { + guildCommand("configure") { description = "Configure a guild to use Keeper." execute { - if (configuration.hasGuildConfig(it.guild!!.idLong)) - return@execute it.respond("Guild configuration exists. To modify it use the commands to set values.") - - conversationService.startPublicConversation(it.author, it.channel, it.guild!!) - it.respond("Guild setup") + if (configuration.hasGuildConfig(guild.id.longValue)) { + respond("Guild configuration exists. To modify it use the commands to set values.") + return@execute + } + ConfigurationConversation(configuration) + .createConfigurationConversation(guild) + .startPublicly(discord, author, channel) + respond("Guild setup") } } - - command("setPrefix") { + + guildCommand("setPrefix") { description = "Set the prefix required for the bot to register a command." execute(AnyArg("Prefix")) { - if (!configuration.hasGuildConfig(it.guild!!.idLong)) - return@execute it.respond("Please run the **configure** command to set this initially.") - - val prefix = it.args.first + if (!configuration.hasGuildConfig(guild.id.longValue)) { + respond("Guild configuration exists. To modify it use the commands to set values.") + return@execute + } - configuration[it.guild!!.idLong]?.prefix = prefix + val prefix = args.first + configuration[guild.id.longValue]?.prefix = prefix configuration.save() - - it.respond("Prefix set to: $prefix") + respond("Prefix set to: $prefix") } } - command("setRole") { + guildCommand("setRole") { description = "Set the role required to use this bot." execute(RoleArg) { - if (!configuration.hasGuildConfig(it.guild!!.idLong)) - return@execute it.respond("Please run the **configure** command to set this initially.") - - val requiredRole = it.args.first + if (!configuration.hasGuildConfig(guild.id.longValue)) { + respond("Guild configuration exists. To modify it use the commands to set values.") + return@execute + } - configuration[it.guild!!.idLong]?.requiredRoleId = requiredRole.idLong + val requiredRole = args.first + configuration[guild.id.longValue]?.requiredRoleId = requiredRole.id.longValue configuration.save() - - it.respond("Required role set to: ${requiredRole.name}") + respond("Required role set to: ${requiredRole.name}") } - command("setReaction") { + guildCommand("setReaction") { description = "Set the reaction used to save messages" - execute(UnicodeEmoteArg) { - if (!configuration.hasGuildConfig(it.guild!!.idLong)) - return@execute it.respond("Please run the **configure** command to set this initially.") + execute(UnicodeEmojiArg) { + if (!configuration.hasGuildConfig(guild.id.longValue)) { + respond("Guild configuration exists. To modify it use the commands to set values.") + return@execute + } - val reaction = it.args.first - - configuration[it.guild!!.idLong]?.bookmarkReaction = reaction + val reaction = args.first + configuration[guild.id.longValue]?.bookmarkReaction = reaction.unicode configuration.save() - - it.respond("Reaction set to: $reaction") + respond("Reaction set to: $reaction") } } } diff --git a/src/main/kotlin/me/ddivad/keeper/commands/OperationCommands.kt b/src/main/kotlin/me/ddivad/keeper/commands/OperationCommands.kt index 5304f4b..8656b21 100644 --- a/src/main/kotlin/me/ddivad/keeper/commands/OperationCommands.kt +++ b/src/main/kotlin/me/ddivad/keeper/commands/OperationCommands.kt @@ -2,43 +2,42 @@ package me.ddivad.keeper.commands import me.ddivad.keeper.dataclasses.Configuration import me.ddivad.keeper.services.StatisticsService -import me.ddivad.keeper.utilities.buildStatsEmbed -import me.jakejmattson.discordkt.api.annotations.CommandSet -import me.jakejmattson.discordkt.api.dsl.command.commands -import me.jakejmattson.discordkt.api.services.ConversationService +import me.ddivad.keeper.embeds.buildStatsEmbed +import me.jakejmattson.discordkt.api.dsl.commands -@CommandSet("Operation") -fun operationCommands(configuration: Configuration, conversationService: ConversationService, statsService: StatisticsService) = commands { - command("enable") { +fun operationCommands(configuration: Configuration, statsService: StatisticsService) = commands("Operation") { + guildCommand("enable") { description = "Enable the bot's functionality" execute { - if (!configuration.hasGuildConfig(it.guild!!.idLong)) - return@execute it.respond("Please run the **configure** command to set this initially.") - - configuration[it.guild!!.idLong]?.enabled = true + if (!configuration.hasGuildConfig(guild.id.longValue)) { + respond("Guild configuration exists. To modify it use the commands to set values.") + return@execute + } + configuration[guild.id.longValue]?.enabled = true configuration.save() - - it.respond("Bot enabled") + respond("Bot enabled") } } - command("disable") { + guildCommand("disable") { description = "Enable the bot's functionality" execute { - if (!configuration.hasGuildConfig(it.guild!!.idLong)) - return@execute it.respond("Please run the **configure** command to set this initially.") - - configuration[it.guild!!.idLong]?.enabled = false + if (!configuration.hasGuildConfig(guild.id.longValue)) { + respond("Guild configuration exists. To modify it use the commands to set values.") + return@execute + } + configuration[guild.id.longValue]?.enabled = false configuration.save() - - it.respond("Bot disabled") + respond("Bot disabled") } } - command("stats") { + guildCommand("stats") { description = "View statistics about Keeper" execute { - it.respond(buildStatsEmbed(it.guild!!, configuration, statsService)) + respond { + buildStatsEmbed(guild, configuration, statsService) + } } } } \ No newline at end of file diff --git a/src/main/kotlin/me/ddivad/keeper/conversations/ConfigurationConversation.kt b/src/main/kotlin/me/ddivad/keeper/conversations/ConfigurationConversation.kt index 5b0ecbc..a6a9d74 100644 --- a/src/main/kotlin/me/ddivad/keeper/conversations/ConfigurationConversation.kt +++ b/src/main/kotlin/me/ddivad/keeper/conversations/ConfigurationConversation.kt @@ -1,20 +1,18 @@ package me.ddivad.keeper.conversations +import com.gitlab.kordlib.core.entity.Guild import me.ddivad.keeper.dataclasses.Configuration import me.jakejmattson.discordkt.api.arguments.EveryArg import me.jakejmattson.discordkt.api.arguments.RoleArg -import me.jakejmattson.discordkt.api.arguments.UnicodeEmoteArg -import me.jakejmattson.discordkt.api.dsl.conversation.Conversation -import me.jakejmattson.discordkt.api.dsl.conversation.conversation -import net.dv8tion.jda.api.entities.Guild +import me.jakejmattson.discordkt.api.arguments.UnicodeEmojiArg +import me.jakejmattson.discordkt.api.dsl.conversation -class ConfigurationConversation(private val configuration: Configuration): Conversation() { - @Conversation.Start +class ConfigurationConversation(private val configuration: Configuration) { fun createConfigurationConversation(guild: Guild) = conversation { val prefix = promptMessage(EveryArg, "Bot prefix:") val role = promptMessage(RoleArg, "Admin role:") - val reaction = promptMessage(UnicodeEmoteArg, "Save message reaction:") + val reaction = promptMessage(UnicodeEmojiArg, "Save message reaction:") - configuration.setup(guild, prefix, role, reaction) + configuration.setup(guild, prefix, role, reaction.unicode) } } \ No newline at end of file diff --git a/src/main/kotlin/me/ddivad/keeper/dataclasses/Configuration.kt b/src/main/kotlin/me/ddivad/keeper/dataclasses/Configuration.kt index 67b9563..546545a 100644 --- a/src/main/kotlin/me/ddivad/keeper/dataclasses/Configuration.kt +++ b/src/main/kotlin/me/ddivad/keeper/dataclasses/Configuration.kt @@ -1,9 +1,10 @@ package me.ddivad.keeper.dataclasses -import me.jakejmattson.discordkt.api.dsl.data.Data -import net.dv8tion.jda.api.JDA -import net.dv8tion.jda.api.entities.Guild -import net.dv8tion.jda.api.entities.Role +import com.gitlab.kordlib.core.entity.Guild +import com.gitlab.kordlib.core.entity.Role +import me.jakejmattson.discordkt.api.dsl.Data +import me.jakejmattson.discordkt.api.extensions.toSnowflake + data class Configuration(val botOwner: Long = 394484823944593409, var totalBookmarks: Int = 0, @@ -11,11 +12,11 @@ data class Configuration(val botOwner: Long = 394484823944593409, operator fun get(id: Long) = guildConfigurations[id] fun setup(guild: Guild, prefix: String, role: Role, reaction: String) { - if (guildConfigurations[guild.idLong] != null) return + if (guildConfigurations[guild.id.longValue] != null) return - val newConfiguration = GuildConfiguration(prefix, role.idLong, reaction, true) + val newConfiguration = GuildConfiguration(prefix, role.id.longValue, reaction, true) - guildConfigurations[guild.idLong] = newConfiguration + guildConfigurations[guild.id.longValue] = newConfiguration save() } fun hasGuildConfig(guildId: Long) = guildConfigurations.containsKey(guildId) @@ -28,5 +29,5 @@ data class GuildConfiguration( var enabled: Boolean, var bookmarkCount: Int = 0 ) { - fun getLiveRole(jda: JDA) = jda.getRoleById(requiredRoleId) + suspend fun getLiveRole(guild: Guild) = guild.getRole(requiredRoleId.toSnowflake()) } \ No newline at end of file diff --git a/src/main/kotlin/me/ddivad/keeper/embeds/Embeds.kt b/src/main/kotlin/me/ddivad/keeper/embeds/Embeds.kt new file mode 100644 index 0000000..955b992 --- /dev/null +++ b/src/main/kotlin/me/ddivad/keeper/embeds/Embeds.kt @@ -0,0 +1,53 @@ +package me.ddivad.keeper.embeds + +import com.gitlab.kordlib.core.entity.Guild +import com.gitlab.kordlib.core.entity.Message +import com.gitlab.kordlib.core.entity.User +import com.gitlab.kordlib.rest.Image +import com.gitlab.kordlib.rest.builder.message.EmbedBuilder +import me.ddivad.keeper.dataclasses.Configuration +import me.ddivad.keeper.extensions.jumpLink +import me.ddivad.keeper.services.StatisticsService +import me.jakejmattson.discordkt.api.extensions.addField +import java.awt.Color + +fun EmbedBuilder.buildSavedMessageEmbed(messageAuthor: User, message: Message, guild: Guild) { + color = Color(0x00BFFF) + author { + name = messageAuthor.tag + icon = messageAuthor.avatar.url + } + description = "**Saved from **${message.channel.mention}\n\n${message.content}" + if (message.attachments.isNotEmpty()) image = message.attachments.first().url + + addField("", "[View Original](${message.jumpLink(guild.id.value)})") + footer { + icon = guild.getIconUrl(Image.Format.PNG) ?: "" + text = guild.name + } +} + +fun EmbedBuilder.buildStatsEmbed(guild: Guild, configuration: Configuration, statsService: StatisticsService) { + title = "Stats" + color = Color(0x00BFFF) + field { + name = "Messages Bookmarked" + value = """ + ``` + Total Bookmarks (global): ${String.format("%4d", configuration.totalBookmarks)} + Total Bookmarks (guild): ${String.format("%4d", configuration[guild.id.longValue]?.bookmarkCount)} + Since Restart: ${String.format("%4d", statsService.totalBookmarks)} + ``` + """.trimIndent() + } + field { + name = "Ping" + value = statsService.ping + inline = true + } + + field { + name = "Uptime" + value = statsService.uptime + } +} \ No newline at end of file diff --git a/src/main/kotlin/me/ddivad/keeper/extensions/Command.kt b/src/main/kotlin/me/ddivad/keeper/extensions/Command.kt index cbafbb1..cfb343d 100644 --- a/src/main/kotlin/me/ddivad/keeper/extensions/Command.kt +++ b/src/main/kotlin/me/ddivad/keeper/extensions/Command.kt @@ -2,7 +2,7 @@ package me.ddivad.keeper.extensions import me.ddivad.keeper.services.DEFAULT_REQUIRED_PERMISSION import me.ddivad.keeper.services.Permission -import me.jakejmattson.discordkt.api.dsl.command.Command +import me.jakejmattson.discordkt.api.dsl.Command val commandPermissions: MutableMap = mutableMapOf() diff --git a/src/main/kotlin/me/ddivad/keeper/extensions/Kord.kt b/src/main/kotlin/me/ddivad/keeper/extensions/Kord.kt new file mode 100644 index 0000000..2968b60 --- /dev/null +++ b/src/main/kotlin/me/ddivad/keeper/extensions/Kord.kt @@ -0,0 +1,5 @@ +package me.ddivad.keeper.extensions + +import com.gitlab.kordlib.core.entity.Message + +fun Message.jumpLink(guildId:String) = "https://discord.com/channels/${guildId}/${channel.id.value}/${id.value}" \ No newline at end of file diff --git a/src/main/kotlin/me/ddivad/keeper/listeners/MessageListener.kt b/src/main/kotlin/me/ddivad/keeper/listeners/MessageListener.kt index c2e4401..81dbd06 100644 --- a/src/main/kotlin/me/ddivad/keeper/listeners/MessageListener.kt +++ b/src/main/kotlin/me/ddivad/keeper/listeners/MessageListener.kt @@ -1,34 +1,32 @@ package me.ddivad.keeper.listeners -import com.google.common.eventbus.Subscribe +import com.gitlab.kordlib.core.event.message.ReactionAddEvent +import com.gitlab.kordlib.kordx.emoji.Emojis +import com.gitlab.kordlib.kordx.emoji.addReaction import me.ddivad.keeper.dataclasses.Configuration import me.ddivad.keeper.services.StatisticsService -import me.ddivad.keeper.utilities.buildSavedMessageEmbed -import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent -import net.dv8tion.jda.api.events.message.priv.react.PrivateMessageReactionAddEvent +import me.ddivad.keeper.embeds.buildSavedMessageEmbed +import me.jakejmattson.discordkt.api.dsl.listeners +import me.jakejmattson.discordkt.api.extensions.isSelf +import me.jakejmattson.discordkt.api.extensions.sendPrivateMessage -class MessageListener(private val configuration: Configuration, private val statsService: StatisticsService) { - @Subscribe - fun onGuildMessageReactionAddEvent(event: GuildMessageReactionAddEvent) { - if (event.user.isBot) return - if (!configuration[event.guild.idLong]?.enabled!!) return - if (event.reaction.reactionEmote.name == configuration[event.guild.idLong]?.bookmarkReaction) { - statsService.bookmarkAdded(event) - event.channel.retrieveMessageById(event.messageId).queue { it -> - event.user.openPrivateChannel().queue{ channel -> - channel.sendMessage(buildSavedMessageEmbed(it.author, it, event.channel, event.guild)).queue{ message -> - message.addReaction("❌").queue() - } - } - } +fun onGuildMessageReactionAddEvent(configuration: Configuration, statsService: StatisticsService) = listeners { + on { + val guild = guild?.asGuildOrNull() ?: return@on + if (!configuration[guild.id.longValue]?.enabled!!) return@on + if (this.emoji.name == configuration[guild.id.longValue]?.bookmarkReaction) { + statsService.bookmarkAdded(this) + this.user.sendPrivateMessage { + buildSavedMessageEmbed(getUser(), message.asMessage(), guild) + }.addReaction(Emojis.x) } } - @Subscribe - fun onPrivateMessageReactionAddEvent(event: PrivateMessageReactionAddEvent) { - if (event.user!!.isBot) return - if (event.reactionEmote.name == "❌") { - event.channel.retrieveMessageById(event.messageId).queue{ it.delete().queue() } + on { + if (this.getGuild() == null && this.emoji.name == "❌" && !this.user.isSelf()) { + this.message.delete() } } + } + diff --git a/src/main/kotlin/me/ddivad/keeper/preconditions/PermissionPrecondition.kt b/src/main/kotlin/me/ddivad/keeper/preconditions/PermissionPrecondition.kt deleted file mode 100644 index a2aa49c..0000000 --- a/src/main/kotlin/me/ddivad/keeper/preconditions/PermissionPrecondition.kt +++ /dev/null @@ -1,26 +0,0 @@ -package me.ddivad.keeper.preconditions - -import me.ddivad.keeper.extensions.requiredPermissionLevel -import me.ddivad.keeper.services.PermissionsService -import me.jakejmattson.discordkt.api.dsl.command.CommandEvent -import me.jakejmattson.discordkt.api.dsl.preconditions.* - -class PermissionPrecondition(private val permissionsService: PermissionsService) : Precondition() { - override fun evaluate(event: CommandEvent<*>): PreconditionResult { - val command = event.command ?: return Fail() - val requiredPermissionLevel = command.requiredPermissionLevel - - if (event.guild == null) { - return if(permissionsService.hasClearance(null, event.author, requiredPermissionLevel)) { - Pass - } else { - Fail("Missing clearance to use this command.") - } - } else { - val guild = event.guild!! - if (!permissionsService.hasClearance(event.guild, event.author, requiredPermissionLevel)) - return Fail("Missing clearance to use this command.") - return Pass - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/me/ddivad/keeper/services/PermissionsService.kt b/src/main/kotlin/me/ddivad/keeper/services/PermissionsService.kt index 57c48fd..1e2e793 100644 --- a/src/main/kotlin/me/ddivad/keeper/services/PermissionsService.kt +++ b/src/main/kotlin/me/ddivad/keeper/services/PermissionsService.kt @@ -1,42 +1,39 @@ package me.ddivad.keeper.services +import com.gitlab.kordlib.core.entity.Member +import kotlinx.coroutines.flow.toList import me.jakejmattson.discordkt.api.annotations.Service import me.ddivad.keeper.dataclasses.Configuration -import me.jakejmattson.discordkt.api.extensions.jda.toMember -import net.dv8tion.jda.api.entities.Guild -import net.dv8tion.jda.api.entities.Member -import net.dv8tion.jda.api.entities.User enum class Permission { BOT_OWNER, GUILD_OWNER, + STAFF, USER, - EVERYONE + NONE } -val DEFAULT_REQUIRED_PERMISSION = Permission.USER +val DEFAULT_REQUIRED_PERMISSION = Permission.STAFF @Service class PermissionsService(private val configuration: Configuration) { - fun hasClearance(guild: Guild?, user: User, requiredPermissionLevel: Permission): Boolean { - val permissionLevel = guild?.getMember(user)?.let { getPermissionLevel(it) } + suspend fun hasClearance(member: Member, requiredPermissionLevel: Permission) = member.getPermissionLevel().ordinal <= requiredPermissionLevel.ordinal - return if(permissionLevel == null) { - requiredPermissionLevel == Permission.EVERYONE - } else { - getPermissionLevel(user.toMember(guild)!!).ordinal <= requiredPermissionLevel.ordinal - } - } - - private fun getPermissionLevel(member: Member) = + private suspend fun Member.getPermissionLevel() = when { - member.isBotOwner() -> Permission.BOT_OWNER - member.isGuildOwner() -> Permission.GUILD_OWNER - member.isUser() -> Permission.USER - else -> Permission.EVERYONE + isBotOwner() -> Permission.BOT_OWNER + isGuildOwner() -> Permission.GUILD_OWNER + isStaff() -> Permission.STAFF + isUser() -> Permission.USER + else -> Permission.NONE } - private fun Member.isBotOwner() = user.idLong == configuration.botOwner - private fun Member.isGuildOwner() = isOwner - private fun Member.isUser() = configuration[guild.idLong]?.getLiveRole(guild.jda) in roles + private fun Member.isBotOwner() = id.longValue == configuration.botOwner + private suspend fun Member.isGuildOwner() = isOwner() + private suspend fun Member.isStaff(): Boolean { + val config = configuration[guildId.longValue] ?: return false + return roles.toList().any { it.id.longValue == config.requiredRoleId } + } + + private suspend fun Member.isUser() = asMemberOrNull() != null } \ No newline at end of file diff --git a/src/main/kotlin/me/ddivad/keeper/services/StatisticsService.kt b/src/main/kotlin/me/ddivad/keeper/services/StatisticsService.kt index 74fed15..e1ceada 100644 --- a/src/main/kotlin/me/ddivad/keeper/services/StatisticsService.kt +++ b/src/main/kotlin/me/ddivad/keeper/services/StatisticsService.kt @@ -1,10 +1,11 @@ package me.ddivad.keeper.services +import com.gitlab.kordlib.core.event.message.ReactionAddEvent import me.jakejmattson.discordkt.api.annotations.Service import me.ddivad.keeper.dataclasses.Configuration import me.ddivad.keeper.utilities.timeToString import me.jakejmattson.discordkt.api.Discord -import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent +import me.jakejmattson.discordkt.api.extensions.toTimeString import java.util.* @Service @@ -17,16 +18,18 @@ class StatisticsService(private val configuration: Configuration, private val di _totalBookmarks = value } - fun bookmarkAdded(event: GuildMessageReactionAddEvent) { - totalBookmarks++ - configuration.totalBookmarks++ - configuration[event.guild.idLong]!!.bookmarkCount++ - configuration.save() + suspend fun bookmarkAdded(event: ReactionAddEvent) { + event.getGuild()?.let { + totalBookmarks++ + configuration.totalBookmarks++ + configuration[it.id.longValue]!!.bookmarkCount++ + configuration.save() + } } val uptime: String - get() = timeToString(Date().time - startTime.time) + get() = ((Date().time - startTime.time) / 1000).toTimeString() val ping: String - get() = "${discord.jda.gatewayPing} ms" + get() = "${discord.api.gateway.averagePing}" } \ No newline at end of file diff --git a/src/main/kotlin/me/ddivad/keeper/utilities/Embeds.kt b/src/main/kotlin/me/ddivad/keeper/utilities/Embeds.kt deleted file mode 100644 index 7a19ff1..0000000 --- a/src/main/kotlin/me/ddivad/keeper/utilities/Embeds.kt +++ /dev/null @@ -1,49 +0,0 @@ -package me.ddivad.keeper.utilities - -import me.ddivad.keeper.dataclasses.Configuration -import me.ddivad.keeper.services.StatisticsService -import me.jakejmattson.discordkt.api.dsl.embed.embed -import net.dv8tion.jda.api.entities.Guild -import net.dv8tion.jda.api.entities.Message -import net.dv8tion.jda.api.entities.MessageChannel -import net.dv8tion.jda.api.entities.User - -fun buildSavedMessageEmbed(messageAuthor: User, message: Message, messageChannel: MessageChannel, guild: Guild) = embed { - color = infoColor - author { - name = messageAuthor.asTag - iconUrl = messageAuthor.effectiveAvatarUrl - } - addField("Saved from #${messageChannel.name}", message.contentRaw) - addField("", "[View Original](${message.jumpUrl})") - footer { - text = guild.name - iconUrl = guild.iconUrl - timeStamp = message.timeCreated - } -} - -fun buildStatsEmbed(guild: Guild, configuration: Configuration, statsService: StatisticsService) = embed { - simpleTitle = "Stats" - color = infoColor - field { - name = "Messages Bookmarked" - value = """ - ``` - Total Bookmarks (global): ${String.format("%4d", configuration.totalBookmarks)} - Total Bookmarks (guild): ${String.format("%4d", configuration[guild.idLong]?.bookmarkCount)} - Since Restart: ${String.format("%4d", statsService.totalBookmarks)} - ``` - """.trimIndent() - } - field { - name = "Ping" - value = statsService.ping - inline = true - } - - field { - name = "Uptime" - value = statsService.uptime - } -} \ No newline at end of file