diff --git a/commons/src/main/java/com/jagrosh/jdautilities/commons/utils/InverseAction.java b/commons/src/main/java/com/jagrosh/jdautilities/commons/utils/InverseAction.java new file mode 100644 index 00000000..cf2f1adb --- /dev/null +++ b/commons/src/main/java/com/jagrosh/jdautilities/commons/utils/InverseAction.java @@ -0,0 +1,776 @@ +package com.jagrosh.jdautilities.commons.utils; + +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.Region; +import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.events.GenericEvent; +import net.dv8tion.jda.api.events.channel.category.CategoryCreateEvent; +import net.dv8tion.jda.api.events.channel.category.update.CategoryUpdateNameEvent; +import net.dv8tion.jda.api.events.channel.category.update.CategoryUpdatePositionEvent; +import net.dv8tion.jda.api.events.channel.priv.PrivateChannelCreateEvent; +import net.dv8tion.jda.api.events.channel.store.StoreChannelCreateEvent; +import net.dv8tion.jda.api.events.channel.store.update.StoreChannelUpdateNameEvent; +import net.dv8tion.jda.api.events.channel.store.update.StoreChannelUpdatePositionEvent; +import net.dv8tion.jda.api.events.channel.text.TextChannelCreateEvent; +import net.dv8tion.jda.api.events.channel.text.update.*; +import net.dv8tion.jda.api.events.channel.voice.VoiceChannelCreateEvent; +import net.dv8tion.jda.api.events.channel.voice.VoiceChannelDeleteEvent; +import net.dv8tion.jda.api.events.channel.voice.update.*; +import net.dv8tion.jda.api.events.emote.EmoteAddedEvent; +import net.dv8tion.jda.api.events.emote.update.EmoteUpdateNameEvent; +import net.dv8tion.jda.api.events.emote.update.EmoteUpdateRolesEvent; +import net.dv8tion.jda.api.events.guild.GuildBanEvent; +import net.dv8tion.jda.api.events.guild.GuildJoinEvent; +import net.dv8tion.jda.api.events.guild.GuildUnbanEvent; +import net.dv8tion.jda.api.events.guild.invite.GuildInviteCreateEvent; +import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent; +import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleAddEvent; +import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleRemoveEvent; +import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateNicknameEvent; +import net.dv8tion.jda.api.events.guild.override.PermissionOverrideCreateEvent; +import net.dv8tion.jda.api.events.guild.override.PermissionOverrideDeleteEvent; +import net.dv8tion.jda.api.events.guild.override.PermissionOverrideUpdateEvent; +import net.dv8tion.jda.api.events.guild.update.*; +import net.dv8tion.jda.api.events.guild.voice.GuildVoiceGuildDeafenEvent; +import net.dv8tion.jda.api.events.guild.voice.GuildVoiceGuildMuteEvent; +import net.dv8tion.jda.api.events.guild.voice.GuildVoiceJoinEvent; +import net.dv8tion.jda.api.events.guild.voice.GuildVoiceMoveEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent; +import net.dv8tion.jda.api.events.role.RoleCreateEvent; +import net.dv8tion.jda.api.events.role.RoleDeleteEvent; +import net.dv8tion.jda.api.events.role.update.*; +import net.dv8tion.jda.api.managers.ChannelManager; +import net.dv8tion.jda.api.managers.EmoteManager; +import net.dv8tion.jda.api.managers.GuildManager; +import net.dv8tion.jda.api.managers.RoleManager; +import net.dv8tion.jda.api.requests.RestAction; +import net.dv8tion.jda.api.requests.restaction.AuditableRestAction; +import net.dv8tion.jda.api.requests.restaction.ChannelAction; +import net.dv8tion.jda.api.requests.restaction.PermissionOverrideAction; +import net.dv8tion.jda.api.requests.restaction.RoleAction; +import net.dv8tion.jda.api.requests.restaction.order.OrderAction; +import net.dv8tion.jda.api.requests.restaction.order.RoleOrderAction; + +import java.awt.*; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; + +/** + * A utility class meant to serve as a way to rollback certain events where it makes sense to. + * + *
+ * All methods are overloaded static factory methods, always returning a {@link net.dv8tion.jda.api.requests.RestAction RestAction>} + * meant to "undo" the given event. Note that this will only be possible for events in which it makes sense. + * In events where something is posted, the inverse would be another request to remove said post, for example. + *
+ *+ * Also, since it's a RestAction that simply makes an attempt at the inverse, it's not always possible due to multiple + * factors, such as permissions, etc. For example, trying to invert a {@link net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent GuildMessageReceivedEvent} in a channel with no permission + * to remove messages will fail + *
+ *+ * Events fired when something is "created" like a {@link net.dv8tion.jda.api.events.guild.override.PermissionOverrideCreateEvent PermissionOverrideCreateEvent} + * can usually be logically inverted, by removing what was created. + *
+ * Events fired for the deletion of something are a different story. Some cases are logical, but many are not, like the + * removal of a text channel. Cases where the complete undoing of the event cannot be guaranteed are not implemented + *
+ *
+ * Keep in mind that inverting the deletion of something requires for a new object to be created with the same values.
+ * But doing this can't possibly copy information such as the ID of the deleted object or undo effects like everyone losing
+ * a role that is deleted
+ *
+ * @author HydroPage90
+ */
+public final class InverseAction
+{
+ public static RestAction> of(GenericEvent event)
+ {
+ if (event instanceof CategoryUpdatePositionEvent)
+ return inverse((CategoryUpdatePositionEvent) event);
+
+ else if (event instanceof CategoryUpdateNameEvent)
+ return inverse((CategoryUpdateNameEvent) event);
+
+ else if (event instanceof CategoryCreateEvent)
+ return inverse((CategoryCreateEvent) event);
+
+ else if (event instanceof GuildInviteCreateEvent)
+ return inverse((GuildInviteCreateEvent) event);
+
+ else if (event instanceof GuildJoinEvent)
+ return inverse((GuildJoinEvent) event);
+
+ else if (event instanceof GuildBanEvent)
+ return inverse((GuildBanEvent) event);
+
+ else if (event instanceof GuildUnbanEvent)
+ return inverse((GuildUnbanEvent) event);
+
+ else if (event instanceof GuildMemberRoleAddEvent)
+ return inverse((GuildMemberRoleAddEvent) event);
+
+ else if (event instanceof GuildMemberRoleRemoveEvent)
+ return inverse((GuildMemberRoleRemoveEvent) event);
+
+ else if (event instanceof GuildMemberUpdateNicknameEvent)
+ return inverse((GuildMemberUpdateNicknameEvent) event);
+
+ else if (event instanceof GuildUpdateVanityCodeEvent)
+ return inverse((GuildUpdateVanityCodeEvent) event);
+
+ else if (event instanceof GuildUpdateMFALevelEvent)
+ return inverse((GuildUpdateMFALevelEvent) event);
+
+ else if (event instanceof GuildUpdateSystemChannelEvent)
+ return inverse((GuildUpdateSystemChannelEvent) event);
+
+ else if (event instanceof GuildUpdateRegionEvent)
+ return inverse((GuildUpdateRegionEvent) event);
+
+ else if (event instanceof GuildUpdateNameEvent)
+ return inverse((GuildUpdateNameEvent) event);
+
+ else if (event instanceof GuildUpdateDescriptionEvent )
+ return inverse((GuildUpdateDescriptionEvent) event);
+
+ else if (event instanceof GuildUpdateExplicitContentLevelEvent)
+ return inverse((GuildUpdateExplicitContentLevelEvent) event);
+
+ else if (event instanceof GuildUpdateNotificationLevelEvent)
+ return inverse((GuildUpdateNotificationLevelEvent) event);
+
+ else if (event instanceof GuildUpdateVerificationLevelEvent)
+ return inverse((GuildUpdateVerificationLevelEvent) event);
+
+ else if (event instanceof GuildUpdateAfkTimeoutEvent)
+ return inverse((GuildUpdateAfkTimeoutEvent) event);
+
+ else if (event instanceof GuildUpdateAfkChannelEvent)
+ return inverse((GuildUpdateAfkChannelEvent) event);
+
+ else if (event instanceof GuildMemberJoinEvent)
+ return inverse((GuildMemberJoinEvent) event);
+
+ else if (event instanceof GuildVoiceGuildDeafenEvent)
+ return inverse((GuildVoiceGuildDeafenEvent) event);
+
+ else if (event instanceof GuildVoiceJoinEvent)
+ return inverse((GuildVoiceJoinEvent) event);
+
+ else if (event instanceof GuildVoiceMoveEvent)
+ return inverse((GuildVoiceMoveEvent) event);
+
+ else if (event instanceof GuildVoiceGuildMuteEvent)
+ return inverse((GuildVoiceGuildMuteEvent) event);
+
+ else if (event instanceof PermissionOverrideCreateEvent)
+ return inverse((PermissionOverrideCreateEvent) event);
+
+ else if (event instanceof PermissionOverrideDeleteEvent)
+ return inverse((PermissionOverrideDeleteEvent) event);
+
+ else if (event instanceof PermissionOverrideUpdateEvent)
+ return inverse((PermissionOverrideUpdateEvent) event);
+
+ else if (event instanceof EmoteAddedEvent)
+ return inverse((EmoteAddedEvent) event);
+
+ else if (event instanceof EmoteUpdateNameEvent)
+ return inverse((EmoteUpdateNameEvent) event);
+
+ else if (event instanceof EmoteUpdateRolesEvent)
+ return inverse((EmoteUpdateRolesEvent) event);
+
+ else if (event instanceof RoleCreateEvent)
+ return inverse((RoleCreateEvent) event);
+
+ else if (event instanceof RoleDeleteEvent)
+ return inverse((RoleDeleteEvent) event);
+
+ else if (event instanceof RoleUpdateMentionableEvent)
+ return inverse((RoleUpdateMentionableEvent) event);
+
+ else if (event instanceof RoleUpdatePositionEvent)
+ return inverse((RoleUpdatePositionEvent) event);
+
+ else if (event instanceof RoleUpdatePermissionsEvent)
+ return inverse((RoleUpdatePermissionsEvent) event);
+
+ else if (event instanceof RoleUpdateNameEvent)
+ return inverse((RoleUpdateNameEvent) event);
+
+ else if (event instanceof RoleUpdateHoistedEvent)
+ return inverse((RoleUpdateHoistedEvent) event);
+
+ else if (event instanceof RoleUpdateColorEvent)
+ return inverse((RoleUpdateColorEvent) event);
+
+ else if (event instanceof PrivateChannelCreateEvent)
+ return inverse((PrivateChannelCreateEvent) event);
+
+ else if (event instanceof VoiceChannelDeleteEvent)
+ return inverse((VoiceChannelDeleteEvent) event);
+
+ else if (event instanceof VoiceChannelCreateEvent)
+ return inverse((VoiceChannelCreateEvent) event);
+
+ else if (event instanceof VoiceChannelUpdateNameEvent)
+ return inverse((VoiceChannelUpdateNameEvent) event);
+
+ else if (event instanceof VoiceChannelUpdateParentEvent)
+ return inverse((VoiceChannelUpdateParentEvent) event);
+
+ else if (event instanceof VoiceChannelUpdatePositionEvent)
+ return inverse((VoiceChannelUpdatePositionEvent) event);
+
+ else if (event instanceof VoiceChannelUpdateBitrateEvent)
+ return inverse((VoiceChannelUpdateBitrateEvent) event);
+
+ else if (event instanceof VoiceChannelUpdateUserLimitEvent)
+ return inverse((VoiceChannelUpdateUserLimitEvent) event);
+
+ else if (event instanceof TextChannelCreateEvent)
+ return inverse((TextChannelCreateEvent) event);
+
+ else if (event instanceof TextChannelUpdateTopicEvent)
+ return inverse((TextChannelUpdateTopicEvent) event);
+
+ else if (event instanceof TextChannelUpdateNameEvent)
+ return inverse((TextChannelUpdateNameEvent) event);
+
+ else if (event instanceof TextChannelUpdateSlowmodeEvent)
+ return inverse((TextChannelUpdateSlowmodeEvent) event);
+
+ else if (event instanceof TextChannelUpdatePositionEvent)
+ return inverse((TextChannelUpdatePositionEvent) event);
+
+ else if (event instanceof TextChannelUpdateNSFWEvent)
+ return inverse((TextChannelUpdateNSFWEvent) event);
+
+ else if (event instanceof TextChannelUpdateParentEvent)
+ return inverse((TextChannelUpdateParentEvent) event);
+
+ else if (event instanceof MessageReactionAddEvent)
+ return inverse((MessageReactionAddEvent) event);
+
+ else if (event instanceof MessageReceivedEvent)
+ return inverse((MessageReceivedEvent) event);
+
+ else if (event instanceof StoreChannelUpdatePositionEvent)
+ return inverse((StoreChannelUpdatePositionEvent) event);
+
+ else if (event instanceof StoreChannelUpdateNameEvent)
+ return inverse((StoreChannelUpdateNameEvent) event);
+
+ else if (event instanceof StoreChannelCreateEvent)
+ return inverse((StoreChannelCreateEvent) event);
+
+ else
+ throw new InversionException("No possible inversion for event: " + event);
+ }
+
+ private static ChannelManager inverse(CategoryUpdatePositionEvent event)
+ {
+ ChannelManager manager = event.getCategory().getManager();
+ int oldPosition = event.getOldPosition();
+
+ return manager.setPosition(oldPosition);
+ }
+
+ private static ChannelManager inverse(CategoryUpdateNameEvent event)
+ {
+ ChannelManager manager = event.getCategory().getManager();
+ String oldName = event.getOldName();
+
+ return manager.setName(oldName);
+ }
+
+ private static AuditableRestAction