diff --git a/src/main/java/com/alttd/buttonManager/ButtonManager.java b/src/main/java/com/alttd/buttonManager/ButtonManager.java index 3ee151f..caf555e 100644 --- a/src/main/java/com/alttd/buttonManager/ButtonManager.java +++ b/src/main/java/com/alttd/buttonManager/ButtonManager.java @@ -3,20 +3,17 @@ package com.alttd.buttonManager; import com.alttd.buttonManager.buttons.autoReminder.ButtonAccepted; import com.alttd.buttonManager.buttons.autoReminder.ButtonInProgress; import com.alttd.buttonManager.buttons.autoReminder.ButtonRejected; +import com.alttd.buttonManager.buttons.eventButton.EventButton; import com.alttd.buttonManager.buttons.remindMeConfirm.ButtonRemindMeCancel; import com.alttd.buttonManager.buttons.remindMeConfirm.ButtonRemindMeConfirm; import com.alttd.buttonManager.buttons.suggestionReview.ButtonSuggestionReviewAccept; import com.alttd.buttonManager.buttons.suggestionReview.ButtonSuggestionReviewDeny; -import com.alttd.util.Util; -import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.interactions.components.buttons.Button; -import net.dv8tion.jda.api.requests.RestAction; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.awt.*; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -34,6 +31,7 @@ public class ButtonManager extends ListenerAdapter { buttons.add(new ButtonAccepted()); buttons.add(new ButtonInProgress()); buttons.add(new ButtonRejected()); + buttons.add(new EventButton()); } public void addButton(DiscordButton button) { diff --git a/src/main/java/com/alttd/buttonManager/buttons/eventButton/EventButton.java b/src/main/java/com/alttd/buttonManager/buttons/eventButton/EventButton.java new file mode 100644 index 0000000..981102f --- /dev/null +++ b/src/main/java/com/alttd/buttonManager/buttons/eventButton/EventButton.java @@ -0,0 +1,101 @@ +package com.alttd.buttonManager.buttons.eventButton; + +import com.alttd.AltitudeBot; +import com.alttd.buttonManager.DiscordButton; +import com.alttd.database.queries.events.Event; +import com.alttd.util.Logger; +import com.alttd.util.Util; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; +import net.dv8tion.jda.api.interactions.components.buttons.Button; + +import java.time.Instant; +import java.util.List; +import java.util.Optional; + +public class EventButton extends DiscordButton { + + public EventButton() { + } + + @Override + public String getButtonId() { + return "event_button"; + } + + @Override + public void execute(ButtonInteractionEvent event) { + Event eventForButton = Event.getEvent(event.getMessageIdLong()); + if (eventForButton == null) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "Event not found")).setEphemeral(true).queue(); + return; + } + + Member member = event.getMember(); + if (member == null) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "This button can only be used within a guild")).setEphemeral(true).queue(); + return; + } + + if (Instant.now().isAfter(eventForButton.getStartTime())) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to process you joining" + eventForButton.getTitle() + ", the event might have ended!")).setEphemeral(true).queue(); + return; + } + + Optional any = member.getRoles().stream().filter(role -> role.getIdLong() == eventForButton.getRoleId()).findAny(); + if (any.isPresent()) { + updateJoinedEventUsersInEmbed(eventForButton); + event.replyEmbeds(Util.genericSuccessEmbed("Success", "Removed you from " + eventForButton.getTitle() + "!")).setEphemeral(true).queue(); + try { + eventForButton.getRole().getGuild().removeRoleFromMember(member, eventForButton.getRole()).queue(); + } catch (Exception e) { + Logger.altitudeLogs.error(e); + } + return; + } + + try { + eventForButton.getRole().getGuild().addRoleToMember(member, eventForButton.getRole()).queue(); + } catch (Exception e) { + Logger.altitudeLogs.error(e); + } + if (updateJoinedEventUsersInEmbed(eventForButton)) { + event.replyEmbeds(Util.genericSuccessEmbed("Success", "You joined " + eventForButton.getTitle() + "!")).setEphemeral(true).queue(); + } else { + event.replyEmbeds(Util.genericErrorEmbed("Error", "Failed to add you to the event, contact an admin for help if needed")).setEphemeral(true).queue(); + } + } + + @Override + public Button getButton() { + return Button.primary(getButtonId(), "Join Event"); + } + + private boolean updateJoinedEventUsersInEmbed(Event event) { + Optional optionalMessage = event.getMessage(); + if (optionalMessage.isEmpty()) { + Logger.altitudeLogs.error("Unable to find event message"); + return false; + } + Message message = optionalMessage.get(); + List embeds = message.getEmbeds(); + if (embeds.isEmpty()) { + Logger.altitudeLogs.error("Unable to find event embed"); + return false; + } + + EmbedBuilder builder = new EmbedBuilder(embeds.get(0)); + builder.clearFields() + .addField("Event Start", "", true); + Guild guildById = AltitudeBot.getInstance().getJDA().getGuildById(event.getGuildId()); + if (guildById != null) { + List membersWithRole = guildById.getMembersWithRoles(event.getRole()); + builder.addField("Participants", String.valueOf(membersWithRole.size()), true); + } + MessageEmbed updatedEmbed = builder.build(); + message.editMessageEmbeds(updatedEmbed).queue(); + return true; + } + +} diff --git a/src/main/java/com/alttd/contextMenuManager/ContextMenuManager.java b/src/main/java/com/alttd/contextMenuManager/ContextMenuManager.java index 2d153ca..e6bf451 100644 --- a/src/main/java/com/alttd/contextMenuManager/ContextMenuManager.java +++ b/src/main/java/com/alttd/contextMenuManager/ContextMenuManager.java @@ -1,5 +1,6 @@ package com.alttd.contextMenuManager; +import com.alttd.contextMenuManager.contextMenus.ContextMenuCreateEvent; import com.alttd.contextMenuManager.contextMenus.ContextMenuForwardToKanboard; import com.alttd.contextMenuManager.contextMenus.ContextMenuRespondSuggestion; import com.alttd.modalManager.ModalManager; @@ -23,6 +24,7 @@ public class ContextMenuManager extends ListenerAdapter { public ContextMenuManager(ModalManager modalManager) { contextMenus = List.of( new ContextMenuRespondSuggestion(modalManager), + new ContextMenuCreateEvent(modalManager), new ContextMenuForwardToKanboard() ); } diff --git a/src/main/java/com/alttd/contextMenuManager/contextMenus/ContextMenuCreateEvent.java b/src/main/java/com/alttd/contextMenuManager/contextMenus/ContextMenuCreateEvent.java new file mode 100644 index 0000000..90fc379 --- /dev/null +++ b/src/main/java/com/alttd/contextMenuManager/contextMenus/ContextMenuCreateEvent.java @@ -0,0 +1,68 @@ +package com.alttd.contextMenuManager.contextMenus; + +import com.alttd.contextMenuManager.DiscordContextMenu; +import com.alttd.modalManager.ModalManager; +import com.alttd.modalManager.modals.ModalCreateEvent; +import com.alttd.util.Util; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent; +import net.dv8tion.jda.api.events.interaction.command.UserContextInteractionEvent; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; +import net.dv8tion.jda.api.interactions.commands.build.CommandData; +import net.dv8tion.jda.api.interactions.commands.build.Commands; +import net.dv8tion.jda.api.interactions.modals.Modal; +import net.dv8tion.jda.api.requests.RestAction; + +public class ContextMenuCreateEvent extends DiscordContextMenu { + + private final ModalManager modalManager; + + public ContextMenuCreateEvent(ModalManager modalManager) { + this.modalManager = modalManager; + } + + @Override + public String getContextMenuId() { + return "Create Event"; + } + + @Override + public void execute(UserContextInteractionEvent event) { + event.getInteraction().replyEmbeds(Util.genericErrorEmbed("Error", "This interaction should have been a message interaction")) + .setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure); + } + + @Override + public void execute(MessageContextInteractionEvent event) { + if (!event.isFromGuild()) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "This has to be done in a guild")) + .setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure); + return; + } + Message message = event.getInteraction().getTarget(); + + if (message.getChannel().getIdLong() != 1172922338023591956L || message.getAuthor().getIdLong() != event.getUser().getIdLong()) { + event.getInteraction().replyEmbeds(Util.genericErrorEmbed("Error", "You can only use this on your own community post")) + .setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure); + return; + } + + Modal createEvent = modalManager.getModalFor("create_event"); + if (createEvent == null) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to find create event modal")) + .setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure); + return; + } + + ModalCreateEvent.userToMessageTracker.putMessage(event.getUser().getIdLong(), message); //TODO find a better way to do this + event.replyModal(createEvent).queue(RestAction.getDefaultSuccess(), Util::handleFailure); + } + + @Override + public CommandData getUserContextInteraction() { + return Commands.message(getContextMenuId()) + .setGuildOnly(true) + .setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MESSAGE_SEND)); + } +} diff --git a/src/main/java/com/alttd/contextMenuManager/contextMenus/ContextMenuRespondSuggestion.java b/src/main/java/com/alttd/contextMenuManager/contextMenus/ContextMenuRespondSuggestion.java index 24cfe7d..0a3ac92 100644 --- a/src/main/java/com/alttd/contextMenuManager/contextMenus/ContextMenuRespondSuggestion.java +++ b/src/main/java/com/alttd/contextMenuManager/contextMenus/ContextMenuRespondSuggestion.java @@ -56,7 +56,7 @@ public class ContextMenuRespondSuggestion extends DiscordContextMenu { return; } - ModalReplySuggestion.putMessage(event.getUser().getIdLong(), message); //TODO find a better way to do this + ModalReplySuggestion.userToMessageTracker.putMessage(event.getUser().getIdLong(), message); //TODO find a better way to do this event.replyModal(replySuggestion).queue(RestAction.getDefaultSuccess(), Util::handleFailure); } diff --git a/src/main/java/com/alttd/database/DatabaseTables.java b/src/main/java/com/alttd/database/DatabaseTables.java index bdfa4da..ff19fc6 100644 --- a/src/main/java/com/alttd/database/DatabaseTables.java +++ b/src/main/java/com/alttd/database/DatabaseTables.java @@ -191,6 +191,24 @@ public class DatabaseTables { } } + private void createEventsTable() { + String sql = "CREATE TABLE IF NOT EXISTS events(" + + "message_id BIGINT NOT NULL, " + + "channel_id BIGINT NOT NULL, " + + "guild_id BIGINT NOT NULL, " + + "epoch_second BIGINT NOT NULL, " + + "role_id BIGINT NOT NULL," + + "title VARCHAR(128) NOT NULL, " + + "PRIMARY KEY (message_id)" + + ")"; + try { + connection.prepareStatement(sql).executeUpdate(); + } catch (SQLException e) { + Logger.altitudeLogs.error(e); + Logger.altitudeLogs.error("Unable to create auction settings table, shutting down..."); + } + } + public static void createTables(Connection connection) { if (instance == null) instance = new DatabaseTables(connection); diff --git a/src/main/java/com/alttd/database/queries/events/Event.java b/src/main/java/com/alttd/database/queries/events/Event.java new file mode 100644 index 0000000..a0582ad --- /dev/null +++ b/src/main/java/com/alttd/database/queries/events/Event.java @@ -0,0 +1,79 @@ +package com.alttd.database.queries.events; + +import com.alttd.AltitudeBot; +import com.alttd.util.Logger; +import lombok.Getter; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; + +import java.time.Instant; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Optional; + + +public final class Event { + + private static final HashMap eventMap = new HashMap<>(); + @Getter + private final long messageId, guildId, channelId, roleId; + @Getter + private final Instant startTime; + @Getter + private Role role = null; + @Getter + private final String title; + + + public static Event getEvent(long messageId) { + return eventMap.get(messageId); + } + + private Message message = null; + + public Event(long messageId, long guildId, long channelId, Instant startTime, long roleId, String title) { + this.messageId = messageId; + this.guildId = guildId; + this.channelId = channelId; + this.startTime = startTime; + this.roleId = roleId; + this.title = title; + + eventMap.put(messageId, this); + loadMessageAndRole(); + Logger.altitudeLogs.info(String.format("Loaded event with title [%s] and message id [%s]", title, messageId)); + } + + public static Optional getNextEvent() { + return eventMap.values().stream().min(Comparator.comparing(Event::getStartTime)); + } + + public static void removeEvent(Event event) { + eventMap.remove(event.getMessageId()); + } + + private void loadMessageAndRole() { + Guild guild = AltitudeBot.getInstance().getJDA().getGuildById(guildId); + if (guild == null) { + Logger.altitudeLogs.error(String.format("Unable to find guild %s when creating event", guildId)); + return; + } + TextChannel textChannel = guild.getTextChannelById(channelId); + if (textChannel == null) { + Logger.altitudeLogs.error(String.format("Unable to find text channel %s when creating event", channelId)); + return; + } + textChannel.retrieveMessageById(messageId).queue(message -> { + this.message = message; + Logger.altitudeLogs.debug(String.format("Loaded message for event with title [%s]", title)); + }); + role = guild.getRoleById(roleId); + } + + public Optional getMessage() { + return message == null ? Optional.empty() : Optional.of(message); + } + +}; diff --git a/src/main/java/com/alttd/database/queries/events/QueriesEvent.java b/src/main/java/com/alttd/database/queries/events/QueriesEvent.java new file mode 100644 index 0000000..38fe0d7 --- /dev/null +++ b/src/main/java/com/alttd/database/queries/events/QueriesEvent.java @@ -0,0 +1,59 @@ +package com.alttd.database.queries.events; + +import com.alttd.database.Database; +import com.alttd.util.Logger; +import net.dv8tion.jda.api.entities.Message; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.Instant; + +public class QueriesEvent { + + public void addEvent(Message message, Instant start, long roleId, String title) { + String sql = "INSERT INTO events VALUES(?, ?, ?, ?, ?, ?)"; + + try { + PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql); + + preparedStatement.setLong(1, message.getIdLong()); + preparedStatement.setLong(2, message.getChannelIdLong()); + preparedStatement.setLong(3, message.getGuildIdLong()); + preparedStatement.setLong(4, start.getEpochSecond()); + preparedStatement.setLong(5, roleId); + preparedStatement.setString(6, title); + + preparedStatement.executeUpdate(); + } catch (SQLException exception) { + Logger.altitudeLogs.error(exception); + } + } + + public void loadActiveEvents() { + String sql = "SELECT * FROM events WHERE epoch_second > ?"; + int counter = 0; + try { + PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql); + + preparedStatement.setLong(1, Instant.now().getEpochSecond()); + + ResultSet resultSet = preparedStatement.executeQuery(); + while (resultSet.next()) { + new Event( + resultSet.getLong("message_id"), + resultSet.getLong("guild_id"), + resultSet.getLong("channel_id"), + Instant.ofEpochSecond(resultSet.getLong("epoch_second")), + resultSet.getLong("role_id"), + resultSet.getString("title") + ); + counter++; + } + } catch (SQLException exception) { + Logger.altitudeLogs.error(exception); + } + Logger.altitudeLogs.info(String.format("Loaded %d events", counter)); + } + +} diff --git a/src/main/java/com/alttd/listeners/JDAListener.java b/src/main/java/com/alttd/listeners/JDAListener.java index b67e340..7f90577 100644 --- a/src/main/java/com/alttd/listeners/JDAListener.java +++ b/src/main/java/com/alttd/listeners/JDAListener.java @@ -5,8 +5,10 @@ import com.alttd.buttonManager.ButtonManager; import com.alttd.commandManager.CommandManager; import com.alttd.contextMenuManager.ContextMenuManager; import com.alttd.database.queries.Poll.PollQueries; +import com.alttd.database.queries.events.QueriesEvent; import com.alttd.modalManager.ModalManager; import com.alttd.schedulers.AuctionScheduler; +import com.alttd.schedulers.EventTimerTask; import com.alttd.schedulers.PollTimerTask; import com.alttd.schedulers.ReminderScheduler; import com.alttd.request.RequestManager; @@ -49,6 +51,8 @@ public class JDAListener extends ListenerAdapter { jda.addEventListener(buttonManager, tagAdded, modalManager, commandManager, contextMenuManager, lockedChannel, appealRepost, selectMenuManager); PollQueries.loadPolls(buttonManager); new Timer().scheduleAtFixedRate(new PollTimerTask(jda, Logger.altitudeLogs), TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(5)); + new QueriesEvent().loadActiveEvents(); + new Timer().scheduleAtFixedRate(new EventTimerTask(), TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(1)); startSchedulers(); // RequestManager.init(); // Logger.altitudeLogs.info("Starting spring application"); diff --git a/src/main/java/com/alttd/modalManager/ModalManager.java b/src/main/java/com/alttd/modalManager/ModalManager.java index 38ca225..619d4be 100644 --- a/src/main/java/com/alttd/modalManager/ModalManager.java +++ b/src/main/java/com/alttd/modalManager/ModalManager.java @@ -2,16 +2,12 @@ package com.alttd.modalManager; import com.alttd.buttonManager.ButtonManager; import com.alttd.modalManager.modals.*; -import com.alttd.util.Util; -import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.interactions.modals.Modal; -import net.dv8tion.jda.api.requests.RestAction; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.awt.*; import java.util.List; import java.util.Optional; @@ -25,7 +21,8 @@ public class ModalManager extends ListenerAdapter { new ModalEvidence(), new ModalReplySuggestion(), new ModalRemindMe(buttonManager), - new ModalCrateItem()); + new ModalCrateItem(), + new ModalCreateEvent(buttonManager)); } @Override diff --git a/src/main/java/com/alttd/modalManager/modals/ModalCreateEvent.java b/src/main/java/com/alttd/modalManager/modals/ModalCreateEvent.java new file mode 100644 index 0000000..96c1766 --- /dev/null +++ b/src/main/java/com/alttd/modalManager/modals/ModalCreateEvent.java @@ -0,0 +1,150 @@ +package com.alttd.modalManager.modals; + +import com.alttd.buttonManager.ButtonManager; +import com.alttd.database.queries.events.Event; +import com.alttd.database.queries.events.QueriesEvent; +import com.alttd.modalManager.DiscordModal; +import com.alttd.util.UserToMessageTracker; +import com.alttd.util.Util; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent; +import net.dv8tion.jda.api.interactions.components.ActionRow; +import net.dv8tion.jda.api.interactions.components.buttons.Button; +import net.dv8tion.jda.api.interactions.components.text.TextInput; +import net.dv8tion.jda.api.interactions.components.text.TextInputStyle; +import net.dv8tion.jda.api.interactions.modals.Modal; +import net.dv8tion.jda.api.interactions.modals.ModalMapping; +import net.dv8tion.jda.api.requests.RestAction; +import net.dv8tion.jda.api.requests.restaction.RoleAction; +import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction; +import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; +import net.dv8tion.jda.api.utils.messages.MessageCreateData; + +import java.awt.*; +import java.time.Instant; +import java.util.Random; +import java.util.stream.Collectors; + +public class ModalCreateEvent extends DiscordModal { + + public static final UserToMessageTracker userToMessageTracker = new UserToMessageTracker(); + private final ButtonManager buttonManager; + + public ModalCreateEvent(ButtonManager buttonManager) { + this.buttonManager = buttonManager; + } + + @Override + public String getModalId() { + return "create_event"; + } + + @Override + public void execute(ModalInteractionEvent event) { + ModalMapping titleModalMapping = event.getInteraction().getValue("title"); + ModalMapping timeModalMapping = event.getInteraction().getValue("time"); + if (titleModalMapping == null || timeModalMapping == null) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to find time or title in modal")) + .setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure); + return; + } + + String title = titleModalMapping.getAsString(); + String time = timeModalMapping.getAsString(); + if (title.isEmpty() || time.isEmpty()) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "Response in modal is empty")) + .setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure); + return; + } + + Instant eventStart; + try { + eventStart = Instant.ofEpochSecond(Long.parseLong(time)); + } catch (NumberFormatException e) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "Invalid time format, try again")) + .setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure); + return; + } + + Member member = event.getMember(); + if (member == null) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "This modal only works from within a guild")) + .setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure); + return; + } + + Message message = userToMessageTracker.pullMessage(member.getIdLong()); + if (message == null) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "No message found to create an event from")) + .setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure); + return; + } + + MessageEmbed messageEmbed = new EmbedBuilder() + .setTitle(title) + .addField("Event Start", "", true) + .addField("Participants", "0", true) + .setFooter("Click the join button to be notified when the event starts") + .setColor(Color.GREEN) + .build(); + + Button eventButton = buttonManager.getButtonFor("event_button"); + + try (MessageCreateData build = new MessageCreateBuilder() + .setEmbeds(messageEmbed) + .setActionRow(eventButton) + .build()) { + + Guild guild = message.getGuild(); + ReplyCallbackAction replyCallbackAction = event.deferReply(true); + createRole(guild).queue(role -> { + message.reply(build).queue(newMessage -> { + new QueriesEvent().addEvent(newMessage, eventStart, role.getIdLong(), title); + new Event(newMessage.getIdLong(), newMessage.getGuildIdLong(), newMessage.getChannelIdLong(), eventStart, role.getIdLong(), title); + }); + replyCallbackAction.setEmbeds(Util.genericSuccessEmbed("Success", "Your event has been created")).queue(); + }, failed -> { + replyCallbackAction.setEmbeds(Util.genericErrorEmbed("Error", "Unable to create event")).queue(); + }); + } + } + + private RoleAction createRole(Guild guild) { + String possibleCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + Random rand = new Random(); + String randomStr = rand.ints(5, 0, possibleCharacters.length()) + .mapToObj(i -> possibleCharacters.charAt(i) + "") + .collect(Collectors.joining()); + + return guild.createRole().setName("event role " + randomStr) + .setMentionable(false) + .setHoisted(false); + } + + @Override + public Modal getModal() { + String currentTimestamp = String.valueOf(Instant.now().getEpochSecond()); + TextInput time = TextInput.create("time", "Epoch time, see https://epochconverter.com/", TextInputStyle.SHORT) + .setPlaceholder(currentTimestamp) + .setMinLength(currentTimestamp.length()) + .setMaxLength(currentTimestamp.length() + 1) + .setRequired(true) + .build(); + + TextInput title = TextInput.create("title", "Event title", TextInputStyle.SHORT) + .setPlaceholder("The title for your event") + .setMinLength(5) + .setMaxLength(128) + .setRequired(true) + .build(); + + return Modal.create(getModalId(), "Create an event") + .addComponents(ActionRow.of(title), ActionRow.of(time)) + .build(); + } +} diff --git a/src/main/java/com/alttd/modalManager/modals/ModalReplySuggestion.java b/src/main/java/com/alttd/modalManager/modals/ModalReplySuggestion.java index 1409ba0..3b30042 100644 --- a/src/main/java/com/alttd/modalManager/modals/ModalReplySuggestion.java +++ b/src/main/java/com/alttd/modalManager/modals/ModalReplySuggestion.java @@ -1,6 +1,7 @@ package com.alttd.modalManager.modals; import com.alttd.modalManager.DiscordModal; +import com.alttd.util.UserToMessageTracker; import com.alttd.util.Util; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; @@ -11,19 +12,9 @@ import net.dv8tion.jda.api.interactions.components.text.TextInputStyle; import net.dv8tion.jda.api.interactions.modals.ModalMapping; import net.dv8tion.jda.api.requests.RestAction; -import java.util.HashMap; - public class ModalReplySuggestion extends DiscordModal { - private static final HashMap userToMessageMap = new HashMap<>(); - - public static synchronized void putMessage(long userId, Message message) { - userToMessageMap.put(userId, message); - } - - private static synchronized Message pullMessage(long userId) { - return userToMessageMap.remove(userId); - } + public final static UserToMessageTracker userToMessageTracker = new UserToMessageTracker(); @Override public String getModalId() { @@ -53,7 +44,7 @@ public class ModalReplySuggestion extends DiscordModal { return; } - Message message = pullMessage(member.getIdLong()); + Message message = userToMessageTracker.pullMessage(member.getIdLong()); if (message == null) { event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to find a message for this modal")) .setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure); diff --git a/src/main/java/com/alttd/schedulers/EventTimerTask.java b/src/main/java/com/alttd/schedulers/EventTimerTask.java new file mode 100644 index 0000000..920426e --- /dev/null +++ b/src/main/java/com/alttd/schedulers/EventTimerTask.java @@ -0,0 +1,45 @@ +package com.alttd.schedulers; + +import com.alttd.database.queries.events.Event; +import com.alttd.util.Logger; +import net.dv8tion.jda.api.entities.Message; + +import java.time.Instant; +import java.util.Optional; +import java.util.TimerTask; +import java.util.concurrent.TimeUnit; + +public class EventTimerTask extends TimerTask { + @Override + public void run() { + checkShouldStartEvent(); + } + + private void checkShouldStartEvent(){ + Optional nextEvent = Event.getNextEvent(); + if (nextEvent.isEmpty()) { + return; + } + Event event = nextEvent.get(); + if (event.getStartTime().isAfter(Instant.now())) { + return; + } + + Event.removeEvent(event); + performEventAction(event); + event.getRole().delete().queueAfter(1, TimeUnit.HOURS); + checkShouldStartEvent(); + } + + private void performEventAction(Event event) { + Optional optionalMessage = event.getMessage(); + if (optionalMessage.isEmpty()) { + Logger.altitudeLogs.error("Unable to find message for event"); + return; + } + + Message message = optionalMessage.get(); + + message.reply(String.format("%s [%s] is starting!", event.getRole().getAsMention(), event.getTitle())).queue(); + } +} diff --git a/src/main/java/com/alttd/util/UserToMessageTracker.java b/src/main/java/com/alttd/util/UserToMessageTracker.java new file mode 100644 index 0000000..bd1438e --- /dev/null +++ b/src/main/java/com/alttd/util/UserToMessageTracker.java @@ -0,0 +1,19 @@ +package com.alttd.util; + +import net.dv8tion.jda.api.entities.Message; + +import java.util.HashMap; + +public class UserToMessageTracker { + + private final HashMap userToMessageMap = new HashMap<>(); + + public synchronized void putMessage(long userId, Message message) { + userToMessageMap.put(userId, message); + } + + public synchronized Message pullMessage(long userId) { + return userToMessageMap.remove(userId); + } + +}