diff --git a/src/main/java/com/jagrosh/vortex/Listener.java b/src/main/java/com/jagrosh/vortex/Listener.java index 9502101..325a150 100644 --- a/src/main/java/com/jagrosh/vortex/Listener.java +++ b/src/main/java/com/jagrosh/vortex/Listener.java @@ -24,6 +24,7 @@ import net.dv8tion.jda.core.entities.Role; import net.dv8tion.jda.core.events.Event; import net.dv8tion.jda.core.events.ReadyEvent; +import net.dv8tion.jda.core.events.channel.text.update.TextChannelUpdateSlowmodeEvent; import net.dv8tion.jda.core.events.guild.GuildBanEvent; import net.dv8tion.jda.core.events.guild.GuildUnbanEvent; import net.dv8tion.jda.core.events.guild.member.*; @@ -206,6 +207,11 @@ if(!gevent.getMember().getUser().isBot()) // ignore bots vortex.getBasicLogger().logVoiceLeave(gevent); } + else if (event instanceof TextChannelUpdateSlowmodeEvent) + { + vortex.getDatabase().tempslowmodes.clearSlowmode(((TextChannelUpdateSlowmodeEvent) event).getChannel()); + vortex.getEventWaiter().onEvent(event); + } else if (event instanceof ReadyEvent) { // Log the shard that has finished loading @@ -216,6 +222,8 @@ +event.getJDA().getGuildCache().size()+"` Users: `"+event.getJDA().getUserCache().size()+"`"); vortex.getThreadpool().scheduleWithFixedDelay(() -> vortex.getDatabase().tempbans.checkUnbans(event.getJDA()), 0, 2, TimeUnit.MINUTES); vortex.getThreadpool().scheduleWithFixedDelay(() -> vortex.getDatabase().tempmutes.checkUnmutes(event.getJDA(), vortex.getDatabase().settings), 0, 45, TimeUnit.SECONDS); + vortex.getThreadpool().scheduleWithFixedDelay(() -> vortex.getDatabase().tempslowmodes.checkSlowmode(event.getJDA()), 0, 45, TimeUnit.SECONDS); + } } } diff --git a/src/main/java/com/jagrosh/vortex/commands/moderation/SlowmodeCmd.java b/src/main/java/com/jagrosh/vortex/commands/moderation/SlowmodeCmd.java index 5ef6ae7..e317f1b 100644 --- a/src/main/java/com/jagrosh/vortex/commands/moderation/SlowmodeCmd.java +++ b/src/main/java/com/jagrosh/vortex/commands/moderation/SlowmodeCmd.java @@ -21,7 +21,11 @@ import com.jagrosh.vortex.utils.FormatUtil; import com.jagrosh.vortex.utils.OtherUtil; import net.dv8tion.jda.core.Permission; -import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.events.channel.text.update.TextChannelUpdateSlowmodeEvent; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.concurrent.TimeUnit; /** * @author Michaili K (mysteriouscursor+git@protonmail.com) @@ -34,7 +38,7 @@ { super(vortex, Permission.MANAGE_CHANNEL); this.name = "slowmode"; - this.arguments = "[time or OFF]"; + this.arguments = "[time or OFF] | [time to disable slowmode]"; this.help = "enables or disables slowmode"; this.botPermissions = new Permission[]{Permission.MANAGE_CHANNEL}; this.guildOnly = true; @@ -43,67 +47,84 @@ @Override protected void execute(CommandEvent event) { - String args = event.getArgs(); - TextChannel channel = event.getTextChannel(); - int time; - // Event args is empty - if (args.isEmpty()) + if(event.getArgs().isEmpty()) { - if (channel.getSlowmode() > 0) - time = 0; - else - time = 5; - } + int slowmodeDuration = vortex.getDatabase().tempslowmodes.timeUntilDisableSlowmode(event.getTextChannel()); + int slowmodeTime = event.getTextChannel().getSlowmode(); - // Event args isn't empty - else - { - // Because parseTime returns 0 if the input is invalid, we'll just check if the argument is not "0", - // then parse it & check again if it's 0. If it's 0, then it's likely invalid. - if (args.equalsIgnoreCase("off") || args.equals("0")) - time = 0; - else + if(slowmodeTime <= 0) { - // Because parseTime will return 0 when you don't give a time unit (for example, if you give "10" as - // argument, you expect for slowmode to be set to 10 seconds), we first try to simply parse the argument - // and if that fails, use parseTime - try - { - time = Integer.parseInt(args); - } - catch (Exception e) - { - time = OtherUtil.parseTime(event.getArgs()); - if (time <= 0) - { - event.replyError("Invalid time"); - return; - } - } - + event.reply("Slowmode is disabled."); + return; } + + if(slowmodeDuration <= 0) + event.reply("Slowmode is enabled with 1 message every "+FormatUtil.secondsToTimeCompact(slowmodeTime)+"."); + else + event.reply("Slowmode is enabled with 1 message every "+FormatUtil.secondsToTimeCompact(slowmodeTime) + + " for "+FormatUtil.secondsToTimeCompact(slowmodeDuration)+"."); + return; } - if (time > MAX_SLOWMODE) + String args = event.getArgs(); + + if(args.equals("0") || args.toLowerCase().equals("off")) + { + vortex.getDatabase().tempslowmodes.clearSlowmode(event.getTextChannel()); + event.getTextChannel().getManager().setSlowmode(0).queue(); + event.replySuccess("Disabled slowmode!"); + return; + } + + String[] split = args.split("\\|",2); + + int slowmodeTime = OtherUtil.parseTime(split[0]); + if(slowmodeTime == -1) + { + event.replyError("Invalid slowmode time!"); + return; + } + if(slowmodeTime > MAX_SLOWMODE) { event.replyError("You can only enable slowmode for up to 6 hours!"); return; } - if (time < 0) + if(slowmodeTime < -1) { event.replyError("Slowmode cannot use negative time!"); return; } - int finalTime = time; - channel.getManager().setSlowmode(time).queue( - success -> event.replySuccess( - finalTime > 0 - ? "Enabled slowmode for " + FormatUtil.secondsToTimeCompact(finalTime) + "!" - : "Disabled slowmode!"), + int slowmodeDuration = split.length == 1 ? 0 : OtherUtil.parseTime(split[1]); + if(slowmodeDuration == -1) + { + event.replyError("Invalid slowmode duration time!"); + return; + } + if(slowmodeDuration < -1) + { + event.replyError("Slowmode duration cannot use negative time!"); + return; + } - failure -> event.replyError("Couldn't " + (finalTime > 0 ? "enable" : "disable") + " slowmode!") - ); + event.getTextChannel().getManager() + .setSlowmode(slowmodeTime) + .reason("Enabled by "+event.getAuthor().getAsTag()+" ("+event.getAuthor().getId()+")") + .queue(); + + if(slowmodeDuration > 0) + { + vortex.getEventWaiter().waitForEvent( + TextChannelUpdateSlowmodeEvent.class, + c -> c.getChannel().getId().equals(event.getTextChannel().getId()), + ev -> vortex.getDatabase().tempslowmodes.setSlowmode(event.getTextChannel(), Instant.now().plus(slowmodeDuration, ChronoUnit.SECONDS)), + 10, TimeUnit.SECONDS, + () -> vortex.getDatabase().tempslowmodes.setSlowmode(event.getTextChannel(), Instant.now().plus(slowmodeDuration, ChronoUnit.SECONDS))); + } + + + event.replySuccess("Enabled slowmode with 1 message every " + FormatUtil.secondsToTimeCompact(slowmodeTime) + + (slowmodeDuration > 0 ? " for "+FormatUtil.secondsToTimeCompact(slowmodeDuration) : "")+"."); } } diff --git a/src/main/java/com/jagrosh/vortex/commands/tools/ExportCmd.java b/src/main/java/com/jagrosh/vortex/commands/tools/ExportCmd.java index 8a6eec5..1979434 100644 --- a/src/main/java/com/jagrosh/vortex/commands/tools/ExportCmd.java +++ b/src/main/java/com/jagrosh/vortex/commands/tools/ExportCmd.java @@ -57,6 +57,7 @@ .put("punishments", db.actions.getAllPunishmentsJson(g)) .put("tempmutes", db.tempmutes.getAllMutesJson(g)) .put("tempbans", db.tempbans.getAllBansJson(g)) + .put("tempslowmodes", db.tempslowmodes.getAllSlowmodesJson(g)) .put("inviteWhitelist", db.inviteWhitelist.getWhitelistJson(g)) .put("filters", db.filters.getFiltersJson(g)) .put("premium", db.premium.getPremiumInfoJson(g)); diff --git a/src/main/java/com/jagrosh/vortex/database/Database.java b/src/main/java/com/jagrosh/vortex/database/Database.java index 6913636..4f638bd 100644 --- a/src/main/java/com/jagrosh/vortex/database/Database.java +++ b/src/main/java/com/jagrosh/vortex/database/Database.java @@ -32,6 +32,7 @@ public final PunishmentManager actions; // strike punishment settings public final TempMuteManager tempmutes; public final TempBanManager tempbans; + public final TempSlowmodeManager tempslowmodes; public final PremiumManager premium; public final InviteWhitelistManager inviteWhitelist; public final FilterManager filters; @@ -48,6 +49,7 @@ actions = new PunishmentManager(this); tempmutes = new TempMuteManager(this); tempbans = new TempBanManager(this); + tempslowmodes = new TempSlowmodeManager(this); premium = new PremiumManager(this); inviteWhitelist = new InviteWhitelistManager(this); filters = new FilterManager(this); diff --git a/src/main/java/com/jagrosh/vortex/database/managers/TempSlowmodeManager.java b/src/main/java/com/jagrosh/vortex/database/managers/TempSlowmodeManager.java new file mode 100644 index 0000000..6c5096a --- /dev/null +++ b/src/main/java/com/jagrosh/vortex/database/managers/TempSlowmodeManager.java @@ -0,0 +1,125 @@ +/* + * Copyright 2018 John Grosh (john.a.grosh@gmail.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jagrosh.vortex.database.managers; + +import com.jagrosh.easysql.DataManager; +import com.jagrosh.easysql.DatabaseConnector; +import com.jagrosh.easysql.SQLColumn; +import com.jagrosh.easysql.columns.InstantColumn; +import com.jagrosh.easysql.columns.LongColumn; +import com.jagrosh.vortex.utils.Pair; +import net.dv8tion.jda.core.JDA; +import net.dv8tion.jda.core.Permission; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.TextChannel; +import org.json.JSONObject; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author Michail K (mysteriouscursor+git@protonmail.com) + */ +public class TempSlowmodeManager extends DataManager +{ + public static final SQLColumn CHANNEL_ID = new LongColumn("CHANNEL_ID", false, 0, true); + public static final SQLColumn FINISH = new InstantColumn("FINISH", false, Instant.EPOCH); + + public TempSlowmodeManager(DatabaseConnector connector) + { + super(connector, "TEMP_SLOWMODES"); + } + + public JSONObject getAllSlowmodesJson(Guild guild) + { + List> list = new ArrayList<>(); + for(TextChannel channel : guild.getTextChannels()) + { + read(selectAll(CHANNEL_ID.is(channel.getId())), rs -> + { + if(rs.next()) + list.add(new Pair<>(CHANNEL_ID.getValue(rs), FINISH.getValue(rs))); + }); + } + + JSONObject json = new JSONObject(); + list.forEach(p -> json.put(Long.toString(p.getKey()), p.getValue().getEpochSecond())); + return json; + } + + public void setSlowmode(TextChannel channel, Instant finish) + { + readWrite(selectAll(CHANNEL_ID.is(channel.getId())), rs -> + { + if(rs.next()) + { + FINISH.updateValue(rs, finish); + rs.updateRow(); + } + else + { + rs.moveToInsertRow(); + CHANNEL_ID.updateValue(rs, channel.getIdLong()); + FINISH.updateValue(rs, finish); + rs.insertRow(); + } + }); + } + + public void clearSlowmode(TextChannel channel) + { + readWrite(selectAll(CHANNEL_ID.is(channel.getId())), rs -> + { + if(rs.next()) + rs.deleteRow(); + }); + } + + public int timeUntilDisableSlowmode(TextChannel channel) + { + return read(selectAll(CHANNEL_ID.is(channel.getId())), rs -> + { + if(rs.next()) + { + Instant end = FINISH.getValue(rs); + if(end==Instant.MAX) + return 0; + else + return (int)(Instant.now().until(end, ChronoUnit.SECONDS)); + } + return 0; + }); + } + + public void checkSlowmode(JDA jda) + { + readWrite(selectAll(FINISH.isLessThan(Instant.now().getEpochSecond())), rs -> + { + while(rs.next()) + { + TextChannel tc = jda.getTextChannelById(CHANNEL_ID.getValue(rs)); + if(tc==null) + continue; + if(tc.getGuild().getSelfMember().hasPermission(tc, Permission.MANAGE_CHANNEL)) + tc.getManager().setSlowmode(0).reason("Temporary Slowmode Completed").queue(s->{}, f->{}); + rs.deleteRow(); + } + }); + } +}