From 5e8749205cfeff6ebd2782791bb2511ab91bb533 Mon Sep 17 00:00:00 2001 From: Ikinon <36565735+Ikinon@users.noreply.github.com> Date: Sun, 23 Aug 2020 15:30:44 +0100 Subject: [PATCH 01/16] Start of lock command --- .../commands/moderation/LockCommand.kt | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt new file mode 100644 index 000000000..0266509d0 --- /dev/null +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt @@ -0,0 +1,62 @@ +package org.cascadebot.cascadebot.commands.moderation + +import net.dv8tion.jda.api.Permission +import net.dv8tion.jda.api.entities.ISnowflake +import net.dv8tion.jda.api.entities.Member +import net.dv8tion.jda.api.entities.Role +import net.dv8tion.jda.api.entities.TextChannel +import org.cascadebot.cascadebot.commandmeta.CommandContext +import org.cascadebot.cascadebot.commandmeta.MainCommand +import org.cascadebot.cascadebot.commandmeta.Module +import org.cascadebot.cascadebot.permissions.CascadePermission +import org.cascadebot.cascadebot.utils.DiscordUtils +import java.util.* + +class LockCommand : MainCommand() { + override fun onCommand(sender: Member, context: CommandContext) { + // Args: [role/member/channel] [channel] + + var channel: TextChannel = context.channel + if (context.args.size == 2) { + channel = DiscordUtils.getTextChannel(context.guild, context.getArg(1)) + ?: return context.reply("Invalid channel") + + } + + val temp: ISnowflake? = if (context.args.isNotEmpty()) { + DiscordUtils.getRole(context.getArg(0), context.guild) + ?: DiscordUtils.getMember(context.guild, context.getArg(0)) + ?: DiscordUtils.getTextChannel(context.guild, context.getArg(0)) + } else { + context.channel + } + var name: String? = null + when (temp) { + is Role -> { + channel.manager.putPermissionOverride(temp, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + name = temp.name + } + is Member -> { + channel.manager.putPermissionOverride(temp, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + name = temp.effectiveName + } + is TextChannel -> temp.manager.putPermissionOverride(context.guild.publicRole, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + } + context.typedMessaging.replySuccess(if (temp is TextChannel) "%s locked".format(temp.name) else "Channel locked for %s".format(name)) + + } + + + override fun command(): String { + return "lock" + } + + override fun permission(): CascadePermission? { + return CascadePermission.of("lock", false, Permission.MANAGE_CHANNEL) + } + + override fun module(): Module { + return Module.MODERATION + } + +} \ No newline at end of file From 5b7f841de268a76fa17de5bba0d7164ef0c28cd0 Mon Sep 17 00:00:00 2001 From: Ikinon <36565735+Ikinon@users.noreply.github.com> Date: Sat, 29 Aug 2020 14:00:01 +0100 Subject: [PATCH 02/16] commit --- .../commands/moderation/UnlockCommand.kt | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt new file mode 100644 index 000000000..dc8a7a5f5 --- /dev/null +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt @@ -0,0 +1,60 @@ +package org.cascadebot.cascadebot.commands.moderation + +import net.dv8tion.jda.api.Permission +import net.dv8tion.jda.api.entities.ISnowflake +import net.dv8tion.jda.api.entities.Member +import net.dv8tion.jda.api.entities.Role +import net.dv8tion.jda.api.entities.TextChannel +import org.cascadebot.cascadebot.commandmeta.CommandContext +import org.cascadebot.cascadebot.commandmeta.MainCommand +import org.cascadebot.cascadebot.commandmeta.Module +import org.cascadebot.cascadebot.permissions.CascadePermission +import org.cascadebot.cascadebot.utils.DiscordUtils +import java.util.* + +class UnlockCommand : MainCommand() { + override fun onCommand(sender: Member, context: CommandContext) { + var channel: TextChannel = context.channel + if (context.args.size == 2) { + channel = DiscordUtils.getTextChannel(context.guild, context.getArg(1)) + ?: return context.reply("Invalid channel") + + } + + val temp: ISnowflake? = if (context.args.isNotEmpty()) { + DiscordUtils.getRole(context.getArg(0), context.guild) + ?: DiscordUtils.getMember(context.guild, context.getArg(0)) + ?: DiscordUtils.getTextChannel(context.guild, context.getArg(0)) + } else { + context.channel + } + var name: String? = null + when (temp) { + is Role -> { + //channel.manager.putPermissionOverride(temp, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + name = temp.name + } + is Member -> { + //channel.manager.putPermissionOverride(temp, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + name = temp.effectiveName + } + ; + //is TextChannel -> temp.manager.putPermissionOverride(context.guild.publicRole, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + // ^ SET TO THE OLD PERMISSION BEFORE SOMEONE LOCKED THE CHANNEL FOR THE USER/ROLE + } + context.typedMessaging.replySuccess(if (temp is TextChannel) "%s unlocked".format(temp.name) else "Channel unlocked for %s".format(name)) + } + + override fun command(): String { + return "unlock" + } + + override fun permission(): CascadePermission? { + return CascadePermission.of("unlock", false, Permission.MANAGE_CHANNEL) + } + + override fun module(): Module { + return Module.MODERATION + } + +} \ No newline at end of file From 22f369b5e9fe8b8faecc312005f0a12b5c6631ab Mon Sep 17 00:00:00 2001 From: Ikinon <36565735+Ikinon@users.noreply.github.com> Date: Fri, 4 Sep 2020 15:11:36 +0100 Subject: [PATCH 03/16] Lock/Unlock/Templock commands --- .../commands/moderation/LockCommand.kt | 39 ++++-- .../commands/moderation/TempLockCommand.kt | 127 ++++++++++++++++++ .../commands/moderation/UnlockCommand.kt | 33 +++-- .../cascadebot/data/managers/LockManager.kt | 45 +++++++ .../cascadebot/data/objects/GuildData.kt | 2 + .../cascadebot/scheduler/ActionType.kt | 51 ++++++- .../cascadebot/scheduler/ScheduledAction.kt | 6 + src/main/resources/arguments.json | 54 ++++++++ src/main/resources/lang/en-GB.json | 36 +++-- 9 files changed, 352 insertions(+), 41 deletions(-) create mode 100644 src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt create mode 100644 src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt index 0266509d0..2aeed1c88 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt @@ -5,21 +5,21 @@ import net.dv8tion.jda.api.entities.ISnowflake import net.dv8tion.jda.api.entities.Member import net.dv8tion.jda.api.entities.Role import net.dv8tion.jda.api.entities.TextChannel +import net.dv8tion.jda.api.exceptions.PermissionException import org.cascadebot.cascadebot.commandmeta.CommandContext import org.cascadebot.cascadebot.commandmeta.MainCommand import org.cascadebot.cascadebot.commandmeta.Module +import org.cascadebot.cascadebot.data.managers.LockManager import org.cascadebot.cascadebot.permissions.CascadePermission import org.cascadebot.cascadebot.utils.DiscordUtils import java.util.* class LockCommand : MainCommand() { override fun onCommand(sender: Member, context: CommandContext) { - // Args: [role/member/channel] [channel] - var channel: TextChannel = context.channel if (context.args.size == 2) { channel = DiscordUtils.getTextChannel(context.guild, context.getArg(1)) - ?: return context.reply("Invalid channel") + ?: return context.typedMessaging.replyDanger(context.i18n("responses.cannot_find_channel_matching", context.getArg(1))) } @@ -27,23 +27,36 @@ class LockCommand : MainCommand() { DiscordUtils.getRole(context.getArg(0), context.guild) ?: DiscordUtils.getMember(context.guild, context.getArg(0)) ?: DiscordUtils.getTextChannel(context.guild, context.getArg(0)) + ?: return context.typedMessaging.replyDanger(context.i18n("commands.lock.invalid_argument", context.getArg(0))) } else { context.channel } + var name: String? = null - when (temp) { - is Role -> { - channel.manager.putPermissionOverride(temp, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() - name = temp.name + try { + when (temp) { + is Role -> { + LockManager.add(channel, temp) + channel.manager.putPermissionOverride(temp, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + name = "%s %s".format(context.i18n("arguments.role"), temp.asMention) + } + is Member -> { + LockManager.add(channel, temp) + channel.manager.putPermissionOverride(temp, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + name = "%s %s".format(context.i18n("arguments.member"), temp.asMention) + } + is TextChannel -> { + LockManager.add(temp) + temp.manager.putPermissionOverride(context.guild.publicRole, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + } } - is Member -> { - channel.manager.putPermissionOverride(temp, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() - name = temp.effectiveName - } - is TextChannel -> temp.manager.putPermissionOverride(context.guild.publicRole, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + } catch (e: PermissionException) { + context.uiMessaging.sendBotDiscordPermError(e.permission) + return } - context.typedMessaging.replySuccess(if (temp is TextChannel) "%s locked".format(temp.name) else "Channel locked for %s".format(name)) + + context.typedMessaging.replySuccess(if (temp is TextChannel) context.i18n("commands.lock.text_success", temp.name) else name?.let { context.i18n("commands.lock.success", channel.name, it) }) } diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt new file mode 100644 index 000000000..0bf3b2614 --- /dev/null +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt @@ -0,0 +1,127 @@ +package org.cascadebot.cascadebot.commands.moderation + +import net.dv8tion.jda.api.Permission +import net.dv8tion.jda.api.entities.ISnowflake +import net.dv8tion.jda.api.entities.Member +import net.dv8tion.jda.api.entities.Role +import net.dv8tion.jda.api.entities.TextChannel +import net.dv8tion.jda.api.exceptions.PermissionException +import org.cascadebot.cascadebot.commandmeta.CommandContext +import org.cascadebot.cascadebot.commandmeta.MainCommand +import org.cascadebot.cascadebot.commandmeta.Module +import org.cascadebot.cascadebot.data.managers.LockManager +import org.cascadebot.cascadebot.data.managers.ScheduledActionManager +import org.cascadebot.cascadebot.permissions.CascadePermission +import org.cascadebot.cascadebot.scheduler.ActionType +import org.cascadebot.cascadebot.scheduler.ScheduledAction +import org.cascadebot.cascadebot.utils.DiscordUtils +import org.cascadebot.cascadebot.utils.FormatUtils +import org.cascadebot.cascadebot.utils.ParserUtils +import java.time.Instant +import java.time.OffsetDateTime +import java.time.temporal.ChronoUnit +import java.util.* + +class TempLockCommand : MainCommand() { + override fun onCommand(sender: Member, context: CommandContext) { + if (context.args.isEmpty()) { + context.uiMessaging.replyUsage() + return + } + + val longDuration = ParserUtils.parseTextTime(context.getArg(0), false) + if (longDuration <= 0) { + context.typedMessaging.replyDanger(context.i18n("responses.invalid_duration")) + return + } + + var channel: TextChannel = context.channel + if (context.args.size == 3) { + val tempChannel = DiscordUtils.getTextChannel(context.guild, context.getArg(2)) + if (tempChannel != null) { + channel = tempChannel + } else { + context.typedMessaging.replyDanger(context.i18n("responses.cannot_find_channel_matching", context.getArg(2))) + return + } + } + + val temp: ISnowflake? = if (context.args.size > 1) { + DiscordUtils.getRole(context.getArg(1), context.guild) + ?: DiscordUtils.getMember(context.guild, context.getArg(1)) + ?: DiscordUtils.getTextChannel(context.guild, context.getArg(1)) + ?: return context.typedMessaging.replyDanger(context.i18n("commands.lock.invalid_argument", context.getArg(0))) + } else { + context.channel + } + + val toAction = ScheduledAction.LockActionData(channel.idLong, null, 0, 0) + + var name: String? = null + try { + when (temp) { + is Role -> { + if (channel.getPermissionOverride(temp)?.denied?.contains(Permission.MESSAGE_WRITE)!!) toAction.oldPermission = false + if (channel.getPermissionOverride(temp)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) toAction.oldPermission = true + + LockManager.add(channel, temp) + channel.manager.putPermissionOverride(temp, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + + toAction.targetRoleID = temp.idLong + name = "%s %s".format(context.i18n("arguments.role"), temp.asMention) + } + is Member -> { + if (channel.getPermissionOverride(temp)?.denied?.contains(Permission.MESSAGE_WRITE)!!) toAction.oldPermission = false + if (channel.getPermissionOverride(temp)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) toAction.oldPermission = true + + LockManager.add(channel, temp) + channel.manager.putPermissionOverride(temp, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + + toAction.targetMemberID = temp.idLong + name = "%s %s".format(context.i18n("arguments.member"), temp.user.asMention) + } + is TextChannel -> { + if (temp.getPermissionOverride(context.guild.publicRole)?.denied?.contains(Permission.MESSAGE_WRITE)!!) toAction.oldPermission = false + if (temp.getPermissionOverride(context.guild.publicRole)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) toAction.oldPermission = true + + LockManager.add(temp) + temp.manager.putPermissionOverride(context.guild.publicRole, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + + toAction.targetChannelID = temp.idLong + } + } + } catch (e: PermissionException) { + context.uiMessaging.sendBotDiscordPermError(e.permission) + return + } + + ScheduledActionManager.registerScheduledAction(ScheduledAction( + ActionType.UNLOCK, + toAction, + context.guild.idLong, + context.channel.idLong, + context.member.idLong, + Instant.now(), + longDuration + )) + + + val textDuration = FormatUtils.formatTime(longDuration, context.locale, true).replace("(0[hm])".toRegex(), "") + + " (" + context.i18n("words.until") + " " + FormatUtils.formatDateTime(OffsetDateTime.now().plus(longDuration, ChronoUnit.SECONDS), context.locale) + ")" + context.typedMessaging.replySuccess(if (temp is TextChannel) context.i18n("commands.templock.text_success", temp.name, textDuration) else name?.let { context.i18n("commands.templock.success", channel, it, textDuration) }) + } + + + override fun command(): String { + return "templock" + } + + override fun permission(): CascadePermission? { + return CascadePermission.of("templock", false, Permission.MANAGE_CHANNEL) + } + + override fun module(): Module { + return Module.MODERATION + } + +} \ No newline at end of file diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt index dc8a7a5f5..58c768020 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt @@ -5,19 +5,20 @@ import net.dv8tion.jda.api.entities.ISnowflake import net.dv8tion.jda.api.entities.Member import net.dv8tion.jda.api.entities.Role import net.dv8tion.jda.api.entities.TextChannel +import net.dv8tion.jda.api.exceptions.PermissionException import org.cascadebot.cascadebot.commandmeta.CommandContext import org.cascadebot.cascadebot.commandmeta.MainCommand import org.cascadebot.cascadebot.commandmeta.Module +import org.cascadebot.cascadebot.data.managers.LockManager import org.cascadebot.cascadebot.permissions.CascadePermission import org.cascadebot.cascadebot.utils.DiscordUtils -import java.util.* class UnlockCommand : MainCommand() { override fun onCommand(sender: Member, context: CommandContext) { var channel: TextChannel = context.channel if (context.args.size == 2) { channel = DiscordUtils.getTextChannel(context.guild, context.getArg(1)) - ?: return context.reply("Invalid channel") + ?: return context.typedMessaging.replyDanger(context.i18n("responses.cannot_find_channel_matching", context.getArg(1))) } @@ -28,21 +29,25 @@ class UnlockCommand : MainCommand() { } else { context.channel } + var name: String? = null - when (temp) { - is Role -> { - //channel.manager.putPermissionOverride(temp, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() - name = temp.name - } - is Member -> { - //channel.manager.putPermissionOverride(temp, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() - name = temp.effectiveName + try { + when (temp) { + is Role -> { + name = "%s %s".format(context.i18n("arguments.role"), temp.asMention) + LockManager.unlock(context.guild, channel, temp) + } + is Member -> { + name = "%s %s".format(context.i18n("arguments.member"), temp.asMention) + LockManager.unlock(context.guild, channel, temp) + } + is TextChannel -> LockManager.unlock(context.guild, temp, context.guild.publicRole) } - ; - //is TextChannel -> temp.manager.putPermissionOverride(context.guild.publicRole, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() - // ^ SET TO THE OLD PERMISSION BEFORE SOMEONE LOCKED THE CHANNEL FOR THE USER/ROLE + } catch (e: PermissionException) { + context.uiMessaging.sendBotDiscordPermError(e.permission) + return } - context.typedMessaging.replySuccess(if (temp is TextChannel) "%s unlocked".format(temp.name) else "Channel unlocked for %s".format(name)) + context.typedMessaging.replySuccess(if (temp is TextChannel) context.i18n("commands.unlock.text_success", temp.name) else name?.let { context.i18n("commands.unlock.success", channel.name, it) }) } override fun command(): String { diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt new file mode 100644 index 000000000..fb91dccf8 --- /dev/null +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt @@ -0,0 +1,45 @@ +package org.cascadebot.cascadebot.data.managers + + +import net.dv8tion.jda.api.Permission +import net.dv8tion.jda.api.entities.* +import java.util.* + +object LockManager { + + // perm values: 0 = null/not specified, 1 = false, 2 = true + fun add(channel: TextChannel, target: Role) { + var perm = 0 + if (channel.getPermissionOverride(target)?.denied?.contains(Permission.MESSAGE_WRITE)!!) perm = 1 + if (channel.getPermissionOverride(target)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) perm = 2 + GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id]?.put(target.id, perm) + } + + fun add(channel: TextChannel) { + var perm = 0 + if (channel.getPermissionOverride(channel.guild.publicRole)?.denied?.contains(Permission.MESSAGE_WRITE)!!) perm = 1 + if (channel.getPermissionOverride(channel.guild.publicRole)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) perm = 2 + GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id]?.put(channel.guild.publicRole.id, perm) + } + + fun add(channel: TextChannel, target: Member) { + var perm = 0 + if (channel.getPermissionOverride(target)?.denied?.contains(Permission.MESSAGE_WRITE)!!) perm = 1 + if (channel.getPermissionOverride(target)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) perm = 2 + GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id]?.put(target.id, perm) + + } + + fun unlock(guild: Guild, channel: TextChannel, target: ISnowflake) { + val state = GuildDataManager.getGuildData(guild.idLong).lockedChannels[channel.id]?.get(target.id) + val empty = EnumSet.noneOf(net.dv8tion.jda.api.Permission::class.java) + val perm = EnumSet.of(Permission.MESSAGE_WRITE) + + channel.getPermissionOverride(target as IPermissionHolder)?.manager + ?.setAllow(if (state == 2) perm else empty) + ?.setDeny(if (state == 1) perm else empty) + ?.clear(if (state == 0) perm else empty) + ?.queue { GuildDataManager.getGuildData(guild.idLong).lockedChannels[channel.idLong.toString()]?.remove(target.idLong.toString()) } + } + +} diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt index e7e0d81ca..477a0bab7 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt @@ -42,6 +42,8 @@ class GuildData(@field:Id val guildId: Long) { val music = GuildSettingsMusic() //endregion + var lockedChannels: MutableMap> = mutableMapOf() + //region Transient fields @Transient val buttonsCache = ButtonsCache(5) diff --git a/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ActionType.kt b/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ActionType.kt index 05efdcba1..8f5015b34 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ActionType.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ActionType.kt @@ -1,7 +1,10 @@ package org.cascadebot.cascadebot.scheduler import net.dv8tion.jda.api.MessageBuilder +import net.dv8tion.jda.api.Permission import net.dv8tion.jda.api.entities.IMentionable +import net.dv8tion.jda.api.entities.IPermissionHolder +import net.dv8tion.jda.api.entities.ISnowflake import net.dv8tion.jda.api.exceptions.PermissionException import org.cascadebot.cascadebot.data.language.Language import org.cascadebot.cascadebot.data.language.Language.i18n @@ -14,9 +17,11 @@ import org.cascadebot.cascadebot.utils.toCapitalized import java.time.Duration import java.time.Instant import java.time.ZoneOffset +import java.util.* import kotlin.reflect.KClass import kotlin.reflect.full.isSubclassOf + enum class ActionType(val expectedClass: KClass<*>, val dataConsumer: (ScheduledAction) -> Unit) { REMINDER(ScheduledAction.ReminderActionData::class, ::reminderAction), UNMUTE(ScheduledAction.ModerationActionData::class, { action -> @@ -25,7 +30,8 @@ enum class ActionType(val expectedClass: KClass<*>, val dataConsumer: (Scheduled val member = guild.getMemberById(action.data.targetId) if (member != null) { guild.removeRoleFromMember(member, guild.getMutedRole()).apply { - val userName = guild.getMemberById(action.data.targetId)?.user?.asTag ?: Language.getGuildLocale(guild.idLong).i18n("words.unknown").toCapitalized() + val userName = guild.getMemberById(action.data.targetId)?.user?.asTag + ?: Language.getGuildLocale(guild.idLong).i18n("words.unknown").toCapitalized() reason(Language.getGuildLocale(guild.idLong).i18n("mod_actions.temp_mute.unmute_reason", userName)) queue(null) { action.channel?.let channelLet@{ channel -> @@ -73,6 +79,39 @@ enum class ActionType(val expectedClass: KClass<*>, val dataConsumer: (Scheduled } }) } + } + }), + UNLOCK(ScheduledAction.LockActionData::class, { action -> + if (action.data is ScheduledAction.LockActionData) { + action.guild?.let { guild -> + var targetChannel = action.channel?.id?.let { guild.getGuildChannelById(it) } + if (action.data.targetChannelID != 0L) { + targetChannel = guild.getGuildChannelById(action.data.targetChannelID) + } + val target: ISnowflake? = + guild.getRoleById(action.data.targetRoleID) + ?: guild.getMemberById(action.data.targetMemberID) + ?: guild.publicRole + + val empty = EnumSet.noneOf(Permission::class.java) + val perm = EnumSet.of(Permission.MESSAGE_WRITE) + + targetChannel?.getPermissionOverride(target as IPermissionHolder)?.manager + ?.setAllow(if (action.data.oldPermission.toString() == "true") perm else empty) + ?.setDeny(if (action.data.oldPermission.toString() == "false") perm else empty) + ?.clear(if (action.data.oldPermission.toString() == "null") perm else empty) + // TODO: There's probably a better way to deal with nullable booleans... do it + ?.queue(null, { + if (it is PermissionException) { + action.channel?.let { channel -> Messaging.sendMessage(MessageType.DANGER, channel, i18n(action.guildId, "responses.no_discord_perm_bot", it.permission.name)) } + } else { + action.channel?.let { channel -> Messaging.sendExceptionMessage(channel, "Couldn't unlock %s".format(targetChannel), it) } + } + }) + + } + + } }); @@ -91,11 +130,11 @@ private fun reminderAction(action: ScheduledAction) { action.user?.openPrivateChannel()?.queue { channel -> channel.sendMessage(MessageBuilder() .setEmbed( - embed(MessageType.INFO) { - description = (warningText?.let { "$it\n\n" } ?: "") + - Language.i18n(action.guildId, "scheduled_actions.reminder_text") + - "\n```\n${action.data.reminder}\n```" - }.build() + embed(MessageType.INFO) { + description = (warningText?.let { "$it\n\n" } ?: "") + + Language.i18n(action.guildId, "scheduled_actions.reminder_text") + + "\n```\n${action.data.reminder}\n```" + }.build() ) .build() ).queue(null) { diff --git a/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ScheduledAction.kt b/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ScheduledAction.kt index 39ec5310e..3fe8fcaf0 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ScheduledAction.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ScheduledAction.kt @@ -84,4 +84,10 @@ data class ScheduledAction( private constructor() : this(0L, 0) } + class LockActionData(var targetChannelID: Long, var oldPermission: Boolean?, var targetMemberID: Long = 0, var targetRoleID: Long = 0) : ActionData { + // Mongo Constructor + @Suppress("unused") + private constructor() : this(0L, true, 0L, 0L) + } + } diff --git a/src/main/resources/arguments.json b/src/main/resources/arguments.json index 0b46254a1..cf8b84dbc 100644 --- a/src/main/resources/arguments.json +++ b/src/main/resources/arguments.json @@ -316,11 +316,65 @@ "_type": "optional" } }, + "lock": { + "channel*": { + "_type": "optional" + }, + "role*": { + "_type": "optional", + "channel*": { + "_type": "optional" + } + }, + "member*": { + "_type": "optional", + "channel*": { + "_type": "optional" + } + } + }, + "templock*" : { + "duration" : { + "_type" : "required", + "channel" : { + "_type" : "optional" + }, + "role*" : { + "_type" : "optional", + "channel" : { + "_type" : "optional" + } + }, + "member*" : { + "_type" : "optional", + "channel" : { + "_type" : "optional" + } + } + } + }, "loop*": { "mode": { "_type": "optional" } }, + "unlock": { + "channel*": { + "_type": "optional" + }, + "role*": { + "_type": "optional", + "channel*": { + "_type": "optional" + } + }, + "member*": { + "_type": "optional", + "channel*": { + "_type": "optional" + } + } + }, "play*": { "url": { "_type": "required", diff --git a/src/main/resources/lang/en-GB.json b/src/main/resources/lang/en-GB.json index 51ac1d835..c15eebd26 100644 --- a/src/main/resources/lang/en-GB.json +++ b/src/main/resources/lang/en-GB.json @@ -105,16 +105,36 @@ "description": "Sets the slowmode of a channel", "time_exceeded": "Maximum time for slowmode of channels is 6 hours", "success": "Slowmode set to {0} in {1}", - "reset" : { - "command" : "reset", + "reset": { + "command": "reset", "description": "Resets the slowmode to off", - "reset_success" : "Slowmode reset in {0}" + "reset_success": "Slowmode reset in {0}" } }, - "tempslowmode":{ - "command" : "tempslowmode", - "description" : "Sets the slowmode of a channel temporarily", - "success" : "Slowmode set to {0} in {1}\nThis will be reset in {2}" + "tempslowmode": { + "command": "tempslowmode", + "description": "Sets the slowmode of a channel temporarily", + "success": "Slowmode set to {0} in {1}\nThis will be reset in {2}" + }, + "lock": { + "command": "lock", + "description": "Locks a channel for a member, role or everyone", + "text_success": "Channel `{0}` locked", + "success": "Channel `{0}` has been locked for {1}", + "invalid_argument": "Could not find a channel, role or member matching `{0}`" + }, + "templock": { + "command": "templock", + "descripton": "Locks a channel for a member, role or everyone for a given amount of time", + "text_success": "Channel `{0}` locked\nThis will be reset in {1}", + "success": "Channel `{0}` has been locked for {1}\nThis will be reset in {2}" + }, + "unlock": { + "command": "unlock", + "description": "Unlocks a channel for a member, role or everyone", + "text_success" : "Channel `{0}` unlocked", + "success" : "Channel `{0}` has been unlocked for {1}", + "fail" : "Channel `{0}` is not locked for {1}" }, "userinfo": { "command": "userinfo", @@ -1612,7 +1632,7 @@ "force": "force", "scope": "scope", "url": "url", - "reset" : "reset", + "reset": "reset", "channel": "channel", "prefix": "prefix", "command": "command", From 4318a5a028819d6be773d05a29c6475ebae49616 Mon Sep 17 00:00:00 2001 From: Ikinon <36565735+Ikinon@users.noreply.github.com> Date: Sat, 5 Sep 2020 17:54:03 +0100 Subject: [PATCH 04/16] make unlock work --- .../commands/moderation/UnlockCommand.kt | 4 ++ .../cascadebot/data/managers/LockManager.kt | 40 ++++++++++--------- src/main/resources/lang/en-GB.json | 2 +- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt index 58c768020..0352aaf7d 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt @@ -1,5 +1,6 @@ package org.cascadebot.cascadebot.commands.moderation +import javassist.NotFoundException import net.dv8tion.jda.api.Permission import net.dv8tion.jda.api.entities.ISnowflake import net.dv8tion.jda.api.entities.Member @@ -46,6 +47,9 @@ class UnlockCommand : MainCommand() { } catch (e: PermissionException) { context.uiMessaging.sendBotDiscordPermError(e.permission) return + } catch (e: NotFoundException) { + context.typedMessaging.replyWarning(context.i18n("commands.unlock.fail", if (temp is TextChannel) context.guild.publicRole.asMention else name!!)) + return } context.typedMessaging.replySuccess(if (temp is TextChannel) context.i18n("commands.unlock.text_success", temp.name) else name?.let { context.i18n("commands.unlock.success", channel.name, it) }) } diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt index fb91dccf8..ddb500f90 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt @@ -1,37 +1,39 @@ package org.cascadebot.cascadebot.data.managers +import javassist.NotFoundException import net.dv8tion.jda.api.Permission -import net.dv8tion.jda.api.entities.* +import net.dv8tion.jda.api.entities.Guild +import net.dv8tion.jda.api.entities.IPermissionHolder +import net.dv8tion.jda.api.entities.ISnowflake +import net.dv8tion.jda.api.entities.TextChannel import java.util.* object LockManager { - // perm values: 0 = null/not specified, 1 = false, 2 = true - fun add(channel: TextChannel, target: Role) { + private fun getPerm(channel: TextChannel, target: ISnowflake): Int { var perm = 0 - if (channel.getPermissionOverride(target)?.denied?.contains(Permission.MESSAGE_WRITE)!!) perm = 1 - if (channel.getPermissionOverride(target)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) perm = 2 - GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id]?.put(target.id, perm) + try { + if (channel.getPermissionOverride(target as IPermissionHolder)?.denied?.contains(Permission.MESSAGE_WRITE)!!) perm = 1 + if (channel.getPermissionOverride(target)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) perm = 2 + } catch (e: NullPointerException) { + null + } + return perm } - fun add(channel: TextChannel) { - var perm = 0 - if (channel.getPermissionOverride(channel.guild.publicRole)?.denied?.contains(Permission.MESSAGE_WRITE)!!) perm = 1 - if (channel.getPermissionOverride(channel.guild.publicRole)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) perm = 2 - GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id]?.put(channel.guild.publicRole.id, perm) + // perm values: 0 = null/not specified, 1 = false, 2 = true + fun add(channel: TextChannel, target: ISnowflake) { + GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id] = mutableMapOf(Pair(target.id, getPerm(channel, target))) } - fun add(channel: TextChannel, target: Member) { - var perm = 0 - if (channel.getPermissionOverride(target)?.denied?.contains(Permission.MESSAGE_WRITE)!!) perm = 1 - if (channel.getPermissionOverride(target)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) perm = 2 - GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id]?.put(target.id, perm) - + fun add(channel: TextChannel) { + GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id] = mutableMapOf(Pair(channel.guild.publicRole.id, getPerm(channel, channel.guild.publicRole))) } - + fun unlock(guild: Guild, channel: TextChannel, target: ISnowflake) { - val state = GuildDataManager.getGuildData(guild.idLong).lockedChannels[channel.id]?.get(target.id) + val state = GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id]?.get(target.id) + ?: throw NotFoundException("") val empty = EnumSet.noneOf(net.dv8tion.jda.api.Permission::class.java) val perm = EnumSet.of(Permission.MESSAGE_WRITE) diff --git a/src/main/resources/lang/en-GB.json b/src/main/resources/lang/en-GB.json index c15eebd26..1ef1e7e40 100644 --- a/src/main/resources/lang/en-GB.json +++ b/src/main/resources/lang/en-GB.json @@ -134,7 +134,7 @@ "description": "Unlocks a channel for a member, role or everyone", "text_success" : "Channel `{0}` unlocked", "success" : "Channel `{0}` has been unlocked for {1}", - "fail" : "Channel `{0}` is not locked for {1}" + "fail" : "Channel is not locked for {0}" }, "userinfo": { "command": "userinfo", From bac5ecb8840d5eee9827f1bd101194763f535b41 Mon Sep 17 00:00:00 2001 From: Ikinon <36565735+Ikinon@users.noreply.github.com> Date: Tue, 8 Sep 2020 19:01:31 +0100 Subject: [PATCH 05/16] lock changes Allow multiple channels to be locked templock adds to the list of locked channls as lock lock channels in lockManager --- .../commands/moderation/LockCommand.kt | 10 ++-- .../commands/moderation/TempLockCommand.kt | 25 ++++----- .../cascadebot/data/managers/LockManager.kt | 53 +++++++++++++------ .../cascadebot/data/objects/GuildData.kt | 3 +- .../cascadebot/scheduler/ActionType.kt | 20 ++----- .../cascadebot/scheduler/ScheduledAction.kt | 4 +- 6 files changed, 56 insertions(+), 59 deletions(-) diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt index 2aeed1c88..d47167b91 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt @@ -12,7 +12,6 @@ import org.cascadebot.cascadebot.commandmeta.Module import org.cascadebot.cascadebot.data.managers.LockManager import org.cascadebot.cascadebot.permissions.CascadePermission import org.cascadebot.cascadebot.utils.DiscordUtils -import java.util.* class LockCommand : MainCommand() { override fun onCommand(sender: Member, context: CommandContext) { @@ -36,18 +35,15 @@ class LockCommand : MainCommand() { try { when (temp) { is Role -> { - LockManager.add(channel, temp) - channel.manager.putPermissionOverride(temp, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + LockManager.lock(channel, temp) name = "%s %s".format(context.i18n("arguments.role"), temp.asMention) } is Member -> { - LockManager.add(channel, temp) - channel.manager.putPermissionOverride(temp, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + LockManager.lock(channel, temp) name = "%s %s".format(context.i18n("arguments.member"), temp.asMention) } is TextChannel -> { - LockManager.add(temp) - temp.manager.putPermissionOverride(context.guild.publicRole, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + LockManager.lock(temp, context.guild.publicRole) } } } catch (e: PermissionException) { diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt index 0bf3b2614..00dbc186c 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt @@ -20,7 +20,6 @@ import org.cascadebot.cascadebot.utils.ParserUtils import java.time.Instant import java.time.OffsetDateTime import java.time.temporal.ChronoUnit -import java.util.* class TempLockCommand : MainCommand() { override fun onCommand(sender: Member, context: CommandContext) { @@ -55,37 +54,31 @@ class TempLockCommand : MainCommand() { context.channel } - val toAction = ScheduledAction.LockActionData(channel.idLong, null, 0, 0) + val toAction = ScheduledAction.LockActionData(channel.idLong, 0, 0, 0) var name: String? = null try { when (temp) { is Role -> { - if (channel.getPermissionOverride(temp)?.denied?.contains(Permission.MESSAGE_WRITE)!!) toAction.oldPermission = false - if (channel.getPermissionOverride(temp)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) toAction.oldPermission = true + toAction.oldPermission = LockManager.getPerm(channel, temp)[0] - LockManager.add(channel, temp) - channel.manager.putPermissionOverride(temp, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + LockManager.lock(channel, temp) toAction.targetRoleID = temp.idLong name = "%s %s".format(context.i18n("arguments.role"), temp.asMention) } is Member -> { - if (channel.getPermissionOverride(temp)?.denied?.contains(Permission.MESSAGE_WRITE)!!) toAction.oldPermission = false - if (channel.getPermissionOverride(temp)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) toAction.oldPermission = true + toAction.oldPermission = LockManager.getPerm(channel, temp)[0] - LockManager.add(channel, temp) - channel.manager.putPermissionOverride(temp, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + LockManager.lock(channel, temp) toAction.targetMemberID = temp.idLong name = "%s %s".format(context.i18n("arguments.member"), temp.user.asMention) } is TextChannel -> { - if (temp.getPermissionOverride(context.guild.publicRole)?.denied?.contains(Permission.MESSAGE_WRITE)!!) toAction.oldPermission = false - if (temp.getPermissionOverride(context.guild.publicRole)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) toAction.oldPermission = true + toAction.oldPermission = LockManager.getPerm(temp, context.guild.publicRole)[0] - LockManager.add(temp) - temp.manager.putPermissionOverride(context.guild.publicRole, null, EnumSet.of(Permission.MESSAGE_WRITE)).queue() + LockManager.lock(temp, context.guild.publicRole) toAction.targetChannelID = temp.idLong } @@ -107,8 +100,8 @@ class TempLockCommand : MainCommand() { val textDuration = FormatUtils.formatTime(longDuration, context.locale, true).replace("(0[hm])".toRegex(), "") + - " (" + context.i18n("words.until") + " " + FormatUtils.formatDateTime(OffsetDateTime.now().plus(longDuration, ChronoUnit.SECONDS), context.locale) + ")" - context.typedMessaging.replySuccess(if (temp is TextChannel) context.i18n("commands.templock.text_success", temp.name, textDuration) else name?.let { context.i18n("commands.templock.success", channel, it, textDuration) }) + " (" + context.i18n("words.until") + " " + FormatUtils.formatDateTime(OffsetDateTime.now().plus(longDuration, ChronoUnit.MILLIS), context.locale) + ")" + context.typedMessaging.replySuccess(if (temp is TextChannel) context.i18n("commands.templock.text_success", temp.name, textDuration) else name?.let { context.i18n("commands.templock.success", channel.name, it, textDuration) }) } diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt index ddb500f90..7d396a377 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt @@ -10,38 +10,57 @@ import net.dv8tion.jda.api.entities.TextChannel import java.util.* object LockManager { + // perm values: 0 = null/not specified, 1 = false, 2 = true - private fun getPerm(channel: TextChannel, target: ISnowflake): Int { - var perm = 0 + fun getPerm(channel: TextChannel, target: ISnowflake): List { + // [target, selfMember] + val perm = mutableListOf(0, 0) try { - if (channel.getPermissionOverride(target as IPermissionHolder)?.denied?.contains(Permission.MESSAGE_WRITE)!!) perm = 1 - if (channel.getPermissionOverride(target)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) perm = 2 + if (channel.getPermissionOverride(target as IPermissionHolder)?.denied?.contains(Permission.MESSAGE_WRITE)!!) perm[0] = 1 + if (channel.getPermissionOverride(target)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) perm[0] = 2 + if (channel.getPermissionOverride(channel.guild.selfMember)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) perm[1] = 1 + if (channel.getPermissionOverride(channel.guild.selfMember)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) perm[0] = 2 } catch (e: NullPointerException) { null } return perm } - // perm values: 0 = null/not specified, 1 = false, 2 = true - fun add(channel: TextChannel, target: ISnowflake) { - GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id] = mutableMapOf(Pair(target.id, getPerm(channel, target))) + private fun add(channel: TextChannel, target: ISnowflake) { + if (GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id] == null) { + (GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels.put(channel.id, mutableMapOf(Pair(target.id, getPerm(channel, target))))) + } else { + GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id]!![target.id] = getPerm(channel, target) + } } - fun add(channel: TextChannel) { - GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id] = mutableMapOf(Pair(channel.guild.publicRole.id, getPerm(channel, channel.guild.publicRole))) + + fun lock(channel: TextChannel, target: IPermissionHolder) { + add(channel, target) + channel.upsertPermissionOverride(channel.guild.selfMember).grant(Permission.MESSAGE_WRITE).queue() + channel.upsertPermissionOverride(target).deny(Permission.MESSAGE_WRITE).queue() } - - fun unlock(guild: Guild, channel: TextChannel, target: ISnowflake) { + + fun unlock(guild: Guild, channel: TextChannel, target: IPermissionHolder) { val state = GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id]?.get(target.id) ?: throw NotFoundException("") - val empty = EnumSet.noneOf(net.dv8tion.jda.api.Permission::class.java) + val empty = EnumSet.noneOf(Permission::class.java) val perm = EnumSet.of(Permission.MESSAGE_WRITE) - channel.getPermissionOverride(target as IPermissionHolder)?.manager - ?.setAllow(if (state == 2) perm else empty) - ?.setDeny(if (state == 1) perm else empty) - ?.clear(if (state == 0) perm else empty) - ?.queue { GuildDataManager.getGuildData(guild.idLong).lockedChannels[channel.idLong.toString()]?.remove(target.idLong.toString()) } + val selfPermission = channel.getPermissionOverride(guild.selfMember)?.manager + ?.grant(if (state[1] == 2) perm else empty) + ?.deny(if (state[1] == 1) perm else empty) + if (state[1] == 0) selfPermission?.clear(perm) + selfPermission?.queue { if (it.allowedRaw == 0L && it.deniedRaw == 0L) it.delete().queue() } + + val targetPermission = channel.getPermissionOverride(target)?.manager + if (state[0] == 2) targetPermission?.grant(perm) + if (state[0] == 1) targetPermission?.deny(perm) + if (state[0] == 0) targetPermission?.clear(perm) + targetPermission?.queue { + GuildDataManager.getGuildData(guild.idLong).lockedChannels[channel.idLong.toString()]?.remove(target.idLong.toString()) + if (it.allowedRaw == 0L && it.deniedRaw == 0L) it.delete().queue() + } } } diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt index 477a0bab7..28bb3d601 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt @@ -1,5 +1,6 @@ package org.cascadebot.cascadebot.data.objects +import com.google.common.collect.ImmutableList import com.google.common.collect.Sets import de.bild.codec.annotations.Id import de.bild.codec.annotations.Transient @@ -42,7 +43,7 @@ class GuildData(@field:Id val guildId: Long) { val music = GuildSettingsMusic() //endregion - var lockedChannels: MutableMap> = mutableMapOf() + var lockedChannels: MutableMap>> = mutableMapOf() //region Transient fields @Transient diff --git a/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ActionType.kt b/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ActionType.kt index 8f5015b34..93210b0b1 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ActionType.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ActionType.kt @@ -4,6 +4,8 @@ import net.dv8tion.jda.api.MessageBuilder import net.dv8tion.jda.api.Permission import net.dv8tion.jda.api.entities.IMentionable import net.dv8tion.jda.api.entities.IPermissionHolder +import org.cascadebot.cascadebot.data.managers.LockManager +import net.dv8tion.jda.api.entities.TextChannel import net.dv8tion.jda.api.entities.ISnowflake import net.dv8tion.jda.api.exceptions.PermissionException import org.cascadebot.cascadebot.data.language.Language @@ -88,26 +90,12 @@ enum class ActionType(val expectedClass: KClass<*>, val dataConsumer: (Scheduled if (action.data.targetChannelID != 0L) { targetChannel = guild.getGuildChannelById(action.data.targetChannelID) } - val target: ISnowflake? = + val target: ISnowflake = guild.getRoleById(action.data.targetRoleID) ?: guild.getMemberById(action.data.targetMemberID) ?: guild.publicRole - val empty = EnumSet.noneOf(Permission::class.java) - val perm = EnumSet.of(Permission.MESSAGE_WRITE) - - targetChannel?.getPermissionOverride(target as IPermissionHolder)?.manager - ?.setAllow(if (action.data.oldPermission.toString() == "true") perm else empty) - ?.setDeny(if (action.data.oldPermission.toString() == "false") perm else empty) - ?.clear(if (action.data.oldPermission.toString() == "null") perm else empty) - // TODO: There's probably a better way to deal with nullable booleans... do it - ?.queue(null, { - if (it is PermissionException) { - action.channel?.let { channel -> Messaging.sendMessage(MessageType.DANGER, channel, i18n(action.guildId, "responses.no_discord_perm_bot", it.permission.name)) } - } else { - action.channel?.let { channel -> Messaging.sendExceptionMessage(channel, "Couldn't unlock %s".format(targetChannel), it) } - } - }) + LockManager.unlock(guild, targetChannel as TextChannel, target as IPermissionHolder) } diff --git a/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ScheduledAction.kt b/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ScheduledAction.kt index 3fe8fcaf0..19f6468f0 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ScheduledAction.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ScheduledAction.kt @@ -84,10 +84,10 @@ data class ScheduledAction( private constructor() : this(0L, 0) } - class LockActionData(var targetChannelID: Long, var oldPermission: Boolean?, var targetMemberID: Long = 0, var targetRoleID: Long = 0) : ActionData { + class LockActionData(var targetChannelID: Long, var oldPermission: Int, var targetMemberID: Long = 0, var targetRoleID: Long = 0) : ActionData { // Mongo Constructor @Suppress("unused") - private constructor() : this(0L, true, 0L, 0L) + private constructor() : this(0L, 0, 0L, 0L) } } From 855801b91550895b8ffe747ce82e5e809292d790 Mon Sep 17 00:00:00 2001 From: William Oldham Date: Wed, 21 Oct 2020 23:23:15 +0100 Subject: [PATCH 06/16] Use more descriptive types and improve some logic? --- .../commands/moderation/LockCommand.kt | 17 ++-- .../commands/moderation/TempLockCommand.kt | 9 +- .../cascadebot/data/managers/LockManager.kt | 86 ++++++++++++------- .../cascadebot/data/objects/GuildData.kt | 6 +- .../cascadebot/scheduler/ScheduledAction.kt | 5 +- 5 files changed, 74 insertions(+), 49 deletions(-) diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt index d47167b91..af236ad49 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt @@ -22,7 +22,7 @@ class LockCommand : MainCommand() { } - val temp: ISnowflake? = if (context.args.isNotEmpty()) { + val target: ISnowflake? = if (context.args.isNotEmpty()) { DiscordUtils.getRole(context.getArg(0), context.guild) ?: DiscordUtils.getMember(context.guild, context.getArg(0)) ?: DiscordUtils.getTextChannel(context.guild, context.getArg(0)) @@ -33,17 +33,17 @@ class LockCommand : MainCommand() { var name: String? = null try { - when (temp) { + when (target) { is Role -> { - LockManager.lock(channel, temp) - name = "%s %s".format(context.i18n("arguments.role"), temp.asMention) + LockManager.lock(channel, target) + name = "%s %s".format(context.i18n("arguments.role"), target.asMention) } is Member -> { - LockManager.lock(channel, temp) - name = "%s %s".format(context.i18n("arguments.member"), temp.asMention) + LockManager.lock(channel, target) + name = "%s %s".format(context.i18n("arguments.member"), target.asMention) } is TextChannel -> { - LockManager.lock(temp, context.guild.publicRole) + LockManager.lock(target, context.guild.publicRole) } } } catch (e: PermissionException) { @@ -51,8 +51,7 @@ class LockCommand : MainCommand() { return } - - context.typedMessaging.replySuccess(if (temp is TextChannel) context.i18n("commands.lock.text_success", temp.name) else name?.let { context.i18n("commands.lock.success", channel.name, it) }) + context.typedMessaging.replySuccess(if (target is TextChannel) context.i18n("commands.lock.text_success", target.name) else name?.let { context.i18n("commands.lock.success", channel.name, it) }) } diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt index 00dbc186c..6b3e80519 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt @@ -10,6 +10,7 @@ import org.cascadebot.cascadebot.commandmeta.CommandContext import org.cascadebot.cascadebot.commandmeta.MainCommand import org.cascadebot.cascadebot.commandmeta.Module import org.cascadebot.cascadebot.data.managers.LockManager +import org.cascadebot.cascadebot.data.managers.LockPermission import org.cascadebot.cascadebot.data.managers.ScheduledActionManager import org.cascadebot.cascadebot.permissions.CascadePermission import org.cascadebot.cascadebot.scheduler.ActionType @@ -54,13 +55,13 @@ class TempLockCommand : MainCommand() { context.channel } - val toAction = ScheduledAction.LockActionData(channel.idLong, 0, 0, 0) + val toAction = ScheduledAction.LockActionData(channel.idLong, LockPermission.NEUTRAL, 0, 0) var name: String? = null try { when (temp) { is Role -> { - toAction.oldPermission = LockManager.getPerm(channel, temp)[0] + toAction.oldPermission = LockManager.getPerm(channel, temp).left LockManager.lock(channel, temp) @@ -68,7 +69,7 @@ class TempLockCommand : MainCommand() { name = "%s %s".format(context.i18n("arguments.role"), temp.asMention) } is Member -> { - toAction.oldPermission = LockManager.getPerm(channel, temp)[0] + toAction.oldPermission = LockManager.getPerm(channel, temp).left LockManager.lock(channel, temp) @@ -76,7 +77,7 @@ class TempLockCommand : MainCommand() { name = "%s %s".format(context.i18n("arguments.member"), temp.user.asMention) } is TextChannel -> { - toAction.oldPermission = LockManager.getPerm(temp, context.guild.publicRole)[0] + toAction.oldPermission = LockManager.getPerm(temp, context.guild.publicRole).left LockManager.lock(temp, context.guild.publicRole) diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt index 7d396a377..48e3778b8 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt @@ -1,65 +1,85 @@ package org.cascadebot.cascadebot.data.managers -import javassist.NotFoundException import net.dv8tion.jda.api.Permission import net.dv8tion.jda.api.entities.Guild import net.dv8tion.jda.api.entities.IPermissionHolder -import net.dv8tion.jda.api.entities.ISnowflake import net.dv8tion.jda.api.entities.TextChannel -import java.util.* +import net.dv8tion.jda.api.requests.restaction.PermissionOverrideAction +import net.dv8tion.jda.internal.utils.tuple.MutablePair +import java.util.EnumSet + +enum class LockPermission { + ALLOW, + DENY, + NEUTRAL; + + fun apply(action: PermissionOverrideAction, perm: EnumSet) { + when (this) { + ALLOW -> action.grant(perm) + DENY -> action.deny(perm) + NEUTRAL -> action.clear(perm) + } + } + +} object LockManager { - // perm values: 0 = null/not specified, 1 = false, 2 = true - fun getPerm(channel: TextChannel, target: ISnowflake): List { + fun getPerm(channel: TextChannel, target: IPermissionHolder): MutablePair { // [target, selfMember] - val perm = mutableListOf(0, 0) - try { - if (channel.getPermissionOverride(target as IPermissionHolder)?.denied?.contains(Permission.MESSAGE_WRITE)!!) perm[0] = 1 - if (channel.getPermissionOverride(target)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) perm[0] = 2 - if (channel.getPermissionOverride(channel.guild.selfMember)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) perm[1] = 1 - if (channel.getPermissionOverride(channel.guild.selfMember)?.allowed?.contains(Permission.MESSAGE_WRITE)!!) perm[0] = 2 - } catch (e: NullPointerException) { - null + val perm = MutablePair(LockPermission.NEUTRAL, LockPermission.NEUTRAL) + + val targetOverride = channel.getPermissionOverride(target) + if (targetOverride != null) { + if (targetOverride.allowed.contains(Permission.MESSAGE_WRITE)) perm.setLeft(LockPermission.ALLOW) + if (targetOverride.denied.contains(Permission.MESSAGE_WRITE)) perm.setLeft(LockPermission.DENY) + } + + val selfMemberOverride = channel.getPermissionOverride(channel.guild.selfMember) + if (selfMemberOverride != null) { + if (selfMemberOverride.allowed.contains(Permission.MESSAGE_WRITE)) perm.setRight(LockPermission.ALLOW) + if (selfMemberOverride.denied.contains(Permission.MESSAGE_WRITE)) perm.setRight(LockPermission.DENY) } return perm } - private fun add(channel: TextChannel, target: ISnowflake) { - if (GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id] == null) { - (GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels.put(channel.id, mutableMapOf(Pair(target.id, getPerm(channel, target))))) + private fun storePermissions(channel: TextChannel, target: IPermissionHolder) { + val lockedChannels = GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels + val mutableMap = lockedChannels[channel.id] + if (mutableMap == null) { + lockedChannels[channel.id] = mutableMapOf(Pair(target.id, getPerm(channel, target))) } else { - GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id]!![target.id] = getPerm(channel, target) + mutableMap[target.id] = getPerm(channel, target) } } fun lock(channel: TextChannel, target: IPermissionHolder) { - add(channel, target) + storePermissions(channel, target) channel.upsertPermissionOverride(channel.guild.selfMember).grant(Permission.MESSAGE_WRITE).queue() channel.upsertPermissionOverride(target).deny(Permission.MESSAGE_WRITE).queue() } fun unlock(guild: Guild, channel: TextChannel, target: IPermissionHolder) { val state = GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id]?.get(target.id) - ?: throw NotFoundException("") - val empty = EnumSet.noneOf(Permission::class.java) + // If there is no state to restore, we can't do anything! + ?: return val perm = EnumSet.of(Permission.MESSAGE_WRITE) - val selfPermission = channel.getPermissionOverride(guild.selfMember)?.manager - ?.grant(if (state[1] == 2) perm else empty) - ?.deny(if (state[1] == 1) perm else empty) - if (state[1] == 0) selfPermission?.clear(perm) - selfPermission?.queue { if (it.allowedRaw == 0L && it.deniedRaw == 0L) it.delete().queue() } - - val targetPermission = channel.getPermissionOverride(target)?.manager - if (state[0] == 2) targetPermission?.grant(perm) - if (state[0] == 1) targetPermission?.deny(perm) - if (state[0] == 0) targetPermission?.clear(perm) - targetPermission?.queue { - GuildDataManager.getGuildData(guild.idLong).lockedChannels[channel.idLong.toString()]?.remove(target.idLong.toString()) - if (it.allowedRaw == 0L && it.deniedRaw == 0L) it.delete().queue() + val selfPermissionAction = channel.getPermissionOverride(guild.selfMember)?.manager + if (selfPermissionAction != null) { + state.right.apply(selfPermissionAction, perm) + selfPermissionAction.queue { if (it.allowedRaw == 0L && it.deniedRaw == 0L) it.delete().queue() } + } + + val targetPermissionAction = channel.getPermissionOverride(target)?.manager + if (targetPermissionAction != null) { + state.left.apply(targetPermissionAction, perm) + targetPermissionAction.queue { + GuildDataManager.getGuildData(guild.idLong).lockedChannels[channel.idLong.toString()]?.remove(target.idLong.toString()) + if (it.allowedRaw == 0L && it.deniedRaw == 0L) it.delete().queue() + } } } diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt index 28bb3d601..e2f97ba21 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt @@ -6,8 +6,11 @@ import de.bild.codec.annotations.Id import de.bild.codec.annotations.Transient import net.dv8tion.jda.api.entities.Message import net.dv8tion.jda.api.entities.MessageChannel +import net.dv8tion.jda.internal.utils.tuple.MutablePair +import net.dv8tion.jda.internal.utils.tuple.Pair import org.cascadebot.cascadebot.CascadeBot import org.cascadebot.cascadebot.data.language.Locale +import org.cascadebot.cascadebot.data.managers.LockPermission import org.cascadebot.cascadebot.music.CascadeLavalinkPlayer import org.cascadebot.cascadebot.utils.buttons.ButtonGroup import org.cascadebot.cascadebot.utils.buttons.ButtonsCache @@ -43,7 +46,8 @@ class GuildData(@field:Id val guildId: Long) { val music = GuildSettingsMusic() //endregion - var lockedChannels: MutableMap>> = mutableMapOf() + // > + var lockedChannels: MutableMap>> = mutableMapOf() //region Transient fields @Transient diff --git a/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ScheduledAction.kt b/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ScheduledAction.kt index 19f6468f0..5476a177f 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ScheduledAction.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ScheduledAction.kt @@ -6,6 +6,7 @@ import net.dv8tion.jda.api.entities.TextChannel import net.dv8tion.jda.api.entities.User import org.bson.types.ObjectId import org.cascadebot.cascadebot.CascadeBot +import org.cascadebot.cascadebot.data.managers.LockPermission import org.cascadebot.cascadebot.data.managers.ScheduledActionManager import java.time.Instant import java.time.temporal.ChronoUnit @@ -84,10 +85,10 @@ data class ScheduledAction( private constructor() : this(0L, 0) } - class LockActionData(var targetChannelID: Long, var oldPermission: Int, var targetMemberID: Long = 0, var targetRoleID: Long = 0) : ActionData { + class LockActionData(var targetChannelID: Long, var oldPermission: LockPermission, var targetMemberID: Long = 0, var targetRoleID: Long = 0) : ActionData { // Mongo Constructor @Suppress("unused") - private constructor() : this(0L, 0, 0L, 0L) + private constructor() : this(0L, LockPermission.NEUTRAL, 0L, 0L) } } From 75da6b5a371de2d313275aeba235f5c1f6ec0356 Mon Sep 17 00:00:00 2001 From: William Oldham Date: Sun, 25 Oct 2020 13:41:43 +0000 Subject: [PATCH 07/16] Renamy stuff --- .../commands/moderation/TempLockCommand.kt | 4 ++-- .../cascadebot/data/managers/LockManager.kt | 23 +++++++++++-------- .../cascadebot/data/objects/GuildData.kt | 6 ++--- .../cascadebot/scheduler/ScheduledAction.kt | 6 ++--- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt index 6b3e80519..d5a2b5daf 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt @@ -10,7 +10,7 @@ import org.cascadebot.cascadebot.commandmeta.CommandContext import org.cascadebot.cascadebot.commandmeta.MainCommand import org.cascadebot.cascadebot.commandmeta.Module import org.cascadebot.cascadebot.data.managers.LockManager -import org.cascadebot.cascadebot.data.managers.LockPermission +import org.cascadebot.cascadebot.data.managers.Status import org.cascadebot.cascadebot.data.managers.ScheduledActionManager import org.cascadebot.cascadebot.permissions.CascadePermission import org.cascadebot.cascadebot.scheduler.ActionType @@ -55,7 +55,7 @@ class TempLockCommand : MainCommand() { context.channel } - val toAction = ScheduledAction.LockActionData(channel.idLong, LockPermission.NEUTRAL, 0, 0) + val toAction = ScheduledAction.LockActionData(channel.idLong, Status.NEUTRAL, 0, 0) var name: String? = null try { diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt index 48e3778b8..aa66c6d94 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt @@ -9,7 +9,7 @@ import net.dv8tion.jda.api.requests.restaction.PermissionOverrideAction import net.dv8tion.jda.internal.utils.tuple.MutablePair import java.util.EnumSet -enum class LockPermission { +enum class Status { ALLOW, DENY, NEUTRAL; @@ -26,20 +26,20 @@ enum class LockPermission { object LockManager { - fun getPerm(channel: TextChannel, target: IPermissionHolder): MutablePair { + fun getPerm(channel: TextChannel, target: IPermissionHolder): MutablePair { // [target, selfMember] - val perm = MutablePair(LockPermission.NEUTRAL, LockPermission.NEUTRAL) + val perm = MutablePair(Status.NEUTRAL, Status.NEUTRAL) val targetOverride = channel.getPermissionOverride(target) if (targetOverride != null) { - if (targetOverride.allowed.contains(Permission.MESSAGE_WRITE)) perm.setLeft(LockPermission.ALLOW) - if (targetOverride.denied.contains(Permission.MESSAGE_WRITE)) perm.setLeft(LockPermission.DENY) + if (targetOverride.allowed.contains(Permission.MESSAGE_WRITE)) perm.setLeft(Status.ALLOW) + if (targetOverride.denied.contains(Permission.MESSAGE_WRITE)) perm.setLeft(Status.DENY) } val selfMemberOverride = channel.getPermissionOverride(channel.guild.selfMember) if (selfMemberOverride != null) { - if (selfMemberOverride.allowed.contains(Permission.MESSAGE_WRITE)) perm.setRight(LockPermission.ALLOW) - if (selfMemberOverride.denied.contains(Permission.MESSAGE_WRITE)) perm.setRight(LockPermission.DENY) + if (selfMemberOverride.allowed.contains(Permission.MESSAGE_WRITE)) perm.setRight(Status.ALLOW) + if (selfMemberOverride.denied.contains(Permission.MESSAGE_WRITE)) perm.setRight(Status.DENY) } return perm } @@ -61,16 +61,19 @@ object LockManager { channel.upsertPermissionOverride(target).deny(Permission.MESSAGE_WRITE).queue() } - fun unlock(guild: Guild, channel: TextChannel, target: IPermissionHolder) { + fun unlock(guild: Guild, channel: TextChannel, target: IPermissionHolder) : Boolean { val state = GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id]?.get(target.id) // If there is no state to restore, we can't do anything! - ?: return + ?: return false val perm = EnumSet.of(Permission.MESSAGE_WRITE) + var changed = false; + val selfPermissionAction = channel.getPermissionOverride(guild.selfMember)?.manager if (selfPermissionAction != null) { state.right.apply(selfPermissionAction, perm) selfPermissionAction.queue { if (it.allowedRaw == 0L && it.deniedRaw == 0L) it.delete().queue() } + changed = true; } val targetPermissionAction = channel.getPermissionOverride(target)?.manager @@ -80,7 +83,9 @@ object LockManager { GuildDataManager.getGuildData(guild.idLong).lockedChannels[channel.idLong.toString()]?.remove(target.idLong.toString()) if (it.allowedRaw == 0L && it.deniedRaw == 0L) it.delete().queue() } + changed = true } + return changed } } diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt index e2f97ba21..34e9cfc6e 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt @@ -1,16 +1,14 @@ package org.cascadebot.cascadebot.data.objects -import com.google.common.collect.ImmutableList import com.google.common.collect.Sets import de.bild.codec.annotations.Id import de.bild.codec.annotations.Transient import net.dv8tion.jda.api.entities.Message import net.dv8tion.jda.api.entities.MessageChannel import net.dv8tion.jda.internal.utils.tuple.MutablePair -import net.dv8tion.jda.internal.utils.tuple.Pair import org.cascadebot.cascadebot.CascadeBot import org.cascadebot.cascadebot.data.language.Locale -import org.cascadebot.cascadebot.data.managers.LockPermission +import org.cascadebot.cascadebot.data.managers.Status import org.cascadebot.cascadebot.music.CascadeLavalinkPlayer import org.cascadebot.cascadebot.utils.buttons.ButtonGroup import org.cascadebot.cascadebot.utils.buttons.ButtonsCache @@ -47,7 +45,7 @@ class GuildData(@field:Id val guildId: Long) { //endregion // > - var lockedChannels: MutableMap>> = mutableMapOf() + var lockedChannels: MutableMap>> = mutableMapOf() //region Transient fields @Transient diff --git a/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ScheduledAction.kt b/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ScheduledAction.kt index 5476a177f..408964d53 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ScheduledAction.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ScheduledAction.kt @@ -6,7 +6,7 @@ import net.dv8tion.jda.api.entities.TextChannel import net.dv8tion.jda.api.entities.User import org.bson.types.ObjectId import org.cascadebot.cascadebot.CascadeBot -import org.cascadebot.cascadebot.data.managers.LockPermission +import org.cascadebot.cascadebot.data.managers.Status import org.cascadebot.cascadebot.data.managers.ScheduledActionManager import java.time.Instant import java.time.temporal.ChronoUnit @@ -85,10 +85,10 @@ data class ScheduledAction( private constructor() : this(0L, 0) } - class LockActionData(var targetChannelID: Long, var oldPermission: LockPermission, var targetMemberID: Long = 0, var targetRoleID: Long = 0) : ActionData { + class LockActionData(var targetChannelID: Long, var oldPermission: Status, var targetMemberID: Long = 0, var targetRoleID: Long = 0) : ActionData { // Mongo Constructor @Suppress("unused") - private constructor() : this(0L, LockPermission.NEUTRAL, 0L, 0L) + private constructor() : this(0L, Status.NEUTRAL, 0L, 0L) } } From 7db3b280aaad1aaf75949656900ae1e1cd566d27 Mon Sep 17 00:00:00 2001 From: William Oldham Date: Sun, 25 Oct 2020 16:15:21 +0000 Subject: [PATCH 08/16] Some changes --- .../commands/moderation/LockCommand.kt | 31 ++++++----- .../commands/moderation/TempLockCommand.kt | 40 ++++++-------- .../commands/moderation/UnlockCommand.kt | 40 +++++++------- .../cascadebot/messaging/Messaging.kt | 10 +++- src/main/resources/arguments.json | 54 ++++++------------- src/main/resources/lang/en-GB.json | 12 ++--- 6 files changed, 81 insertions(+), 106 deletions(-) diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt index af236ad49..1691d9b99 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt @@ -16,42 +16,41 @@ import org.cascadebot.cascadebot.utils.DiscordUtils class LockCommand : MainCommand() { override fun onCommand(sender: Member, context: CommandContext) { var channel: TextChannel = context.channel - if (context.args.size == 2) { - channel = DiscordUtils.getTextChannel(context.guild, context.getArg(1)) - ?: return context.typedMessaging.replyDanger(context.i18n("responses.cannot_find_channel_matching", context.getArg(1))) + if (context.args.isNotEmpty()) { + channel = DiscordUtils.getTextChannel(context.guild, context.getArg(0)) + ?: return context.typedMessaging.replyDanger(context.i18n("responses.cannot_find_channel_matching", context.getArg(0))) } - val target: ISnowflake? = if (context.args.isNotEmpty()) { - DiscordUtils.getRole(context.getArg(0), context.guild) - ?: DiscordUtils.getMember(context.guild, context.getArg(0)) - ?: DiscordUtils.getTextChannel(context.guild, context.getArg(0)) + val target: ISnowflake = if (context.args.size == 2) { + DiscordUtils.getRole(context.getArg(1), context.guild) + ?: DiscordUtils.getMember(context.guild, context.getArg(1)) + ?: DiscordUtils.getTextChannel(context.guild, context.getArg(1)) ?: return context.typedMessaging.replyDanger(context.i18n("commands.lock.invalid_argument", context.getArg(0))) } else { - context.channel + context.guild.publicRole } - var name: String? = null - try { + if (target is TextChannel) channel = target; + + val name: String = try { when (target) { is Role -> { LockManager.lock(channel, target) - name = "%s %s".format(context.i18n("arguments.role"), target.asMention) + "%s %s".format(context.i18n("arguments.role"), target.asMention) } is Member -> { LockManager.lock(channel, target) - name = "%s %s".format(context.i18n("arguments.member"), target.asMention) - } - is TextChannel -> { - LockManager.lock(target, context.guild.publicRole) + "%s %s".format(context.i18n("arguments.member"), target.asMention) } + else -> "" } } catch (e: PermissionException) { context.uiMessaging.sendBotDiscordPermError(e.permission) return } - context.typedMessaging.replySuccess(if (target is TextChannel) context.i18n("commands.lock.text_success", target.name) else name?.let { context.i18n("commands.lock.success", channel.name, it) }) + context.typedMessaging.replySuccess((context.i18n("commands.lock.success", channel.name, name))) } diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt index d5a2b5daf..4d7b6a045 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt @@ -36,21 +36,20 @@ class TempLockCommand : MainCommand() { } var channel: TextChannel = context.channel - if (context.args.size == 3) { - val tempChannel = DiscordUtils.getTextChannel(context.guild, context.getArg(2)) + if (context.args.size == 2) { + val tempChannel = DiscordUtils.getTextChannel(context.guild, context.getArg(1)) if (tempChannel != null) { channel = tempChannel } else { - context.typedMessaging.replyDanger(context.i18n("responses.cannot_find_channel_matching", context.getArg(2))) + context.typedMessaging.replyDanger(context.i18n("responses.cannot_find_channel_matching", context.getArg(1))) return } } - val temp: ISnowflake? = if (context.args.size > 1) { + val target: ISnowflake = if (context.args.size == 3) { DiscordUtils.getRole(context.getArg(1), context.guild) - ?: DiscordUtils.getMember(context.guild, context.getArg(1)) - ?: DiscordUtils.getTextChannel(context.guild, context.getArg(1)) - ?: return context.typedMessaging.replyDanger(context.i18n("commands.lock.invalid_argument", context.getArg(0))) + ?: DiscordUtils.getMember(context.guild, context.getArg(2)) + ?: return context.typedMessaging.replyDanger(context.i18n("commands.templock.invalid_argument", context.getArg(2))) } else { context.channel } @@ -59,29 +58,22 @@ class TempLockCommand : MainCommand() { var name: String? = null try { - when (temp) { + when (target) { is Role -> { - toAction.oldPermission = LockManager.getPerm(channel, temp).left + toAction.oldPermission = LockManager.getPerm(channel, target).left - LockManager.lock(channel, temp) + LockManager.lock(channel, target) - toAction.targetRoleID = temp.idLong - name = "%s %s".format(context.i18n("arguments.role"), temp.asMention) + toAction.targetRoleID = target.idLong + name = "%s %s".format(context.i18n("arguments.role"), target.asMention) } is Member -> { - toAction.oldPermission = LockManager.getPerm(channel, temp).left + toAction.oldPermission = LockManager.getPerm(channel, target).left - LockManager.lock(channel, temp) + LockManager.lock(channel, target) - toAction.targetMemberID = temp.idLong - name = "%s %s".format(context.i18n("arguments.member"), temp.user.asMention) - } - is TextChannel -> { - toAction.oldPermission = LockManager.getPerm(temp, context.guild.publicRole).left - - LockManager.lock(temp, context.guild.publicRole) - - toAction.targetChannelID = temp.idLong + toAction.targetMemberID = target.idLong + name = "%s %s".format(context.i18n("arguments.member"), target.user.asMention) } } } catch (e: PermissionException) { @@ -102,7 +94,7 @@ class TempLockCommand : MainCommand() { val textDuration = FormatUtils.formatTime(longDuration, context.locale, true).replace("(0[hm])".toRegex(), "") + " (" + context.i18n("words.until") + " " + FormatUtils.formatDateTime(OffsetDateTime.now().plus(longDuration, ChronoUnit.MILLIS), context.locale) + ")" - context.typedMessaging.replySuccess(if (temp is TextChannel) context.i18n("commands.templock.text_success", temp.name, textDuration) else name?.let { context.i18n("commands.templock.success", channel.name, it, textDuration) }) + context.typedMessaging.replySuccess(if (target is TextChannel) context.i18n("commands.templock.text_success", target.name, textDuration) else name?.let { context.i18n("commands.templock.success", channel.name, it, textDuration) }) } diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt index 0352aaf7d..c6274427b 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt @@ -17,41 +17,45 @@ import org.cascadebot.cascadebot.utils.DiscordUtils class UnlockCommand : MainCommand() { override fun onCommand(sender: Member, context: CommandContext) { var channel: TextChannel = context.channel - if (context.args.size == 2) { - channel = DiscordUtils.getTextChannel(context.guild, context.getArg(1)) - ?: return context.typedMessaging.replyDanger(context.i18n("responses.cannot_find_channel_matching", context.getArg(1))) + if (context.args.isNotEmpty()) { + channel = DiscordUtils.getTextChannel(context.guild, context.getArg(0)) + ?: return context.typedMessaging.replyDanger(context.i18n("responses.cannot_find_channel_matching", context.getArg(0))) } - val temp: ISnowflake? = if (context.args.isNotEmpty()) { - DiscordUtils.getRole(context.getArg(0), context.guild) - ?: DiscordUtils.getMember(context.guild, context.getArg(0)) - ?: DiscordUtils.getTextChannel(context.guild, context.getArg(0)) + val target: ISnowflake = if (context.args.size == 2) { + DiscordUtils.getRole(context.getArg(1), context.guild) + ?: DiscordUtils.getMember(context.guild, context.getArg(1)) + ?: return context.typedMessaging.replyDanger(context.i18n("commands.unlock.invalid_argument", context.getArg(1))) } else { - context.channel + context.guild.publicRole } - var name: String? = null - try { - when (temp) { + var name = "" + val completed = try { + when (target) { is Role -> { - name = "%s %s".format(context.i18n("arguments.role"), temp.asMention) - LockManager.unlock(context.guild, channel, temp) + name = target.asMention + LockManager.unlock(context.guild, channel, target) } is Member -> { - name = "%s %s".format(context.i18n("arguments.member"), temp.asMention) - LockManager.unlock(context.guild, channel, temp) + name = "%s %s".format(context.i18n("arguments.member"), target.asMention) + LockManager.unlock(context.guild, channel, target) } - is TextChannel -> LockManager.unlock(context.guild, temp, context.guild.publicRole) + else -> false } } catch (e: PermissionException) { context.uiMessaging.sendBotDiscordPermError(e.permission) return } catch (e: NotFoundException) { - context.typedMessaging.replyWarning(context.i18n("commands.unlock.fail", if (temp is TextChannel) context.guild.publicRole.asMention else name!!)) + context.typedMessaging.replyWarning(context.i18n("commands.unlock.fail", if (target is TextChannel) context.guild.publicRole.asMention else name!!)) return } - context.typedMessaging.replySuccess(if (temp is TextChannel) context.i18n("commands.unlock.text_success", temp.name) else name?.let { context.i18n("commands.unlock.success", channel.name, it) }) + if (completed) { + context.typedMessaging.replySuccess(context.i18n("commands.unlock.success", channel.name, name)) + } else { + context.typedMessaging.replyDanger(context.i18n("commands.unlock.failure", channel.name, name)) + } } override fun command(): String { diff --git a/src/main/kotlin/org/cascadebot/cascadebot/messaging/Messaging.kt b/src/main/kotlin/org/cascadebot/cascadebot/messaging/Messaging.kt index 163488c5c..72affaee2 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/messaging/Messaging.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/messaging/Messaging.kt @@ -39,7 +39,10 @@ object Messaging { return if (embed) { channel.sendMessage(MessagingObjects.getMessageTypeEmbedBuilder(type).setDescription(message).build()).submit() } else { - channel.sendMessage(MessagingObjects.getMessageTypeMessageBuilder(type).append(message).build()).submit() + channel.sendMessage(MessagingObjects.getMessageTypeMessageBuilder(type) + .append(message) + .denyMentions(Message.MentionType.EVERYONE, Message.MentionType.HERE, Message.MentionType.ROLE).build()) + .submit() } } @@ -49,7 +52,10 @@ object Messaging { return if (embed) { channel.sendMessage(builder.setColor(type.color).build()).submit() } else { - channel.sendMessage(type.emoji + " " + FormatUtils.formatEmbed(builder.build())).submit() + channel.sendMessage(MessageBuilder() + .denyMentions(Message.MentionType.EVERYONE, Message.MentionType.HERE, Message.MentionType.ROLE) + .setContent(type.emoji + " " + FormatUtils.formatEmbed(builder.build())) + .build()).submit() } } diff --git a/src/main/resources/arguments.json b/src/main/resources/arguments.json index bbad2e54f..c49efd543 100644 --- a/src/main/resources/arguments.json +++ b/src/main/resources/arguments.json @@ -334,38 +334,22 @@ } }, "lock": { - "channel*": { - "_type": "optional" - }, - "role*": { - "_type": "optional", - "channel*": { - "_type": "optional" - } - }, - "member*": { - "_type": "optional", - "channel*": { - "_type": "optional" + "channel": { + "_type": "required", + "role*": { + "_aliases": ["member"], + "_type": "required" } } }, "templock*" : { "duration" : { "_type" : "required", - "channel" : { - "_type" : "optional" - }, - "role*" : { - "_type" : "optional", - "channel" : { - "_type" : "optional" - } - }, - "member*" : { - "_type" : "optional", - "channel" : { - "_type" : "optional" + "channel": { + "_type": "required", + "role*": { + "_aliases": ["member"], + "_type": "required" } } } @@ -376,19 +360,11 @@ } }, "unlock": { - "channel*": { - "_type": "optional" - }, - "role*": { - "_type": "optional", - "channel*": { - "_type": "optional" - } - }, - "member*": { - "_type": "optional", - "channel*": { - "_type": "optional" + "channel": { + "_type": "required", + "role*": { + "_aliases": ["member"], + "_type": "required" } } }, diff --git a/src/main/resources/lang/en-GB.json b/src/main/resources/lang/en-GB.json index 8642fa5ec..a6f46ce79 100644 --- a/src/main/resources/lang/en-GB.json +++ b/src/main/resources/lang/en-GB.json @@ -141,22 +141,20 @@ "lock": { "command": "lock", "description": "Locks a channel for a member, role or everyone", - "text_success": "Channel `{0}` locked", - "success": "Channel `{0}` has been locked for {1}", + "success": "The channel `{0}` has been locked for {1}", "invalid_argument": "Could not find a channel, role or member matching `{0}`" }, "templock": { "command": "templock", "descripton": "Locks a channel for a member, role or everyone for a given amount of time", - "text_success": "Channel `{0}` locked\nThis will be reset in {1}", - "success": "Channel `{0}` has been locked for {1}\nThis will be reset in {2}" + "success": "The channel `{0}` has been locked for {1}\nThis will be reset in {2}" }, "unlock": { "command": "unlock", "description": "Unlocks a channel for a member, role or everyone", - "text_success" : "Channel `{0}` unlocked", - "success" : "Channel `{0}` has been unlocked for {1}", - "fail" : "Channel is not locked for {0}" + "success" : "The channel `{0}` has been unlocked for {1}", + "failure": "The channel `{0}` is not locked for {1}", + "invalid_argument": "Could not find a channel, role or member matching `{0}`" }, "userinfo": { "command": "userinfo", From eb52642dc68b4d4729cd1cd4df6aeae57c6fe6e4 Mon Sep 17 00:00:00 2001 From: William Oldham Date: Sun, 25 Oct 2020 20:51:57 +0000 Subject: [PATCH 09/16] Remove duplicate JSON keys --- src/main/resources/lang/en-GB.json | 41 ++++++++++-------------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/src/main/resources/lang/en-GB.json b/src/main/resources/lang/en-GB.json index a6f46ce79..0a9788956 100644 --- a/src/main/resources/lang/en-GB.json +++ b/src/main/resources/lang/en-GB.json @@ -1688,27 +1688,14 @@ "value": "value", "volume": "volume", "weight": "weight", - "setting": "setting", - "flag": "flag", - "query": "query", - "force": "force", - "scope": "scope", - "url": "url", - "reset": "reset", - "channel": "channel", - "prefix": "prefix", - "command": "command", - "timestamp": "timestamp", - "amount": "amount", - "token": "token", - "item": "item", - "list": "list", "words": "words", - "filters#type#whitelist": { - "name": "whitelist" + "guild#flag#list": { + "name": "list", + "description": "Lists all flags." }, - "filters#operator#or": { - "name": "or" + "guild#save#all": { + "name": "all", + "description": "Saves all guilds." }, "userperms#list#user#permissions": { "name": "permissions", @@ -1718,13 +1705,8 @@ "name": "groups", "description": "Lists the groups a user has." }, - "guild#save#all": { - "name": "all", - "description": "Saves all guilds." - }, - "guild#flag#list": { - "name": "list", - "description": "Lists all flags." + "color#red#green#blue": { + "description": "Gets the information of a colour from the red, green and blue values." }, "random#max": { "description": "Random number between 1 and the max you specify." @@ -1732,8 +1714,11 @@ "random#min#max": { "description": "Random number between the min and the max." }, - "color#red#green#blue": { - "description": "Gets the information of a colour from the red, green and blue values." + "filters#operator#or": { + "name": "or" + }, + "filters#type#whitelist": { + "name": "whitelist" } }, "utils": { From f265b3f9f141cf8378c289829a95fc13c6612083 Mon Sep 17 00:00:00 2001 From: William Oldham Date: Sat, 12 Jun 2021 17:46:47 +0100 Subject: [PATCH 10/16] Create a util class to hold previous lock state --- .../cascadebot/data/managers/LockManager.kt | 21 +++++++++---------- .../cascadebot/data/objects/GuildData.kt | 5 ++--- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt index aa66c6d94..78354f058 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt @@ -6,7 +6,6 @@ import net.dv8tion.jda.api.entities.Guild import net.dv8tion.jda.api.entities.IPermissionHolder import net.dv8tion.jda.api.entities.TextChannel import net.dv8tion.jda.api.requests.restaction.PermissionOverrideAction -import net.dv8tion.jda.internal.utils.tuple.MutablePair import java.util.EnumSet enum class Status { @@ -24,22 +23,23 @@ enum class Status { } +data class LockPermissionState(val target: Status, val selfMember: Status) + object LockManager { - fun getPerm(channel: TextChannel, target: IPermissionHolder): MutablePair { - // [target, selfMember] - val perm = MutablePair(Status.NEUTRAL, Status.NEUTRAL) + fun getPerm(channel: TextChannel, target: IPermissionHolder): LockPermissionState { + var perm = LockPermissionState(Status.NEUTRAL, Status.NEUTRAL) val targetOverride = channel.getPermissionOverride(target) if (targetOverride != null) { - if (targetOverride.allowed.contains(Permission.MESSAGE_WRITE)) perm.setLeft(Status.ALLOW) - if (targetOverride.denied.contains(Permission.MESSAGE_WRITE)) perm.setLeft(Status.DENY) + if (targetOverride.allowed.contains(Permission.MESSAGE_WRITE)) perm = perm.copy(target = Status.ALLOW) + if (targetOverride.denied.contains(Permission.MESSAGE_WRITE)) perm = perm.copy(target = Status.DENY) } val selfMemberOverride = channel.getPermissionOverride(channel.guild.selfMember) if (selfMemberOverride != null) { - if (selfMemberOverride.allowed.contains(Permission.MESSAGE_WRITE)) perm.setRight(Status.ALLOW) - if (selfMemberOverride.denied.contains(Permission.MESSAGE_WRITE)) perm.setRight(Status.DENY) + if (selfMemberOverride.allowed.contains(Permission.MESSAGE_WRITE)) perm = perm.copy(selfMember = Status.ALLOW) + if (selfMemberOverride.denied.contains(Permission.MESSAGE_WRITE)) perm = perm.copy(selfMember = Status.DENY) } return perm } @@ -54,7 +54,6 @@ object LockManager { } } - fun lock(channel: TextChannel, target: IPermissionHolder) { storePermissions(channel, target) channel.upsertPermissionOverride(channel.guild.selfMember).grant(Permission.MESSAGE_WRITE).queue() @@ -71,14 +70,14 @@ object LockManager { val selfPermissionAction = channel.getPermissionOverride(guild.selfMember)?.manager if (selfPermissionAction != null) { - state.right.apply(selfPermissionAction, perm) + state.selfMember.apply(selfPermissionAction, perm) selfPermissionAction.queue { if (it.allowedRaw == 0L && it.deniedRaw == 0L) it.delete().queue() } changed = true; } val targetPermissionAction = channel.getPermissionOverride(target)?.manager if (targetPermissionAction != null) { - state.left.apply(targetPermissionAction, perm) + state.target.apply(targetPermissionAction, perm) targetPermissionAction.queue { GuildDataManager.getGuildData(guild.idLong).lockedChannels[channel.idLong.toString()]?.remove(target.idLong.toString()) if (it.allowedRaw == 0L && it.deniedRaw == 0L) it.delete().queue() diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt index 34e9cfc6e..fe5d7b9ed 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt @@ -5,10 +5,9 @@ import de.bild.codec.annotations.Id import de.bild.codec.annotations.Transient import net.dv8tion.jda.api.entities.Message import net.dv8tion.jda.api.entities.MessageChannel -import net.dv8tion.jda.internal.utils.tuple.MutablePair import org.cascadebot.cascadebot.CascadeBot import org.cascadebot.cascadebot.data.language.Locale -import org.cascadebot.cascadebot.data.managers.Status +import org.cascadebot.cascadebot.data.managers.LockPermissionState import org.cascadebot.cascadebot.music.CascadeLavalinkPlayer import org.cascadebot.cascadebot.utils.buttons.ButtonGroup import org.cascadebot.cascadebot.utils.buttons.ButtonsCache @@ -45,7 +44,7 @@ class GuildData(@field:Id val guildId: Long) { //endregion // > - var lockedChannels: MutableMap>> = mutableMapOf() + var lockedChannels: MutableMap> = mutableMapOf() //region Transient fields @Transient From 6b8b92fb53a2bc3844f9fe01d90a45d926e7f836 Mon Sep 17 00:00:00 2001 From: William Oldham Date: Sat, 12 Jun 2021 17:48:30 +0100 Subject: [PATCH 11/16] Hold the time at which the permission state was applied --- .../org/cascadebot/cascadebot/data/managers/LockManager.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt index 78354f058..c1ca06c8b 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt @@ -6,6 +6,7 @@ import net.dv8tion.jda.api.entities.Guild import net.dv8tion.jda.api.entities.IPermissionHolder import net.dv8tion.jda.api.entities.TextChannel import net.dv8tion.jda.api.requests.restaction.PermissionOverrideAction +import java.time.OffsetDateTime import java.util.EnumSet enum class Status { @@ -23,7 +24,7 @@ enum class Status { } -data class LockPermissionState(val target: Status, val selfMember: Status) +data class LockPermissionState(val target: Status, val selfMember: Status, val createdAt: OffsetDateTime = OffsetDateTime.now()) object LockManager { From 75159a35e2cb6db44833d1d0da9e251126586c58 Mon Sep 17 00:00:00 2001 From: William Oldham Date: Sat, 12 Jun 2021 18:38:43 +0100 Subject: [PATCH 12/16] Convert lock and unlock to callback functions --- .../cascadebot/data/managers/LockManager.kt | 68 ++++++++++++++----- 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt index c1ca06c8b..d3faf8b9e 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt @@ -8,6 +8,7 @@ import net.dv8tion.jda.api.entities.TextChannel import net.dv8tion.jda.api.requests.restaction.PermissionOverrideAction import java.time.OffsetDateTime import java.util.EnumSet +import java.util.concurrent.CompletableFuture enum class Status { ALLOW, @@ -24,7 +25,11 @@ enum class Status { } -data class LockPermissionState(val target: Status, val selfMember: Status, val createdAt: OffsetDateTime = OffsetDateTime.now()) +data class LockPermissionState( + val target: Status, + val selfMember: Status, + val createdAt: OffsetDateTime = OffsetDateTime.now() +) object LockManager { @@ -55,37 +60,68 @@ object LockManager { } } - fun lock(channel: TextChannel, target: IPermissionHolder) { + fun lock(channel: TextChannel, target: IPermissionHolder, success: () -> Unit, failure: (Throwable) -> Unit) { storePermissions(channel, target) - channel.upsertPermissionOverride(channel.guild.selfMember).grant(Permission.MESSAGE_WRITE).queue() - channel.upsertPermissionOverride(target).deny(Permission.MESSAGE_WRITE).queue() + + CompletableFuture.allOf( + channel.upsertPermissionOverride(channel.guild.selfMember).grant(Permission.MESSAGE_WRITE).submit(), + channel.upsertPermissionOverride(target).deny(Permission.MESSAGE_WRITE).submit() + ).handle { _, throwable -> if (throwable == null) success() else failure(throwable) } } - fun unlock(guild: Guild, channel: TextChannel, target: IPermissionHolder) : Boolean { - val state = GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id]?.get(target.id) - // If there is no state to restore, we can't do anything! - ?: return false + fun isLocked(channel: TextChannel, target: IPermissionHolder): Boolean { + val lockedChannels = GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels + val mutableMap = lockedChannels[channel.id] ?: return false + return mutableMap.containsKey(target.id) + } + + fun unlock(guild: Guild, channel: TextChannel, target: IPermissionHolder, success: (Boolean) -> Unit, failure: (Throwable) -> Unit) { + val previousState = GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id]?.get(target.id) + // If there is no state to restore, we can't do anything! + ?: return val perm = EnumSet.of(Permission.MESSAGE_WRITE) - var changed = false; + val futures: MutableList> = mutableListOf() val selfPermissionAction = channel.getPermissionOverride(guild.selfMember)?.manager if (selfPermissionAction != null) { - state.selfMember.apply(selfPermissionAction, perm) - selfPermissionAction.queue { if (it.allowedRaw == 0L && it.deniedRaw == 0L) it.delete().queue() } - changed = true; + // Apply the self member's previous state + previousState.selfMember.apply(selfPermissionAction, perm) + // Apply the changes to the permission override + val submit = selfPermissionAction.submit() + // If the permission override has no permissions set after we have reset the perms, delete it to tidy. + submit.thenAccept { if (it.allowedRaw == 0L && it.deniedRaw == 0L) it.delete().queue() } + futures.add(submit) } val targetPermissionAction = channel.getPermissionOverride(target)?.manager if (targetPermissionAction != null) { - state.target.apply(targetPermissionAction, perm) - targetPermissionAction.queue { + // Apply the target's previous state + previousState.target.apply(targetPermissionAction, perm) + // Apply thr changes to the permission override + val submit = targetPermissionAction.submit() + // Remove the locked channels entry for this permission override and delete the + // override if there are no permissions left on it to tidy. + submit.thenAccept { GuildDataManager.getGuildData(guild.idLong).lockedChannels[channel.idLong.toString()]?.remove(target.idLong.toString()) if (it.allowedRaw == 0L && it.deniedRaw == 0L) it.delete().queue() } - changed = true + futures.add(submit) + } + + val bothFutures = CompletableFuture.allOf(*futures.toTypedArray()) + + bothFutures.handle { _, throwable -> + if (throwable == null) { + success(true) + } else { + failure(throwable) + } + } + + if (futures.isEmpty()) { + success(false) } - return changed } } From b5f8608681b19ba494023a3d3da80972a0342690 Mon Sep 17 00:00:00 2001 From: William Oldham Date: Sat, 12 Jun 2021 18:38:54 +0100 Subject: [PATCH 13/16] LockCommand: Use callbacks --- .../commands/moderation/LockCommand.kt | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt index 1691d9b99..acb669a38 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt @@ -1,6 +1,8 @@ package org.cascadebot.cascadebot.commands.moderation import net.dv8tion.jda.api.Permission +import net.dv8tion.jda.api.entities.IMentionable +import net.dv8tion.jda.api.entities.IPermissionHolder import net.dv8tion.jda.api.entities.ISnowflake import net.dv8tion.jda.api.entities.Member import net.dv8tion.jda.api.entities.Role @@ -12,6 +14,7 @@ import org.cascadebot.cascadebot.commandmeta.Module import org.cascadebot.cascadebot.data.managers.LockManager import org.cascadebot.cascadebot.permissions.CascadePermission import org.cascadebot.cascadebot.utils.DiscordUtils +import java.lang.IllegalStateException class LockCommand : MainCommand() { override fun onCommand(sender: Member, context: CommandContext) { @@ -25,32 +28,37 @@ class LockCommand : MainCommand() { val target: ISnowflake = if (context.args.size == 2) { DiscordUtils.getRole(context.getArg(1), context.guild) ?: DiscordUtils.getMember(context.guild, context.getArg(1)) - ?: DiscordUtils.getTextChannel(context.guild, context.getArg(1)) ?: return context.typedMessaging.replyDanger(context.i18n("commands.lock.invalid_argument", context.getArg(0))) } else { context.guild.publicRole } - if (target is TextChannel) channel = target; + if (target !is IPermissionHolder) error("Target must be a IPermissionHolder") - val name: String = try { - when (target) { - is Role -> { - LockManager.lock(channel, target) - "%s %s".format(context.i18n("arguments.role"), target.asMention) - } - is Member -> { - LockManager.lock(channel, target) - "%s %s".format(context.i18n("arguments.member"), target.asMention) - } - else -> "" + val success = { + val name: String = when(target) { + is Role -> target.asMention + is Member -> target.asMention + else -> error("Target must be either a Role or a Member") + } + + if (target is Member) { + context.typedMessaging.replySuccess((context.i18n("commands.lock.success_member", channel.name, target.asMention))) + } else if (target is Role) { + context.typedMessaging.replySuccess((context.i18n("commands.lock.success_role", channel.name, target.asMention))) + } + + } + + val failure = { throwable: Throwable -> + if (throwable is PermissionException) { + context.uiMessaging.sendBotDiscordPermError(throwable.permission) + } else { + context.typedMessaging.replyException("Something went wrong!", throwable) } - } catch (e: PermissionException) { - context.uiMessaging.sendBotDiscordPermError(e.permission) - return } - context.typedMessaging.replySuccess((context.i18n("commands.lock.success", channel.name, name))) + LockManager.lock(channel, target, success, failure) } From 47776073d8b69f442a615856f343a088759fc388 Mon Sep 17 00:00:00 2001 From: William Oldham Date: Sat, 12 Jun 2021 22:01:48 +0100 Subject: [PATCH 14/16] Refactor log commands --- .../commands/moderation/LockCommand.kt | 2 + .../commands/moderation/TempLockCommand.kt | 64 +++++++++---------- .../commands/moderation/UnlockCommand.kt | 45 +++++++------ .../cascadebot/data/managers/LockManager.kt | 2 +- .../cascadebot/scheduler/ActionType.kt | 23 +++++-- src/main/resources/lang/en-GB.json | 12 ++-- 6 files changed, 86 insertions(+), 62 deletions(-) diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt index acb669a38..317c05875 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt @@ -33,6 +33,8 @@ class LockCommand : MainCommand() { context.guild.publicRole } + // Member and Role are both IPermissionHolder so this should not happen + // This check is here to smart-cast target to IPermissionHolder for later code if (target !is IPermissionHolder) error("Target must be a IPermissionHolder") val success = { diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt index 4d7b6a045..6fead6036 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/TempLockCommand.kt @@ -1,6 +1,7 @@ package org.cascadebot.cascadebot.commands.moderation import net.dv8tion.jda.api.Permission +import net.dv8tion.jda.api.entities.IPermissionHolder import net.dv8tion.jda.api.entities.ISnowflake import net.dv8tion.jda.api.entities.Member import net.dv8tion.jda.api.entities.Role @@ -51,50 +52,49 @@ class TempLockCommand : MainCommand() { ?: DiscordUtils.getMember(context.guild, context.getArg(2)) ?: return context.typedMessaging.replyDanger(context.i18n("commands.templock.invalid_argument", context.getArg(2))) } else { - context.channel + context.guild.publicRole } - val toAction = ScheduledAction.LockActionData(channel.idLong, Status.NEUTRAL, 0, 0) + // Member and Role are both IPermissionHolder so this should not happen + // This check is here to smart-cast target to IPermissionHolder for later code + if (target !is IPermissionHolder) error("Target must be a IPermissionHolder") - var name: String? = null - try { - when (target) { - is Role -> { - toAction.oldPermission = LockManager.getPerm(channel, target).left + val unlockFutureData = ScheduledAction.LockActionData(channel.idLong, Status.NEUTRAL, 0, 0) + unlockFutureData.oldPermission = LockManager.getPerm(channel, target).target + unlockFutureData.targetRoleID = target.idLong - LockManager.lock(channel, target) - - toAction.targetRoleID = target.idLong - name = "%s %s".format(context.i18n("arguments.role"), target.asMention) - } - is Member -> { - toAction.oldPermission = LockManager.getPerm(channel, target).left - - LockManager.lock(channel, target) - - toAction.targetMemberID = target.idLong - name = "%s %s".format(context.i18n("arguments.member"), target.user.asMention) - } - } - } catch (e: PermissionException) { - context.uiMessaging.sendBotDiscordPermError(e.permission) - return - } - - ScheduledActionManager.registerScheduledAction(ScheduledAction( + val success = { + ScheduledActionManager.registerScheduledAction(ScheduledAction( ActionType.UNLOCK, - toAction, + unlockFutureData, context.guild.idLong, context.channel.idLong, context.member.idLong, Instant.now(), longDuration - )) + )) + + val textDuration = FormatUtils.formatTime(longDuration, context.locale, true).replace("(0[hm])".toRegex(), "") + + " (" + context.i18n("words.until") + " " + FormatUtils.formatDateTime(OffsetDateTime.now().plus(longDuration, ChronoUnit.MILLIS), context.locale) + ")" + val message = when (target) { + is Role -> context.i18n("commands.templock.success_role", channel.name, target.asMention, textDuration) + is Member -> context.i18n("commands.templock.success_member", channel.name, target.asMention, textDuration) + else -> error("Target should be either Role or Member!") + } + + context.typedMessaging.replySuccess(message) + } + + val failure = { throwable: Throwable -> + if (throwable is PermissionException) { + context.uiMessaging.sendBotDiscordPermError(throwable.permission) + } else { + context.typedMessaging.replyException("Something went wrong!", throwable) + } + } - val textDuration = FormatUtils.formatTime(longDuration, context.locale, true).replace("(0[hm])".toRegex(), "") + - " (" + context.i18n("words.until") + " " + FormatUtils.formatDateTime(OffsetDateTime.now().plus(longDuration, ChronoUnit.MILLIS), context.locale) + ")" - context.typedMessaging.replySuccess(if (target is TextChannel) context.i18n("commands.templock.text_success", target.name, textDuration) else name?.let { context.i18n("commands.templock.success", channel.name, it, textDuration) }) + LockManager.lock(channel, target, success, failure); } diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt index c6274427b..19361cf4e 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/UnlockCommand.kt @@ -2,6 +2,7 @@ package org.cascadebot.cascadebot.commands.moderation import javassist.NotFoundException import net.dv8tion.jda.api.Permission +import net.dv8tion.jda.api.entities.IPermissionHolder import net.dv8tion.jda.api.entities.ISnowflake import net.dv8tion.jda.api.entities.Member import net.dv8tion.jda.api.entities.Role @@ -31,31 +32,35 @@ class UnlockCommand : MainCommand() { context.guild.publicRole } - var name = "" - val completed = try { - when (target) { - is Role -> { - name = target.asMention - LockManager.unlock(context.guild, channel, target) + // Member and Role are both IPermissionHolder so this should not happen + // This check is here to smart-cast target to IPermissionHolder for later code + if (target !is IPermissionHolder) error("Target must be a IPermissionHolder") + + val success = { completed: Boolean -> + if (completed) { + when (target) { + is Role -> context.typedMessaging.replySuccess(context.i18n("commands.unlock.success_role", channel.name, target.asMention)) + is Member -> context.typedMessaging.replySuccess(context.i18n("commands.unlock.success_member", channel.name, target.asMention)) + else -> error("Target should be one of Role or Member") } - is Member -> { - name = "%s %s".format(context.i18n("arguments.member"), target.asMention) - LockManager.unlock(context.guild, channel, target) + } else { + when (target) { + is Role -> context.typedMessaging.replySuccess(context.i18n("commands.unlock.failure_role", channel.name, target.asMention)) + is Member -> context.typedMessaging.replySuccess(context.i18n("commands.unlock.failure_member", channel.name, target.asMention)) + else -> error("Target should be one of Role or Member") } - else -> false } - } catch (e: PermissionException) { - context.uiMessaging.sendBotDiscordPermError(e.permission) - return - } catch (e: NotFoundException) { - context.typedMessaging.replyWarning(context.i18n("commands.unlock.fail", if (target is TextChannel) context.guild.publicRole.asMention else name!!)) - return } - if (completed) { - context.typedMessaging.replySuccess(context.i18n("commands.unlock.success", channel.name, name)) - } else { - context.typedMessaging.replyDanger(context.i18n("commands.unlock.failure", channel.name, name)) + + val failure = { throwable: Throwable -> + if (throwable is PermissionException) { + context.uiMessaging.sendBotDiscordPermError(throwable.permission) + } else { + context.typedMessaging.replyException("Something went wrong!", throwable) + } } + + LockManager.unlock(context.guild, channel, target, success, failure) } override fun command(): String { diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt index d3faf8b9e..4b0d870fe 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt @@ -78,7 +78,7 @@ object LockManager { fun unlock(guild: Guild, channel: TextChannel, target: IPermissionHolder, success: (Boolean) -> Unit, failure: (Throwable) -> Unit) { val previousState = GuildDataManager.getGuildData(channel.guild.idLong).lockedChannels[channel.id]?.get(target.id) // If there is no state to restore, we can't do anything! - ?: return + ?: return success(false) val perm = EnumSet.of(Permission.MESSAGE_WRITE) val futures: MutableList> = mutableListOf() diff --git a/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ActionType.kt b/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ActionType.kt index 93210b0b1..ccddacb96 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ActionType.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/scheduler/ActionType.kt @@ -73,13 +73,25 @@ enum class ActionType(val expectedClass: KClass<*>, val dataConsumer: (Scheduled if (action.data is ScheduledAction.SlowmodeActionData) { action.guild?.let { guild -> val targetChannel = guild.getGuildChannelById(action.data.targetId) - targetChannel?.manager?.setSlowmode(action.data.oldSlowmode)?.queue(null, { + targetChannel?.manager?.setSlowmode(action.data.oldSlowmode)?.queue(null) { if (it is PermissionException) { - action.channel?.let { channel -> Messaging.sendMessage(MessageType.DANGER, channel, i18n(action.guildId, "responses.no_discord_perm_bot", it.permission.name)) } + action.channel?.let { channel -> + Messaging.sendMessage( + MessageType.DANGER, + channel, + i18n(action.guildId, "responses.no_discord_perm_bot", it.permission.name) + ) + } } else { - action.channel?.let { channel -> Messaging.sendExceptionMessage(channel, "Couldn't unslowmode %s".format(targetChannel), it) } + action.channel?.let { channel -> + Messaging.sendExceptionMessage( + channel, + "Couldn't unslowmode %s".format(targetChannel), + it + ) + } } - }) + } } } }), @@ -95,7 +107,8 @@ enum class ActionType(val expectedClass: KClass<*>, val dataConsumer: (Scheduled ?: guild.getMemberById(action.data.targetMemberID) ?: guild.publicRole - LockManager.unlock(guild, targetChannel as TextChannel, target as IPermissionHolder) + // TODO: Do something on failure? + LockManager.unlock(guild, targetChannel as TextChannel, target as IPermissionHolder, {}, {}) } diff --git a/src/main/resources/lang/en-GB.json b/src/main/resources/lang/en-GB.json index 0a9788956..d1c4266f3 100644 --- a/src/main/resources/lang/en-GB.json +++ b/src/main/resources/lang/en-GB.json @@ -141,19 +141,23 @@ "lock": { "command": "lock", "description": "Locks a channel for a member, role or everyone", - "success": "The channel `{0}` has been locked for {1}", + "success_role": "The channel `{0}` has been locked for the role {1}", + "success_member": "The channel `{0}` has been locked for the member {1}", "invalid_argument": "Could not find a channel, role or member matching `{0}`" }, "templock": { "command": "templock", "descripton": "Locks a channel for a member, role or everyone for a given amount of time", - "success": "The channel `{0}` has been locked for {1}\nThis will be reset in {2}" + "success_role": "The channel `{0}` has been locked for the role {1}\nThis will be reset in {2}", + "success_member": "The channel `{0}` has been locked for the member {1}\nThis will be reset in {2}" }, "unlock": { "command": "unlock", "description": "Unlocks a channel for a member, role or everyone", - "success" : "The channel `{0}` has been unlocked for {1}", - "failure": "The channel `{0}` is not locked for {1}", + "success_role" : "The channel `{0}` has been unlocked for the role {1}", + "success_member" : "The channel `{0}` has been unlocked for the member {1}", + "failure_role": "The channel `{0}` is not locked for the role {1}", + "failure_member": "The channel `{0}` is not locked for the member {1}", "invalid_argument": "Could not find a channel, role or member matching `{0}`" }, "userinfo": { From a97c8643e798baeb05bda2732e317d1434047cd5 Mon Sep 17 00:00:00 2001 From: William Oldham Date: Sun, 13 Jun 2021 23:17:20 +0100 Subject: [PATCH 15/16] Add check if the channel is already locked --- .../cascadebot/commands/moderation/LockCommand.kt | 8 ++++++++ src/main/resources/lang/en-GB.json | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt index 317c05875..e2768c1b9 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/commands/moderation/LockCommand.kt @@ -37,6 +37,14 @@ class LockCommand : MainCommand() { // This check is here to smart-cast target to IPermissionHolder for later code if (target !is IPermissionHolder) error("Target must be a IPermissionHolder") + if (LockManager.isLocked(channel, target)) { + when (target) { + is Role -> context.typedMessaging.replyWarning(context.i18n("commands.lock.already_locked_role", channel.name, target.asMention)) + is Member -> context.typedMessaging.replyWarning(context.i18n("commands.lock.already_locked_member", channel.name, target.asMention)) + } + return + } + val success = { val name: String = when(target) { is Role -> target.asMention diff --git a/src/main/resources/lang/en-GB.json b/src/main/resources/lang/en-GB.json index d1c4266f3..f57a50db6 100644 --- a/src/main/resources/lang/en-GB.json +++ b/src/main/resources/lang/en-GB.json @@ -143,6 +143,8 @@ "description": "Locks a channel for a member, role or everyone", "success_role": "The channel `{0}` has been locked for the role {1}", "success_member": "The channel `{0}` has been locked for the member {1}", + "already_locked_role": "The channel `{0}` is already locked for the role {1}!", + "already_locked_member": "The channel `{0}` is already locked for the member {1}!", "invalid_argument": "Could not find a channel, role or member matching `{0}`" }, "templock": { From 350f87e287c070669dbaf9b73b1830e5398a1ba2 Mon Sep 17 00:00:00 2001 From: William Oldham Date: Sun, 13 Jun 2021 23:17:43 +0100 Subject: [PATCH 16/16] Allow new LockStatus object to be serialised --- .../cascadebot/data/database/DatabaseManager.java | 3 ++- .../cascadebot/cascadebot/data/managers/LockManager.kt | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/cascadebot/cascadebot/data/database/DatabaseManager.java b/src/main/java/org/cascadebot/cascadebot/data/database/DatabaseManager.java index d18ba1d40..05e677b90 100644 --- a/src/main/java/org/cascadebot/cascadebot/data/database/DatabaseManager.java +++ b/src/main/java/org/cascadebot/cascadebot/data/database/DatabaseManager.java @@ -19,6 +19,7 @@ import org.bson.Document; import org.bson.codecs.configuration.CodecRegistries; import org.bson.codecs.configuration.CodecRegistry; +import org.cascadebot.cascadebot.data.managers.LockPermissionState; import org.cascadebot.cascadebot.utils.lists.WeightedList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,7 +43,7 @@ public class DatabaseManager { "org.cascadebot.cascadebot.utils.lists", "org.cascadebot.cascadebot.scheduler", "org.cascadebot.shared" - ).register(WeightedList.WeightPair.class).build()) + ).register(WeightedList.WeightPair.class, LockPermissionState.class).build()) ); @Getter diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt index 4b0d870fe..af16f50e2 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/managers/LockManager.kt @@ -7,6 +7,7 @@ import net.dv8tion.jda.api.entities.IPermissionHolder import net.dv8tion.jda.api.entities.TextChannel import net.dv8tion.jda.api.requests.restaction.PermissionOverrideAction import java.time.OffsetDateTime +import java.util.Date import java.util.EnumSet import java.util.concurrent.CompletableFuture @@ -28,8 +29,12 @@ enum class Status { data class LockPermissionState( val target: Status, val selfMember: Status, - val createdAt: OffsetDateTime = OffsetDateTime.now() -) + val createdAt: Date = Date() +) { + + private constructor() : this(Status.NEUTRAL, Status.NEUTRAL) + +} object LockManager {