finish abstraction for StepTask
This commit is contained in:
1 parent
f01c48c61c
commit
3466fb536d
29 files changed
+725
-133
No files matched your search
@@ -12,6 +12,8 @@ import me.bobert.netneutrality.core.command.options.CommandOptionsBuilder;
|
||||
import me.bobert.netneutrality.core.context.CommandContext;
|
||||
import me.bobert.netneutrality.core.tasks.TaskManager;
|
||||
import me.bobert.netneutrality.tasks.emoji.EmojiReactionRoleTask;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
|
||||
import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
|
||||
@@ -19,6 +21,8 @@ import net.dv8tion.jda.api.interactions.commands.build.SubcommandGroupData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ReactionCommand extends AbstractAdminCommand {
|
||||
|
||||
@@ -74,7 +78,7 @@ public class ReactionCommand extends AbstractAdminCommand {
|
||||
|
||||
@Override
|
||||
public CommandExecutionResult execute(CommandContext context) {
|
||||
context.ack();
|
||||
context.ephemeral();
|
||||
|
||||
String guildId = context.getGuild().getId();
|
||||
String messageId = context.getOption("messageid", CommandOption::getAsString);
|
||||
@@ -102,25 +106,31 @@ public class ReactionCommand extends AbstractAdminCommand {
|
||||
builder.append("I have found the following tasks for this guild:");
|
||||
|
||||
for (EmojiReactionRoleTask item : tasks) {
|
||||
Map<String, String> mapping = item.getEmojiMapping().entrySet().stream()
|
||||
.map(entry -> {
|
||||
Role role = context.getGuild().getRoleById(entry.getValue());
|
||||
return role != null ? Map.entry(entry.getKey(), role.getAsMention()) : null;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
|
||||
builder.append("\n- Task ID: ").append(item.getId()).append("\n")
|
||||
.append(" Message ID: ").append(item.getMessageId()).append("\n")
|
||||
.append(" Emoji Mapping: ").append(item.getEmojiMapping()).append("\n");
|
||||
.append(" Message: ")
|
||||
.append(String.format(Message.JUMP_URL, item.getGuildId(), item.getChannelId(), item.getMessageId()))
|
||||
.append("\n")
|
||||
.append(" Emoji Mappings:\n");
|
||||
|
||||
if (mapping.isEmpty()) {
|
||||
builder.append(" No emoji mappings found\n");
|
||||
} else {
|
||||
mapping.forEach((emoji, roleMention) ->
|
||||
builder.append(" - ").append(emoji).append(" → ").append(roleMention).append("\n")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return CommandExecutionResult.success(builder.toString());
|
||||
}
|
||||
case "setup" -> {
|
||||
if (task != null) {
|
||||
return CommandExecutionResult.error("The message ID is already registered, use the add subcommand instead.");
|
||||
}
|
||||
|
||||
String emoji = context.getOption("emoji", CommandOption::getAsString);
|
||||
String role = context.getOption("role", CommandOption::getAsString);
|
||||
task = new EmojiReactionRoleTask(guildId, messageId, Map.of(emoji, role));
|
||||
task.insert(context);
|
||||
|
||||
return CommandExecutionResult.success("Added emoji to message successfully!");
|
||||
}
|
||||
case "add" -> {
|
||||
if (task == null) {
|
||||
return CommandExecutionResult.error("The message ID provided isn't registered with the bot");
|
||||
@@ -129,7 +139,6 @@ public class ReactionCommand extends AbstractAdminCommand {
|
||||
String emoji = context.getOption("emoji", CommandOption::getAsString);
|
||||
String role = context.getOption("role", CommandOption::getAsString);
|
||||
task.addEmoji(emoji, role);
|
||||
task.save();
|
||||
return CommandExecutionResult.success("Added emoji to message successfully!");
|
||||
}
|
||||
case "remove" -> {
|
||||
@@ -140,7 +149,6 @@ public class ReactionCommand extends AbstractAdminCommand {
|
||||
}
|
||||
|
||||
task.removeEmoji(emoji);
|
||||
task.save();
|
||||
return CommandExecutionResult.success("Removed emoji from message successfully!");
|
||||
}
|
||||
case "delete" -> {
|
||||
|
||||
@@ -14,7 +14,6 @@ import me.bobert.netneutrality.music.MusicManager;
|
||||
import me.bobert.netneutrality.utils.MessageFunction;
|
||||
import me.bobert.netneutrality.utils.MusicUtils;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
|
||||
import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
|
||||
@@ -26,6 +25,11 @@ public class QueueCommand extends AbstractMusicCommand {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needAdmin() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return "queue";
|
||||
@@ -52,11 +56,6 @@ public class QueueCommand extends AbstractMusicCommand {
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultMemberPermissions getSlashCommandPermission() {
|
||||
return DefaultMemberPermissions.DISABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandExecutionResult execute(CommandContext context) {
|
||||
MusicManager manager = MusicManager.get(context.getGuild());
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package me.bobert.netneutrality.command.react;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.command.AbstractMessageMenuCommand;
|
||||
import me.bobert.netneutrality.core.command.CommandExecutionResult;
|
||||
import me.bobert.netneutrality.core.context.CommandContext;
|
||||
import me.bobert.netneutrality.core.tasks.TaskManager;
|
||||
import me.bobert.netneutrality.tasks.emoji.EmojiReactionRoleTask;
|
||||
import me.bobert.netneutrality.tasks.reaction.EmojiRoleFirstStep;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
public class CreateEmojiReaction extends AbstractMessageMenuCommand {
|
||||
@Override
|
||||
public CommandExecutionResult execute(Message target, CommandContext context) {
|
||||
EmojiReactionRoleTask task = TaskManager.getInstance().findTaskByPartialId(EmojiReactionRoleTask.class, target.getId()).orElse(null);
|
||||
|
||||
if (task != null) {
|
||||
context.replyEphemeral("This message is already registered with the bot, please use the modify command instead");
|
||||
return CommandExecutionResult.none();
|
||||
}
|
||||
|
||||
return CommandExecutionResult.task(new EmojiRoleFirstStep(target));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needAdmin() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return "Create emoji role mapping";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package me.bobert.netneutrality.command.react;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.command.AbstractMessageMenuCommand;
|
||||
import me.bobert.netneutrality.core.command.CommandExecutionResult;
|
||||
import me.bobert.netneutrality.core.context.CommandContext;
|
||||
import me.bobert.netneutrality.core.tasks.TaskManager;
|
||||
import me.bobert.netneutrality.tasks.emoji.EmojiReactionRoleTask;
|
||||
import me.bobert.netneutrality.tasks.reaction.EmojiRoleModify;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
public class ModifyEmojiReaction extends AbstractMessageMenuCommand {
|
||||
|
||||
@Override
|
||||
public CommandExecutionResult execute(Message target, CommandContext context) {
|
||||
EmojiReactionRoleTask task = TaskManager.getInstance().findTaskByPartialId(EmojiReactionRoleTask.class, target.getId()).orElse(null);
|
||||
if (task == null) {
|
||||
context.replyEphemeral("This message is not registered with the bot, please use the create command instead");
|
||||
return CommandExecutionResult.none();
|
||||
}
|
||||
|
||||
return CommandExecutionResult.task(new EmojiRoleModify(target, task));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needAdmin() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return "Modify emoji role mapping";
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,7 @@ public class MessageTaskContext extends TaskContext implements MessageContext {
|
||||
@Override
|
||||
public void replyEphemeral(MessageCreateData messageCreateData) {
|
||||
if (getType() == ChannelType.PRIVATE) {
|
||||
reply(messageCreateData);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@ package me.bobert.netneutrality.core.command;
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
|
||||
|
||||
public abstract class AbstractAdminCommand extends AbstractCommand {
|
||||
|
||||
@Override
|
||||
@@ -14,11 +12,6 @@ public abstract class AbstractAdminCommand extends AbstractCommand {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultMemberPermissions getSlashCommandPermission() {
|
||||
return DefaultMemberPermissions.DISABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandCategory getCategory() {
|
||||
return CommandCategory.ADMINISTRATION;
|
||||
|
||||
@@ -24,6 +24,10 @@ public abstract class AbstractCommand implements Command {
|
||||
|
||||
@Override
|
||||
public DefaultMemberPermissions getSlashCommandPermission() {
|
||||
if (needAdmin()) {
|
||||
return DefaultMemberPermissions.DISABLED;
|
||||
}
|
||||
|
||||
return DefaultMemberPermissions.ENABLED;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,13 +15,13 @@ public class CommandExecutionResult {
|
||||
|
||||
private final Result result;
|
||||
private final String message;
|
||||
private final Object data;
|
||||
private final Task task;
|
||||
private final Exception exception;
|
||||
|
||||
private CommandExecutionResult(Result result, String message, Object data, Exception exception) {
|
||||
private CommandExecutionResult(Result result, String message, Task task, Exception exception) {
|
||||
this.result = result;
|
||||
this.message = message;
|
||||
this.data = data;
|
||||
this.task = task;
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
@@ -33,10 +33,6 @@ public class CommandExecutionResult {
|
||||
this(result, message, null);
|
||||
}
|
||||
|
||||
private CommandExecutionResult(Result result, Object data) {
|
||||
this(result, null, data, null);
|
||||
}
|
||||
|
||||
public Result getResult() {
|
||||
return result;
|
||||
}
|
||||
@@ -45,8 +41,8 @@ public class CommandExecutionResult {
|
||||
return message;
|
||||
}
|
||||
|
||||
public Object getData() {
|
||||
return data;
|
||||
public Task getTask() {
|
||||
return task;
|
||||
}
|
||||
|
||||
public Exception getException() {
|
||||
|
||||
@@ -98,7 +98,7 @@ public class CommandProcessor {
|
||||
}
|
||||
|
||||
if (result == TASK) {
|
||||
TaskManager.getInstance().insert(context, (Task) commandExecutionResult.getData());
|
||||
TaskManager.getInstance().insert(context, commandExecutionResult.getTask());
|
||||
}
|
||||
|
||||
String message = commandExecutionResult.getMessage();
|
||||
|
||||
@@ -17,11 +17,6 @@ public abstract class AbstractTask implements Task {
|
||||
creationTime = OffsetDateTime.now();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInsertable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OffsetDateTime getCreationTime() {
|
||||
return creationTime;
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
package me.bobert.netneutrality.core.tasks;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
public interface IStepTask {
|
||||
|
||||
/**
|
||||
* Defines the type of input expected for a step.
|
||||
*/
|
||||
enum StepType {
|
||||
/**
|
||||
* Expects a string input from the user.
|
||||
*/
|
||||
STRING,
|
||||
|
||||
/**
|
||||
* Expects a valid role ID for the current guild.
|
||||
* The role must exist in the guild where the command was executed.
|
||||
*/
|
||||
ROLE,
|
||||
|
||||
/**
|
||||
* Expects a valid emoji.
|
||||
*/
|
||||
EMOJI
|
||||
}
|
||||
|
||||
class StepResult {
|
||||
private enum ResultType {
|
||||
SUCCESS, FAILURE
|
||||
}
|
||||
|
||||
private final ResultType type;
|
||||
private final String message;
|
||||
private final Task nextStep;
|
||||
|
||||
/**
|
||||
* Represents the result of a step execution. Each step can either succeed, fail, or transition to another step.
|
||||
*/
|
||||
private StepResult(ResultType type, String message, Task nextStep) {
|
||||
this.type = type;
|
||||
this.message = message;
|
||||
this.nextStep = nextStep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the step was completed successfully, with an optional follow-up step.
|
||||
*
|
||||
* @param message the success message
|
||||
* @param nextStep the next step in the workflow, or null if this is the final step
|
||||
* @return a successful result
|
||||
*/
|
||||
public static StepResult success(String message, Task nextStep) {
|
||||
return new StepResult(ResultType.SUCCESS, message, nextStep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the step was completed successfully.
|
||||
*
|
||||
* @param message the success message
|
||||
* @return a successful result without a next step
|
||||
*/
|
||||
public static StepResult success(String message) {
|
||||
return new StepResult(ResultType.SUCCESS, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the step has failed.
|
||||
*
|
||||
* @param message the failure message
|
||||
* @return a failed result
|
||||
*/
|
||||
public static StepResult failure(String message) {
|
||||
return new StepResult(ResultType.FAILURE, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves directly to the next step without displaying a message.
|
||||
*
|
||||
* @param nextTask the next task in the workflow
|
||||
* @return a successful result that advances to the next step
|
||||
*/
|
||||
public static StepResult next(Task nextTask) {
|
||||
return new StepResult(ResultType.SUCCESS, null, nextTask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the message associated with the step result.
|
||||
*
|
||||
* @return the result message, or null if there is no message
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next step in the task workflow.
|
||||
*
|
||||
* @return the next step, or null if this is the last step
|
||||
*/
|
||||
public Task getNextStep() {
|
||||
return nextStep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the step execution was successful.
|
||||
*
|
||||
* @return true if the step was successful, false otherwise
|
||||
*/
|
||||
public boolean isSuccess() {
|
||||
return type == ResultType.SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of step input expected.
|
||||
*
|
||||
* @return the step type
|
||||
*/
|
||||
StepType getStepType();
|
||||
|
||||
/**
|
||||
* Provides a general description of the step. This will be displayed before asking the question.
|
||||
*
|
||||
* @return the step description
|
||||
*/
|
||||
String getStepDescription();
|
||||
|
||||
/**
|
||||
* Provides the specific question for this step.
|
||||
*
|
||||
* @return the step question
|
||||
*/
|
||||
String getStepQuestion();
|
||||
|
||||
/**
|
||||
* Executes the step using the provided answer.
|
||||
*
|
||||
* @param answer the user's input, validated against the expected step type
|
||||
* @return the result of executing this step
|
||||
*/
|
||||
StepResult executeStep(Object answer);
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import me.bobert.netneutrality.core.LogHandler;
|
||||
import me.bobert.netneutrality.core.context.CommandContext;
|
||||
import me.bobert.netneutrality.core.context.InteractionContext;
|
||||
import me.bobert.netneutrality.core.context.TaskContext;
|
||||
import me.bobert.netneutrality.core.tasks.impl.StepTask;
|
||||
import me.bobert.netneutrality.core.tasks.trait.Deletable;
|
||||
import me.bobert.netneutrality.core.tasks.trait.NotAcknowledgeable;
|
||||
import me.bobert.netneutrality.core.tasks.trait.WithChildren;
|
||||
@@ -81,10 +80,6 @@ public class TaskManager {
|
||||
return tasks.values();
|
||||
}
|
||||
|
||||
public synchronized Collection<Task> getPendingTasks() {
|
||||
return pendingTasks;
|
||||
}
|
||||
|
||||
public void insert(CommandContext context, Task task) {
|
||||
String id = task.getId();
|
||||
|
||||
@@ -102,7 +97,7 @@ public class TaskManager {
|
||||
taskService.persistTask(persistableTask);
|
||||
}
|
||||
|
||||
if (task instanceof StepTask) {
|
||||
if (task instanceof IStepTask) {
|
||||
pendingTasks.add(task);
|
||||
} else {
|
||||
tasks.put(id, task);
|
||||
@@ -116,7 +111,7 @@ public class TaskManager {
|
||||
if (task instanceof WithChildren taskWithChildren) {
|
||||
List<Task> childrens = taskWithChildren.getChildTasks();
|
||||
if (childrens == null || childrens.isEmpty()) {
|
||||
logger.warn("Task [{}]: parent task doesn't create any childs", task.getId());
|
||||
logger.warn("Parent task '{}' doesn't create any childs", task.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -126,22 +121,25 @@ public class TaskManager {
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void activateTask(Task task) {
|
||||
public void activateTask(Task task, String oldId) {
|
||||
if (pendingTasks.remove(task)) {
|
||||
tasks.put(task.getId(), task);
|
||||
logger.info("Updating task {} with new id: {}", task.getName(), task.getId());
|
||||
logger.info("Updating task {} with new id: {} (was: {})",
|
||||
task.getName(), task.getId(), oldId);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void removeTask(Task task) {
|
||||
public void removeTask(Task task) {
|
||||
String id = task.getId();
|
||||
|
||||
if (tasks.containsKey(id)) {
|
||||
logger.debug("Removing task: {}", task);
|
||||
tasks.remove(id);
|
||||
}
|
||||
if (tasks.remove(id) != null) {
|
||||
logger.debug("Removing task: {}", id);
|
||||
|
||||
tasksLock.remove(task.getLockId());
|
||||
ReentrantLock lock = tasksLock.remove(task.getLockId());
|
||||
if (lock != null) {
|
||||
logger.debug("Cleaning up lock for removed task: {}", task.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handle(TaskContext context) {
|
||||
@@ -166,15 +164,15 @@ public class TaskManager {
|
||||
if (lock != null) {
|
||||
logger.debug("Aquiring lock for task: {}", taskId);
|
||||
lock.lock();
|
||||
logger.debug("Aquired lock for: {}", lockId);
|
||||
|
||||
if (!tasks.containsKey(taskId)) {
|
||||
logger.debug("Task {} is no longer available after aquiring lock", taskId);
|
||||
tasksLock.remove(lockId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug("Executing task: {}", task);
|
||||
logger.debug("Executing task: {}", taskId);
|
||||
Task.Lifecycle status = task.execute(context);
|
||||
handleTaskLifecycle(task, status);
|
||||
|
||||
@@ -201,6 +199,11 @@ public class TaskManager {
|
||||
}
|
||||
}
|
||||
|
||||
public <E extends Task> Optional<E> findTaskByPartialId(Class<E> clazz, String partialId) {
|
||||
List<E> tasks = findTasksByPartialId(clazz, partialId);
|
||||
return Optional.ofNullable(tasks.isEmpty() ? null : tasks.get(0));
|
||||
}
|
||||
|
||||
public <E extends Task> List<E> findTasksByPartialId(Class<E> clazz, String partialId) {
|
||||
return tasks.values().stream()
|
||||
.filter(clazz::isInstance)
|
||||
|
||||
@@ -6,10 +6,14 @@ package me.bobert.netneutrality.core.tasks.impl;
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.tasks.GenericRandomIdTask;
|
||||
import me.bobert.netneutrality.core.tasks.Task;
|
||||
import me.bobert.netneutrality.core.tasks.trait.WithChildren;
|
||||
import net.dv8tion.jda.api.interactions.components.ActionRow;
|
||||
import net.dv8tion.jda.api.interactions.components.buttons.Button;
|
||||
import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ButtonTask extends GenericRandomIdTask {
|
||||
private final ButtonStyle buttonStyle;
|
||||
@@ -33,4 +37,17 @@ public abstract class ButtonTask extends GenericRandomIdTask {
|
||||
public boolean isExpired() {
|
||||
return getCreationTime().plusMinutes(15).isBefore(OffsetDateTime.now());
|
||||
}
|
||||
|
||||
public ActionRow createActionRow(List<Task> tasks) {
|
||||
ActionRow row = ActionRow.of(tasks.stream().map(Task::createButton).toList());
|
||||
if (this instanceof WithChildren parent) {
|
||||
parent.addChild(tasks);
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
public ActionRow createActionRow(Task... tasks) {
|
||||
return createActionRow(List.of(tasks));
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,12 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
public abstract class EmojiTask extends AbstractPersistableTask {
|
||||
private final Map<String, String> emojiMapping = new ConcurrentHashMap<>();
|
||||
private final String guildId;
|
||||
private final String channelId;
|
||||
private final String messageId;
|
||||
|
||||
public EmojiTask(String guildId, String messageId) {
|
||||
public EmojiTask(String guildId, String channelId, String messageId) {
|
||||
this.guildId = guildId;
|
||||
this.channelId = channelId;
|
||||
this.messageId = messageId;
|
||||
}
|
||||
|
||||
@@ -26,16 +28,22 @@ public abstract class EmojiTask extends AbstractPersistableTask {
|
||||
return guildId;
|
||||
}
|
||||
|
||||
public String getChannelId() {
|
||||
return channelId;
|
||||
}
|
||||
|
||||
public String getMessageId() {
|
||||
return messageId;
|
||||
}
|
||||
|
||||
public void addEmoji(String emoji, String snowflake) {
|
||||
emojiMapping.put(emoji, snowflake);
|
||||
save();
|
||||
}
|
||||
|
||||
public void removeEmoji(String emoji) {
|
||||
emojiMapping.remove(emoji);
|
||||
save();
|
||||
}
|
||||
|
||||
public Map<String, String> getEmojiMapping() {
|
||||
|
||||
@@ -10,23 +10,26 @@ import me.bobert.netneutrality.core.context.CommandContext;
|
||||
import me.bobert.netneutrality.core.context.MessageContext;
|
||||
import me.bobert.netneutrality.core.context.TaskContext;
|
||||
import me.bobert.netneutrality.core.tasks.AbstractTask;
|
||||
import me.bobert.netneutrality.core.tasks.IStepTask;
|
||||
import me.bobert.netneutrality.core.tasks.TaskManager;
|
||||
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.interactions.components.buttons.Button;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import net.fellbaum.jemoji.Emoji;
|
||||
import net.fellbaum.jemoji.EmojiManager;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class StepTask extends AbstractTask {
|
||||
private static final Logger logger = LoggerFactory.getLogger(StepTask.class);
|
||||
|
||||
public enum StepType {
|
||||
STRING, ROLE, EMOJI
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a task that consists of multiple sequential steps. The task starts with an initial message (question)
|
||||
* and expects a user response. Each step can lead to another step, forming a workflow.
|
||||
*/
|
||||
public abstract class StepTask extends AbstractTask implements IStepTask {
|
||||
private final Object stepLock = new Object();
|
||||
private CommandContext commandContext;
|
||||
private Guild guild;
|
||||
private String id = UUID.randomUUID().toString();
|
||||
|
||||
@@ -35,45 +38,76 @@ public abstract class StepTask extends AbstractTask {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInsertable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Guild getGuild() {
|
||||
return guild;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replyToInteraction(CommandContext context) {
|
||||
synchronized (stepLock) {
|
||||
this.commandContext = context;
|
||||
}
|
||||
|
||||
if (context.isFromGuild()) {
|
||||
guild = context.getGuild();
|
||||
}
|
||||
|
||||
if (guild == null && getStepType() == StepType.ROLE) {
|
||||
throw new IllegalArgumentException("Step task if of type role but it was inserted in a non-guild context");
|
||||
throw new IllegalArgumentException("Step task is of type role but it was inserted in a non-guild context");
|
||||
}
|
||||
|
||||
if (inDM()) {
|
||||
context.replyEphemeral("Please follow the instructions sent in DM.");
|
||||
context.sendMessageInPrivate(getStepDescription() + "\n" + getStepQuestion(), asyncContext -> assignId(asyncContext.getMessageId()));
|
||||
} else {
|
||||
context.reply(getStepQuestion(), asyncContext -> id = asyncContext.getMessageId());
|
||||
}
|
||||
|
||||
System.out.println("step id : " + id);
|
||||
context.replyEphemeral("Please follow the instructions sent in DM.");
|
||||
context.sendMessageInPrivate(getStepDescription() + "\n\n" + getStepQuestion(),
|
||||
asyncContext -> assignId(asyncContext.getMessageId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lifecycle execute(TaskContext context) {
|
||||
if (context instanceof MessageContext messageContext) {
|
||||
Message message = messageContext.getMessage();
|
||||
String answer = message.getContentRaw();
|
||||
|
||||
if (validateAnswer(answer)) {
|
||||
StepTask nextStep = executeStep(answer);
|
||||
|
||||
//TODO: to finish
|
||||
synchronized (stepLock) {
|
||||
if (!context.getDiscordUser().equals(commandContext.getDiscordUser())) {
|
||||
return Lifecycle.KEEP;
|
||||
}
|
||||
}
|
||||
|
||||
return Lifecycle.REMOVE_SELF;
|
||||
if (context instanceof MessageContext messageContext) {
|
||||
Message message = messageContext.getMessage();
|
||||
String input = message.getContentRaw();
|
||||
|
||||
|
||||
Object answer = validateInput(context, input);
|
||||
if (answer == null) {
|
||||
return Lifecycle.KEEP;
|
||||
}
|
||||
|
||||
StepResult result = executeStep(answer);
|
||||
if (!result.isSuccess()) {
|
||||
context.replyEphemeral(result.getMessage());
|
||||
return Lifecycle.KEEP;
|
||||
}
|
||||
|
||||
if (result.getMessage() != null) {
|
||||
context.replyEphemeral(result.getMessage());
|
||||
}
|
||||
|
||||
if (result.getNextStep() != null) {
|
||||
result.getNextStep().insert(commandContext);
|
||||
}
|
||||
|
||||
return Lifecycle.REMOVE_SELF;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Step task is not of type MessageContext");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExpired() {
|
||||
return getCreationTime().plusMinutes(30).isBefore(OffsetDateTime.now());
|
||||
// is it really needed to expire this type of task?
|
||||
return getCreationTime().plusMinutes(60).isBefore(OffsetDateTime.now());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,8 +115,44 @@ public abstract class StepTask extends AbstractTask {
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean validateAnswer(String answer) {
|
||||
return false;
|
||||
/**
|
||||
* Validates the user input against the expected step type.
|
||||
*
|
||||
* @param context the task execution context
|
||||
* @param input the user-provided input
|
||||
* @return the parsed input if valid, or null if invalid
|
||||
*/
|
||||
private Object validateInput(TaskContext context, String input) {
|
||||
switch (getStepType()) {
|
||||
case ROLE -> {
|
||||
try {
|
||||
Role role = guild.getRoleById(input);
|
||||
if (role == null) {
|
||||
context.replyEphemeral("The role doesn't exist");
|
||||
return null;
|
||||
}
|
||||
|
||||
return role;
|
||||
} catch (NumberFormatException e) {
|
||||
context.replyEphemeral("Not a valid role ID");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
case EMOJI -> {
|
||||
Optional<Emoji> parsed = EmojiManager.getEmoji(input);
|
||||
|
||||
if (parsed.isPresent()) {
|
||||
return parsed.get().getEmoji();
|
||||
}
|
||||
|
||||
context.replyEphemeral("Not a valid emoji");
|
||||
return null;
|
||||
}
|
||||
case STRING -> {
|
||||
return input;
|
||||
}
|
||||
default -> throw new IllegalStateException("Unknown step type: " + getStepType());
|
||||
}
|
||||
}
|
||||
|
||||
private void assignId(String newId) {
|
||||
@@ -90,21 +160,10 @@ public abstract class StepTask extends AbstractTask {
|
||||
throw new IllegalArgumentException("Task ID cannot be null or empty.");
|
||||
}
|
||||
|
||||
String oldId = id;
|
||||
synchronized (this) {
|
||||
this.id = newId;
|
||||
TaskManager.getInstance().activateTask(this);
|
||||
TaskManager.getInstance().activateTask(this, oldId);
|
||||
}
|
||||
|
||||
this.id = newId;
|
||||
}
|
||||
|
||||
public abstract boolean inDM();
|
||||
|
||||
public abstract StepType getStepType();
|
||||
|
||||
public abstract String getStepDescription();
|
||||
|
||||
public abstract String getStepQuestion();
|
||||
|
||||
public abstract StepTask executeStep(String answer);
|
||||
}
|
||||
@@ -41,7 +41,7 @@ public class TaskFactory {
|
||||
|
||||
public static PersistableTask createTaskInstance(String className, JSONArray params, JSONArray types, JSONObject payload) throws Exception {
|
||||
if (params.length() != types.length()) {
|
||||
throw new RuntimeException("Wrong number of parameters and types.");
|
||||
throw new RuntimeException("Wrong number of parameters and types found in task mappings");
|
||||
}
|
||||
|
||||
Class<?> clazz = Class.forName(className);
|
||||
|
||||
@@ -19,7 +19,11 @@ public interface WithChildren extends Task {
|
||||
|
||||
List<Task> getChildTasks();
|
||||
|
||||
default void addChild(List<Task> tasks) {
|
||||
getChildTasks().addAll(tasks);
|
||||
}
|
||||
|
||||
default void addChild(Task... tasks) {
|
||||
getChildTasks().addAll(List.of(tasks));
|
||||
addChild(List.of(tasks));
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ public class TaskService {
|
||||
for (OTask oTask : tasks) {
|
||||
String taskId = oTask.getTaskId();
|
||||
String taskClass = oTask.getTaskClass();
|
||||
logger.debug("Trying to load task with class: {}", taskClass);
|
||||
logger.debug("Trying to load task with ID: {} and class: {}", taskId, taskClass);
|
||||
|
||||
String payload = oTask.getPayload();
|
||||
|
||||
@@ -95,11 +95,12 @@ public class TaskService {
|
||||
|
||||
oTask.setPayload(task.toPayload());
|
||||
|
||||
logger.info("Persisting task: {}", oTask.getTaskId());
|
||||
taskRepository.save(oTask);
|
||||
}
|
||||
|
||||
public void unpersistTask(PersistableTask task) {
|
||||
logger.debug("Unpersisting task: {}", task);
|
||||
logger.debug("Unpersisting task: {}", task.getId());
|
||||
TaskRepository taskRepository = new TaskRepository();
|
||||
|
||||
taskRepository.deleteBy(task.getId());
|
||||
|
||||
@@ -70,7 +70,7 @@ public class TrackLoadingHandler implements AudioLoadResultHandler {
|
||||
|
||||
@Override
|
||||
public void loadFailed(FriendlyException e) {
|
||||
logger.debug("Guild {}: load failed for identifier {}", guild.getId(), identifier, e);
|
||||
logger.debug("Guild {}: load failed for identifier {}", guild.getId(), identifier);
|
||||
|
||||
//TODO: better error messages
|
||||
RuntimeException exception = new RuntimeException("Failed to load track: " + e.getMessage(), e);
|
||||
|
||||
@@ -14,12 +14,12 @@ import java.util.Map;
|
||||
|
||||
public class EmojiReactionRoleTask extends EmojiTask {
|
||||
public EmojiReactionRoleTask(String guildId, String channelId, String messageId) {
|
||||
super(guildId, messageId);
|
||||
super(guildId, channelId, messageId);
|
||||
}
|
||||
|
||||
// constructor for auto loading
|
||||
public EmojiReactionRoleTask(String guildId, String messageId, Map<String, String> emojiMapping) {
|
||||
super(guildId, messageId);
|
||||
public EmojiReactionRoleTask(String guildId, String channelId, String messageId, Map<String, String> emojiMapping) {
|
||||
super(guildId, channelId, messageId);
|
||||
getEmojiMapping().putAll(emojiMapping);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ package me.bobert.netneutrality.tasks.generic;
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.context.TaskContext;
|
||||
import me.bobert.netneutrality.core.tasks.trait.NotAcknowledgeable;
|
||||
import me.bobert.netneutrality.core.tasks.trait.WithChildren;
|
||||
import me.bobert.netneutrality.core.tasks.trait.WithParent;
|
||||
import me.bobert.netneutrality.core.tasks.impl.ButtonTask;
|
||||
@@ -18,7 +19,7 @@ import java.util.function.Function;
|
||||
* A generic button task that represents a button to accept a choice.
|
||||
* @param <P> the type of the parent task, which must implement WithChildren
|
||||
*/
|
||||
public class AcceptButton<P extends WithChildren> extends ButtonTask implements WithParent<P> {
|
||||
public class AcceptButton<P extends WithChildren> extends ButtonTask implements WithParent<P>, NotAcknowledgeable {
|
||||
private final P parentTask;
|
||||
private final Function<TaskContext, Lifecycle> function;
|
||||
|
||||
@@ -32,10 +33,18 @@ public class AcceptButton<P extends WithChildren> extends ButtonTask implements
|
||||
return new AcceptButton<>(parentTask, ButtonStyle.PRIMARY, buttonLabel, function);
|
||||
}
|
||||
|
||||
public static <P extends WithChildren> AcceptButton<P> createSecondaryButton(P parentTask, String buttonLabel, Function<TaskContext, Lifecycle> function) {
|
||||
return new AcceptButton<>(parentTask, ButtonStyle.SECONDARY, buttonLabel, function);
|
||||
}
|
||||
|
||||
public static <P extends WithChildren> AcceptButton<P> createSuccessButton(P parentTask, String buttonLabel, Function<TaskContext, Lifecycle> function) {
|
||||
return new AcceptButton<>(parentTask, ButtonStyle.SUCCESS, buttonLabel, function);
|
||||
}
|
||||
|
||||
public static <P extends WithChildren> AcceptButton<P> createDangerButton(P parentTask, String buttonLabel, Function<TaskContext, Lifecycle> function) {
|
||||
return new AcceptButton<>(parentTask, ButtonStyle.DANGER, buttonLabel, function);
|
||||
}
|
||||
|
||||
@Override
|
||||
public P getParentTask() {
|
||||
return parentTask;
|
||||
@@ -46,6 +55,11 @@ public class AcceptButton<P extends WithChildren> extends ButtonTask implements
|
||||
return "accept-" + parentTask.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInsertable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lifecycle execute(TaskContext context) {
|
||||
return function.apply(context);
|
||||
|
||||
@@ -39,6 +39,11 @@ public class CancelButton<P extends WithChildren> extends ButtonTask implements
|
||||
return "cancel-" + parentTask.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInsertable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lifecycle execute(TaskContext context) {
|
||||
return function.apply(context);
|
||||
|
||||
@@ -24,7 +24,6 @@ import me.bobert.netneutrality.utils.MusicUtils;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.emoji.Emoji;
|
||||
import net.dv8tion.jda.api.interactions.components.ActionRow;
|
||||
import net.dv8tion.jda.api.interactions.components.ItemComponent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -40,10 +39,6 @@ public class LoadPlaylistTask extends ButtonTask implements WithChildren, Deleta
|
||||
this.sourceType = sourceType;
|
||||
}
|
||||
|
||||
public AudioPlaylist getPlaylist() {
|
||||
return playlist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "load-playlist";
|
||||
@@ -69,17 +64,14 @@ public class LoadPlaylistTask extends ButtonTask implements WithChildren, Deleta
|
||||
// Search results
|
||||
if (playlist.isSearchResult()) {
|
||||
List<AudioTrack> searchResults = playlist.getTracks().stream().limit(searchResultsLimit).toList();
|
||||
List<ItemComponent> buttonList = new ArrayList<>();
|
||||
List<Task> loadTasks = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < searchResults.size(); i++) {
|
||||
AudioTrack track = searchResults.get(i);
|
||||
Task buttonTask = new LoadTrackFromPlaylistTask(this, String.valueOf(i + 1), track);
|
||||
|
||||
buttonList.add(buttonTask.createButton());
|
||||
addChild(buttonTask);
|
||||
loadTasks.add(new LoadTrackFromPlaylistTask(this, String.valueOf(i + 1), track));
|
||||
}
|
||||
|
||||
ActionRow firstRow = ActionRow.of(buttonList);
|
||||
ActionRow firstRow = createActionRow(loadTasks);
|
||||
ActionRow secondRow = commonButtons(searchResults, "Add all tracks", "Not for me honey");
|
||||
|
||||
context.edit(MessageFunction.buildSearchResultsMessage(searchResults, context.getGuildUser()), List.of(firstRow, secondRow));
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package me.bobert.netneutrality.tasks.reaction;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.tasks.impl.StepTask;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
|
||||
public class EmojiRoleFirstStep extends StepTask {
|
||||
private final Message target;
|
||||
|
||||
public EmojiRoleFirstStep(Message target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "role-first-step";
|
||||
}
|
||||
|
||||
@Override
|
||||
public StepType getStepType() {
|
||||
return StepType.ROLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStepDescription() {
|
||||
return String.format("Creating a new emoji role mapping in guild %s for message %s",
|
||||
getGuild().getId(),
|
||||
target.getJumpUrl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStepQuestion() {
|
||||
return "Reply to this message with the role ID you want to configure";
|
||||
}
|
||||
|
||||
@Override
|
||||
public StepResult executeStep(Object answer) {
|
||||
return StepResult.next(new EmojiRoleSecondStep(target, (Role) answer));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package me.bobert.netneutrality.tasks.reaction;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.context.CommandContext;
|
||||
import me.bobert.netneutrality.core.tasks.Task;
|
||||
import me.bobert.netneutrality.core.tasks.TaskManager;
|
||||
import me.bobert.netneutrality.core.tasks.impl.ButtonTask;
|
||||
import me.bobert.netneutrality.core.tasks.trait.WithChildren;
|
||||
import me.bobert.netneutrality.tasks.emoji.EmojiReactionRoleTask;
|
||||
import me.bobert.netneutrality.tasks.generic.AcceptButton;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.interactions.components.ActionRow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class EmojiRoleModify extends ButtonTask implements WithChildren {
|
||||
private final List<Task> childrens = new ArrayList<>();
|
||||
private final Message target;
|
||||
private final EmojiReactionRoleTask task;
|
||||
|
||||
public EmojiRoleModify(Message target, EmojiReactionRoleTask task) {
|
||||
super(null, null);
|
||||
this.target = target;
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "modify emoji role";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInsertable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replyToInteraction(CommandContext context) {
|
||||
Task addEmojiTask = AcceptButton.createSuccessButton(this, "Add emoji role mapping", taskContext -> {
|
||||
if (task.getEmojiMapping().size() >= 10) {
|
||||
taskContext.replyEphemeral("You cannot add more than 10 emoji roles on a message");
|
||||
return Lifecycle.KEEP;
|
||||
}
|
||||
|
||||
new EmojiRoleFirstStep(target).insert(context);
|
||||
return Lifecycle.KEEP;
|
||||
});
|
||||
|
||||
Task removeEmojiTask = AcceptButton.createSecondaryButton(this, "Remove emoji role mapping", taskContext -> {
|
||||
if (task.getEmojiMapping().isEmpty()) {
|
||||
taskContext.replyEphemeral("No emoji role mapping found for the message");
|
||||
return Lifecycle.KEEP;
|
||||
}
|
||||
|
||||
new EmojiRoleRemoveStep(target, task).insert(context);
|
||||
return Lifecycle.KEEP;
|
||||
});
|
||||
|
||||
Task deleteMappingTask = AcceptButton.createDangerButton(this, "Unregister task", taskContext -> {
|
||||
if (!TaskManager.getInstance().hasTask(task.getId())) {
|
||||
taskContext.replyEphemeral("This task no longer exists");
|
||||
return Lifecycle.REMOVE_SELF;
|
||||
}
|
||||
|
||||
task.delete();
|
||||
context.replyEphemeral("Task deleted successfully!");
|
||||
return Lifecycle.REMOVE_SELF;
|
||||
});
|
||||
|
||||
ActionRow row = createActionRow(addEmojiTask, removeEmojiTask, deleteMappingTask);
|
||||
context.replyEphemeral("Select what you want to do with this message", List.of(row));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Task> getChildTasks() {
|
||||
return childrens;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package me.bobert.netneutrality.tasks.reaction;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.tasks.impl.StepTask;
|
||||
import me.bobert.netneutrality.tasks.emoji.EmojiReactionRoleTask;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
public class EmojiRoleRemoveStep extends StepTask {
|
||||
private final Message target;
|
||||
private final EmojiReactionRoleTask task;
|
||||
|
||||
public EmojiRoleRemoveStep(Message target, EmojiReactionRoleTask task) {
|
||||
this.target = target;
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StepType getStepType() {
|
||||
return StepType.EMOJI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStepDescription() {
|
||||
return String.format("Select which emoji you want to remove from the message %s", target.getJumpUrl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStepQuestion() {
|
||||
StringJoiner joiner = new StringJoiner(" - ");
|
||||
Set<String> emojis = task.getEmojiMapping().keySet();
|
||||
for (String emoji : emojis) {
|
||||
joiner.add(emoji);
|
||||
}
|
||||
|
||||
return joiner.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StepResult executeStep(Object answer) {
|
||||
String emoji = (String) answer;
|
||||
|
||||
if (!task.getEmojiMapping().containsKey(emoji)) {
|
||||
return StepResult.failure("The emoji doesn't exist");
|
||||
}
|
||||
|
||||
task.removeEmoji(emoji);
|
||||
return StepResult.success("Removed emoji successfully!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "emoji-role-remove";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package me.bobert.netneutrality.tasks.reaction;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.tasks.Task;
|
||||
import me.bobert.netneutrality.core.tasks.TaskManager;
|
||||
import me.bobert.netneutrality.core.tasks.impl.StepTask;
|
||||
import me.bobert.netneutrality.tasks.emoji.EmojiReactionRoleTask;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class EmojiRoleSecondStep extends StepTask {
|
||||
private final Message target;
|
||||
private final Role role;
|
||||
|
||||
public EmojiRoleSecondStep(Message target, Role role) {
|
||||
this.target = target;
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StepType getStepType() {
|
||||
return StepType.EMOJI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStepDescription() {
|
||||
return String.format("Creating a new emoji role mapping in guild %s for message %s and role %s",
|
||||
getGuild().getId(),
|
||||
target.getJumpUrl(),
|
||||
role.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStepQuestion() {
|
||||
return "Reply with the emoji you want to add to the role";
|
||||
}
|
||||
|
||||
@Override
|
||||
public StepResult executeStep(Object answer) {
|
||||
String emoji = (String) answer;
|
||||
Task emojiTask = new EmojiReactionRoleTask(target.getGuildId(),
|
||||
target.getChannelId(),
|
||||
target.getId(),
|
||||
Map.of(emoji, role.getId()));
|
||||
|
||||
if (TaskManager.getInstance().hasTask(emojiTask.getId())) {
|
||||
return StepResult.failure("The message ID is already registered with the bot, please use the modify mapping command instead");
|
||||
}
|
||||
|
||||
return StepResult.success("Mapping registered successfully for role " + role.getName() + " with emoji " + emoji, emojiTask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "role-second-step";
|
||||
}
|
||||
}
|
||||
@@ -18,19 +18,18 @@ public class CleanupTaskThread implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
List<Task> tasks = TaskManager.getInstance().getTasks()
|
||||
TaskManager manager = TaskManager.getInstance();
|
||||
|
||||
List<Task> expiredTasks = manager.getTasks()
|
||||
.stream()
|
||||
.filter(task -> !(task instanceof PersistableTask))
|
||||
.filter(task -> !(task instanceof BuiltInTask))
|
||||
.filter(Task::isExpired)
|
||||
.toList();
|
||||
|
||||
if (!tasks.isEmpty()) {
|
||||
logger.info("Cleaning up {} expired tasks..", tasks.size());
|
||||
|
||||
for (Task task : tasks) {
|
||||
TaskManager.getInstance().removeTask(task);
|
||||
}
|
||||
if (!expiredTasks.isEmpty()) {
|
||||
logger.info("Cleaning up {} expired tasks..", expiredTasks.size());
|
||||
expiredTasks.forEach(manager::removeTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,12 @@
|
||||
"class": "me.bobert.netneutrality.tasks.emoji.EmojiReactionRoleTask",
|
||||
"params": [
|
||||
"guildId",
|
||||
"channelId",
|
||||
"messageId",
|
||||
"emojiMapping"
|
||||
],
|
||||
"types": [
|
||||
"string",
|
||||
"string",
|
||||
"string",
|
||||
"map"
|
||||
|
||||
Reference in new issue
Block a user