updated javadoc for experience tracking

added/changed some javadoc for mod mail
some small interface changes
changed a few methods to actually use the exists mechanic, instead of checking for null values
added some templates instead of hard coded strings
fixed some bugs related to mod mail
This commit is contained in:
Sheldan
2020-06-13 00:51:50 +02:00
parent e76351ddc1
commit 19a7d09576
111 changed files with 1238 additions and 162 deletions

View File

@@ -0,0 +1,10 @@
package dev.sheldan.abstracto.modmail.condition;
import dev.sheldan.abstracto.core.command.condition.CommandCondition;
/**
* This condition represents the condition that the command can only be executed while the member
* is within a mod mail channel.
*/
public interface ModMailContextCondition extends CommandCondition {
}

View File

@@ -14,6 +14,9 @@ import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
/**
* General instance of {@link FeatureConfig} to establish the mod mail feature
*/
@Component
public class ModMailFeature implements FeatureConfig {

View File

@@ -3,6 +3,10 @@ package dev.sheldan.abstracto.modmail.config;
import dev.sheldan.abstracto.core.config.FeatureMode;
import lombok.Getter;
/**
* This enum defines the to {@link FeatureMode} mod mail has.
* Either closed mod mail threads are logged, or they are not logged to the respective post target.
*/
@Getter
public enum ModMailMode implements FeatureMode {
LOGGING("log"), NO_LOG("nolog");

View File

@@ -5,7 +5,14 @@ import lombok.Getter;
@Getter
public enum ModMailPostTargets implements PostTargetEnum {
MOD_MAIL_PING("modmailPing"), MOD_MAIL_LOG("modmailLog");
/**
* The channel to be used for notifying the users about new mod mail threads
*/
MOD_MAIL_PING("modmailPing"),
/**
* The channel to be used to log the contents of closed mod mail threads
*/
MOD_MAIL_LOG("modmailLog");
private String key;

View File

@@ -3,9 +3,12 @@ package dev.sheldan.abstracto.modmail.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.templating.Templatable;
/**
* This exception is thrown then you try to subscribe to a mod mail thread, to which you are already subscribed to
*/
public class AlreadySubscribedException extends AbstractoRunTimeException implements Templatable {
public AlreadySubscribedException(String message) {
super(message);
public AlreadySubscribedException() {
super("");
}
@Override

View File

@@ -0,0 +1,36 @@
package dev.sheldan.abstracto.modmail.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.templating.Templatable;
import lombok.Getter;
import lombok.Setter;
import java.util.HashMap;
/**
* This exception is thrown when a {@link net.dv8tion.jda.api.entities.Member} tries to set the mod mail category
* via a command, and the new value does not qualify as a valid {@link net.dv8tion.jda.api.entities.Category}
* in the member executes the command in
*/
@Getter
@Setter
public class ModMailCategoryIdException extends AbstractoRunTimeException implements Templatable {
private Long categoryId;
public ModMailCategoryIdException(Long categoryId) {
super("");
this.categoryId = categoryId;
}
@Override
public String getTemplateName() {
return "modmail_category_not_setup";
}
@Override
public Object getTemplateModel() {
HashMap<String, Long> params = new HashMap<>();
params.put("categoryId", this.categoryId);
return params;
}
}

View File

@@ -5,6 +5,10 @@ import dev.sheldan.abstracto.templating.Templatable;
import java.util.HashMap;
/**
* This exception is raised, when for some reason the mod mail thread is not found in the database anymore, but the context which is executed stems from a mod mail thread.
* For example if it is attempted to log a thread, without the thread existing in the database.
*/
public class ModMailThreadNotFoundException extends AbstractoRunTimeException implements Templatable {
private final Long modMailThreadId;

View File

@@ -3,9 +3,12 @@ package dev.sheldan.abstracto.modmail.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.templating.Templatable;
/**
* This exception is thrown when you try to unsubscribe from a mod mail thread, to which you are not subscribed to
*/
public class NotSubscribedException extends AbstractoRunTimeException implements Templatable {
public NotSubscribedException(String message) {
super(message);
public NotSubscribedException() {
super("");
}
@Override

View File

@@ -7,6 +7,11 @@ import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.*;
import java.time.Instant;
/**
* A table used to store which messages need to be retrieved when logging a mod mail thread.
* These messages are only the messages passed between the member and the staff handling the thread and include all messages by the user
* and only the messages send via command (reply/anonreply)
*/
@Builder
@Entity
@NoArgsConstructor
@@ -18,19 +23,34 @@ import java.time.Instant;
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class ModMailMessage {
/**
* The globally unique message ID which was send in the mod mail thread, either by a user of by the staff handling the thread
*/
@Id
private Long messageId;
/**
* The {@link AUserInAServer} which authored this message
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "modmail_message_author", nullable = false)
private AUserInAServer author;
/**
* The {@link ModMailThread} in whose context this message was sent and this message is related to
*/
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "threadReference", nullable = false)
private ModMailThread threadReference;
/**
* Whether or not this message was from the user or a staff member, for convenience
*/
private Boolean dmChannel;
/**
* Staff only: Whether or not this message meant to be sent anonymous
*/
private Boolean anonymous;
@Column(name = "created")

View File

@@ -8,6 +8,10 @@ import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.*;
import java.time.Instant;
/**
* The table responsible to define which roles are the roles responsible for handling the mod mail threads.
* These will get notified via a ping, when a new mod mail thread is created.
*/
@Builder
@Entity
@NoArgsConstructor
@@ -19,14 +23,23 @@ import java.time.Instant;
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class ModMailRole {
/**
* Unique ID of the mod mail role
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long modMailRoleId;
/**
* Which {@link AServer} this role is associated with, for convenience
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "modmail_role_server", nullable = false)
private AServer server;
/**
* The actual {@link ARole} which this mod mail role references
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "modmail_role", nullable = false)
private ARole role;

View File

@@ -9,6 +9,10 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
/**
* The table responsible to associate certain channels to be mod mail thread channels. It also stores the current state of the thread (answered, initial)
* ,who the associated user is, who has subscribed to the thread and the messages posted in the thread.
*/
@Builder
@Entity
@NoArgsConstructor
@@ -24,14 +28,23 @@ public class ModMailThread {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* The member who opened the thread or who got contacted
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "modmail_user", nullable = false)
private AUserInAServer user;
/**
* The text channel in which this thread is dealt with
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "modmail_thread_channel", nullable = false)
private AChannel channel;
/**
* The server on which this mod mail thread is, for convenience
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "modmail_thread_server", nullable = false)
private AServer server;
@@ -55,6 +68,10 @@ public class ModMailThread {
@Column
private Instant closed;
/**
* The messages which were officially posted in the context of the mod mail thread. Either via command (from the
* staff side of view) or by messaging the bot (from the member view)
*/
@OneToMany(
fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
@@ -64,6 +81,9 @@ public class ModMailThread {
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private List<ModMailMessage> messages = new ArrayList<>();
/**
* The staff members who subscribed to be notified in case there is a new message in a mod mail thread.
*/
@OneToMany(
fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
@@ -73,6 +93,9 @@ public class ModMailThread {
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private List<ModMailThreadSubscriber> subscribers = new ArrayList<>();
/**
* The current state of the mod mail thread. Whether or not the last post was by staff or user.
*/
@Enumerated(EnumType.STRING)
@Column
private ModMailThreadState state;

View File

@@ -1,5 +1,20 @@
package dev.sheldan.abstracto.modmail.models.database;
public enum ModMailThreadState {
INITIAL, USER_REPLIED, MOD_REPLIED, CLOSED, CLOSING;
/**
* User opened the mod mail thread or staff contacted member, but did not post a message yet
*/
INITIAL,
/**
* User replied to mod mail thread
*/
USER_REPLIED,
/**
* Staff member responded to the mod mail thread
*/
MOD_REPLIED,
/**
* The thread was closed by a staff member and the channel was removed
*/
CLOSED, CLOSING;
}

View File

@@ -7,6 +7,10 @@ import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.*;
import java.time.Instant;
/**
* This able contains the staff users which subscribed to a certain mod mail thread and will get notified of new messages
* in a mod mail thread
*/
@Builder
@Entity
@NoArgsConstructor
@@ -22,10 +26,16 @@ public class ModMailThreadSubscriber {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long subscriberId;
/**
* The staff member which is subscribed
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "modmail_message_subscriber", nullable = false)
private AUserInAServer subscriber;
/**
* The thread for which the member is subscribed to
*/
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "modMailThread", nullable = false)
private ModMailThread threadReference;

View File

@@ -5,10 +5,20 @@ import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
/**
* Used when the user shares multiple servers with the bot and needs to determine for which server the user
* wants to open a mod mail thread, this is done by reacting to the prompt with the proper emote.
*/
@Getter
@Setter
@Builder
public class ServerChoice {
/**
* The possible guild to open a mod mail thread for
*/
private FullGuild guild;
/**
* The unicode emote used in the prompt to identify this choice
*/
private String reactionEmote;
}

View File

@@ -5,6 +5,11 @@ import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.Category;
/**
* This model is used when confirming the setup up the mod mail configuration for the category in which the channels should be created
* This model contains the actual JDA category object where the channels will be created in, and the id of said
* category
*/
@Getter
@Setter
@Builder

View File

@@ -1,16 +1,21 @@
package dev.sheldan.abstracto.modmail.models.template;
import dev.sheldan.abstracto.core.models.ValidationError;
import dev.sheldan.abstracto.core.models.ValidationErrorModel;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.util.HashMap;
/**
* This model is used when the category for creating mod mail threads is not properly setup
* and when the feature is enabled via command. This will be rendered as a simple additional line of validation errors
* after the command finished
*/
@Getter
@Setter
@Builder
public class ModMailCategoryValidationError implements ValidationError {
public class ModMailCategoryValidationErrorModel implements ValidationErrorModel {
private Long currentCategoryId;
@Override

View File

@@ -7,13 +7,27 @@ import lombok.Setter;
import java.time.Duration;
/**
* This model is used when rendering the message before logging the messages in a closed {@link ModMailThread} and contains
* general information about why the thread was closed and the thread itself.
*/
@Getter
@Setter
@Builder
public class ModMailClosingHeaderModel {
/**
* The note used to close the thread, might be the default value
*/
private String note;
/**
* The {@link ModMailThread} which was closed
*/
private ModMailThread closedThread;
/**
* The duration between the creation and closed date of a {@link ModMailThread}
* @return
*/
public Duration getDuration() {
return Duration.between(closedThread.getCreated(), closedThread.getClosed());
}

View File

@@ -6,11 +6,25 @@ import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
/**
* This model is used to render any exception happening when executing a command within a {@link ModMailThread}
* and this command failing in any capacity. This model is used to render multiple templates (for differnet kinds of
* exceptions), all of which might use the information or not.
*/
@Getter
@Setter
@Builder
public class ModMailExceptionModel {
/**
* The {@link ModMailThread} in which the exception occurred
*/
private ModMailThread modMailThread;
/**
* A user associated with this exception, depends on the exact behaviour of the exception.
*/
private FullUser user;
/**
* The exception which was thrown
*/
private Throwable throwable;
}

View File

@@ -1,19 +0,0 @@
package dev.sheldan.abstracto.modmail.models.template;
import dev.sheldan.abstracto.core.models.FullUser;
import dev.sheldan.abstracto.modmail.models.database.ModMailMessage;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.Message;
@Getter
@Setter
@Builder
public class ModMailLoggedMessage {
private Message message;
private ModMailMessage modMailMessage;
private FullUser author;
}

View File

@@ -0,0 +1,32 @@
package dev.sheldan.abstracto.modmail.models.template;
import dev.sheldan.abstracto.core.models.FullUser;
import dev.sheldan.abstracto.modmail.models.database.ModMailMessage;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.Message;
/**
* This model is used to render a message from a mod mail thread when closing the thread and logging the thread to the logging post target
*/
@Getter
@Setter
@Builder
public class ModMailLoggedMessageModel {
/**
* The {@link Message} instance which was posted
*/
private Message message;
/**
* The reference to the {@link ModMailMessage} stored in the database
*/
private ModMailMessage modMailMessage;
/**
* A reference to the {@link FullUser} which is the author. The member part is null, if the member left the guild.
*/
private FullUser author;
}

View File

@@ -8,14 +8,36 @@ import lombok.Setter;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
/**
* Model used to render the response by staff members to the DM channel with the user
*/
@Getter
@Setter
@Builder
public class ModMailModeratorReplyModel {
/**
* A {@link FullUser} reference representing the user the thread is about. The member attribute is null, if the user left the guild
*/
private FullUser threadUser;
/**
* The staff {@link Member} which replied to the thread, be it anonymously or normal.
*/
private Member moderator;
/**
* The text which was used to reply. This is necessary, because the reply is triggered via a command, so
* we would need re-parse the {@link Message} in order to find the value to display
*/
private String text;
/**
* The {@link Message} which contained the command to reply to the user. This is needed for attachments.
*/
private Message postedMessage;
/**
* Whether or not the reply should be shown anonymous
*/
private Boolean anonymous;
/**
* The {@link ModMailThread} to reply to
*/
private ModMailThread modMailThread;
}

View File

@@ -10,11 +10,24 @@ import lombok.experimental.SuperBuilder;
import java.util.List;
/**
* The model used to notify staff members about a newly created mod mail thread. This model contains a dynamic amount of roles which are pinged
* upon creation of a mod mail thread
*/
@Getter
@Setter
@SuperBuilder
public class ModMailNotificationModel extends ServerContext {
/**
* The created {@link ModMailThread} which was just created
*/
private ModMailThread modMailThread;
/**
* The {@link FullUser} for which this thread is about
*/
private FullUser threadUser;
/**
* A list of roles which will be notified upon creation of the mod mail thread.
*/
private List<ModMailRole> roles;
}

View File

@@ -7,9 +7,17 @@ import lombok.Setter;
import java.util.List;
/**
* Container model used to define all the possible {@link ServerChoice} which are presented when the initial message is
* sent to the bot
*/
@Getter
@Setter
@Builder
public class ModMailServerChooserModel {
/**
* A list of {@link ServerChoice} which contains the common servers of the user and the bot, but only those
* in which the mod mail feature is currently enabled
*/
private List<ServerChoice> commonGuilds;
}

View File

@@ -7,6 +7,10 @@ import lombok.Getter;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
/**
* This model is used to notify a staff member that there is already a mod mail thread open for the user
* and provide a link to the channel associated with the user.
*/
@Getter
@Setter
@SuperBuilder

View File

@@ -6,11 +6,25 @@ import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
/**
* This is the model used when a new mod mail thread is opened and a message containing some information about the user
* is displayed for the user handling the mod mail thread.
*/
@Getter
@Setter
@Builder
public class ModMailThreaderHeader {
/**
* A {@link FullUser} instance to retrieve information from
*/
private FullUser threadUser;
/**
* The latest {@link ModMailThread}, before the current opened one. This is null if there is no closed mod mail thread
* for the user
*/
private ModMailThread latestModMailThread;
/**
* The amount of previous mod mail thread the user has.
*/
private Long pastModMailThreadCount;
}

View File

@@ -9,12 +9,28 @@ import net.dv8tion.jda.api.entities.Message;
import java.util.List;
/**
* Model used to render the response by the user to the mod mail thread channel.
*/
@Getter
@Setter
@Builder
public class ModMailUserReplyModel {
/**
* The {@link FullUser} from which the message is and whose mod mail thread it is
*/
private FullUser threadUser;
/**
* The {@link Message} which was posted, which contains all the possible information
*/
private Message postedMessage;
/**
* The {@link ModMailThread} for which the {@link Message} was a reply for
*/
private ModMailThread modMailThread;
/**
* List of {@link FullUser} which are registered as subscribers for a particular mod mail thread and will be pinged
* when the user sends a new message
*/
private List<FullUser> subscribers;
}

View File

@@ -5,6 +5,10 @@ import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.Category;
/**
* Model which is used when setting up the mod mail feature. The category property will be used when there is already a category
* defined to be used for mod mail threads and it is still a valid category.
*/
@Getter
@Setter
@Builder

View File

@@ -6,6 +6,14 @@ import net.dv8tion.jda.api.entities.Message;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* Service to handle the messages of a {@link dev.sheldan.abstracto.modmail.models.database.ModMailThread}
*/
public interface ModMailMessageService {
/**
* Loads the given mod mail messages in the form of {@link Message} from Discord and returns the created promises, some of which might fail, if the message was already deleted
* @param modMailMessages The list of {@link ModMailMessage} to load
* @return A list of futures which contain the individual results of actively loading the {@link Message}
*/
List<CompletableFuture<Message>> loadModMailMessages(List<ModMailMessage> modMailMessages);
}

View File

@@ -1,9 +1,24 @@
package dev.sheldan.abstracto.modmail.service;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AServer;
/**
* Service for managing {@link dev.sheldan.abstracto.modmail.models.database.ModMailRole}, this includes crating and removing them
*/
public interface ModMailRoleService {
void addRoleToModMailRoles(ARole role, AServer server);
void removeRoleFromModMailRoles(ARole role, AServer server);
/**
* Adds a given {@link ARole} to the list of {@link dev.sheldan.abstracto.modmail.models.database.ModMailRole} of the given server.
* This method also allows the given role to execute the mod mail related commands. (Which causes the commands to automatically be restricted)
* @param role The {@link ARole} to change to a {@link dev.sheldan.abstracto.modmail.models.database.ModMailRole}
*
*/
void addRoleToModMailRoles(ARole role);
/**
* Removes the given {@link ARole} from the list of {@link dev.sheldan.abstracto.modmail.models.database.ModMailRole} of the server.
* This automatically dis-allows the mod mail related commands for the given role.
* @param role The {@link ARole} to remove from the list of mod mail roles
*
*/
void removeRoleFromModMailRoles(ARole role);
}

View File

@@ -3,7 +3,23 @@ package dev.sheldan.abstracto.modmail.service;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
/**
* Service used to add subscriptions to threads and remove them as well.
*/
public interface ModMailSubscriptionService {
/**
* Subscribes the {@link AUserInAServer} to the given {@link ModMailThread}.
* @param aUserInAServer The {@link AUserInAServer} to subscribe
* @param modMailThread The {@link ModMailThread} to subscribe the user to
* @throws dev.sheldan.abstracto.modmail.exception.AlreadySubscribedException in case the user is already subscribed
*/
void subscribeToThread(AUserInAServer aUserInAServer, ModMailThread modMailThread);
/**
* Un-subscribes the {@link AUserInAServer} from the given {@link ModMailThread}
* @param aUserInAServer The {@link AUserInAServer} to un-subscribe
* @param modMailThread The {@link ModMailThread} to un-subscribe the user from
* @throws dev.sheldan.abstracto.modmail.exception.NotSubscribedException in case the user is not subscribed to the thread
*/
void unsubscribeFromThread(AUserInAServer aUserInAServer, ModMailThread modMailThread);
}

View File

@@ -6,17 +6,85 @@ import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageChannel;
/**
* Service used to handle the mod mail life cycle, including creation, updating, sending/receiving messages and logging the mod mail thread
*/
public interface ModMailThreadService {
/**
* Creates a new mod mail thread for the given user. including: the {@link net.dv8tion.jda.api.entities.TextChannel}
* in the appropriate {@link net.dv8tion.jda.api.entities.Category} and calls the methods responsible for storing
* the necessary data in the database, notifying the users and sending messages related to the creation of the {@link ModMailThread}
* @param userInAServer The {@link AUserInAServer} to create the mod mail thread for
* @param initialMessage The initial message sparking this mod mail thread, null in case it was created by a command
* @param feedBackChannel The {@link MessageChannel} in which feedback about exceptions should be posted to
* @param userInitiated Whether or not the mod mail thread was initiated by a user
*/
void createModMailThreadForUser(FullUser userInAServer, Message initialMessage, MessageChannel feedBackChannel, boolean userInitiated);
boolean hasOpenThread(AUserInAServer aUserInAServer);
boolean hasOpenThread(AUser user);
void setModMailCategoryTo(AServer server, Long categoryId);
/**
* Changes the configuration value of the category used to create mod mail threads to the given ID.
* @param guild The {@link Guild} to change the category value for
* @param categoryId The ID of the category to use
*/
void setModMailCategoryTo(Guild guild, Long categoryId);
/**
* Creates a prompt message, where the user initiating the mod mail thread has to chose for which server
* the user wants to create a mod mail thread for. The message will be displayed in the same channel
* as the original message was displayed in. Only servers in which the mod mail feature is enabled, will be counted
* and if there are no servers available an error message will be displayed.
* @param user The {@link AUser} who wants to open a mod mail thread
* @param initialMessage The {@link Message} which was send by the user to open a mod mail thread with.
*/
void createModMailPrompt(AUser user, Message initialMessage);
/**
* Forwards the given {@link Message} send by the user to the appropriate text channel of the given {@link ModMailThread}.
* In case there was no channel found, this will cause a message to be shown to the user and the existing mod mail thread will be closed.
* This is the case, if the mod mail thread was still open in the database, but no text channel was found anymore.
* @param modMailThread The {@link ModMailThread} on which the user answered
* @param message The {@link Message} object which was sent by the user to answer with
*/
void relayMessageToModMailThread(ModMailThread modMailThread, Message message);
/**
* Forwards a message send by a moderator to the direct message channel opened with the user. If the message is
* marked as anonymous, the bot will take the place of the author, in other case the author is shown in the embed.
* @param modMailThread The {@link ModMailThread} to which the reply was sent to
* @param text The parsed text of the reply
* @param message The pure {@link Message} containing the command which caused the reply
* @param anonymous Whether or nor the message should be send anonymous
* @param feedBack The {@link MessageChannel} in which feedback about possible exceptions should be sent to
*/
void relayMessageToDm(ModMailThread modMailThread, String text, Message message, boolean anonymous, MessageChannel feedBack);
/**
* Closes the mod mail thread which means: deletes the {@link net.dv8tion.jda.api.entities.TextChannel} associated with the mod mail thread,
* and depending on the {@link dev.sheldan.abstracto.core.config.FeatureMode} of mod mail logs the content of the thread into the appropriate
* post target. This also takes an optional note, which will be displayed in the first message of the logging. This method changes the state of the
* {@link ModMailThread} to CLOSED and notifies the user about closing.
* @param modMailThread The {@link ModMailThread} which is being closed.
* @param feedBack The {@link MessageChannel} in which feedback about possible exceptions should be sent to
* @param note The text of the note used for the header message of the logged mod mail thread.
* @param notifyUser Whether or not the user should be notified
*/
void closeModMailThread(ModMailThread modMailThread, MessageChannel feedBack, String note, boolean notifyUser);
/**
* Closes the mod mail thread which means: deletes the {@link net.dv8tion.jda.api.entities.TextChannel} associated with the mod mail thread,
* and logs the content of the thread into the appropriate post target. This also takes an optional note, which will
* be displayed in the first message of the logging. This method changes the state of the {@link ModMailThread} to
* CLOSED and notifies the user about closing.
* @param modMailThread The {@link ModMailThread} which is being closed.
* @param feedBack The {@link MessageChannel} in which feedback about possible exceptions should be sent to
* @param note The text of the note used for the header message of the logged mod mail thread, this is only required when actually
* logging the mod mail thread
* @param notifyUser Whether or not the user should be notified
* @param logThread Whether or not the thread should be logged to the appropriate post target
*/
void closeModMailThread(ModMailThread modMailThread, MessageChannel feedBack, String note, boolean notifyUser, boolean logThread);
}

View File

@@ -7,7 +7,25 @@ import net.dv8tion.jda.api.entities.Message;
import java.util.List;
/**
* Management service to handle the creation and retrieval of {@link ModMailMessage} instances from the database
*/
public interface ModMailMessageManagementService {
/**
* Creates an instance of {@link ModMailMessage}, attaches it to the given {@link ModMailThread} and returns the created instance
* @param modMailThread The {@link ModMailThread} the message should be attached to
* @param message The {@link Message} which should be attached to the {@link ModMailThread}
* @param author The {@link AUserInAServer} who authored the {@link Message} originally
* @param anonymous Whether or not the message was sent anonymous (only possible by staff members)
* @param dmChannel Whether or not the message originated from the user, and therefore in an direct message channel
* @return
*/
ModMailMessage addMessageToThread(ModMailThread modMailThread, Message message, AUserInAServer author, Boolean anonymous, Boolean dmChannel);
/**
* Retrieves all messages which were sent in a {@link ModMailThread}
* @param modMailThread The {@link ModMailThread} to retrieve the messages for
* @return A list of {@link ModMailMessage} which were sent in the given thread
*/
List<ModMailMessage> getMessagesOfThread(ModMailThread modMailThread);
}

View File

@@ -6,9 +6,40 @@ import dev.sheldan.abstracto.modmail.models.database.ModMailRole;
import java.util.List;
/**
* Management service bean responsible to create, remove, retrieve and check mod mail roles which are used to determine
* which roles are getting pinged when a new mod mail thread is created.
*/
public interface ModMailRoleManagementService {
/**
* Adds the given {@link ARole} to the mod mail roles of the {@link AServer}. This method does not check if the role
* is already present.
* @param role The {@link ARole} to add to the mod mail roles
* @param server The {@link AServer} to which the given {@link ARole} should be added to the mod mail roles
*/
void addRoleToModMailRoles(ARole role, AServer server);
/**
* Removes the given {@link ARole} from the mod mail roles of the given {@link AServer}. Does nothing if the
* role is not used as a mod mail role on the server
* @param role The {@link ARole} to remove from the mod mail roles
* @param server The {@link AServer} from which the role should be removed from the mod mail roles
*/
void removeRoleFromModMailRoles(ARole role, AServer server);
/**
* Retrieves all roles which should be pinged when a new mod mail thread is created by a user and returns the list
* of {@link ModMailRole} for the given {@link AServer}.
* @param server The {@link AServer} for which to retrieve the mod mail roles for
* @return The list of found {@link ModMailRole} for the given {@link AServer}
*/
List<ModMailRole> getRolesForServer(AServer server);
/**
* Checks whether or not the given {@link ARole} has already been assigned as a {@link ModMailRole} in the given {@link AServer}
* @param role The {@link ARole} to check for
* @param server The {@link AServer} to check in
* @return Whether or not the given {@link ARole} is used as a {@link ModMailRole} in the given {@link AServer}
*/
boolean isRoleAlreadyAssigned(ARole role, AServer server);
}

View File

@@ -6,9 +6,38 @@ import dev.sheldan.abstracto.modmail.models.database.ModMailThreadSubscriber;
import java.util.List;
/**
* Management service used to retrieve/create/remove instances of {@link ModMailThreadSubscriber}
*/
public interface ModMailSubscriberManagementService {
/**
* Retrieves all the {@link ModMailThreadSubscriber} of the given {@link ModMailThread}
* @param modMailThread The {@link ModMailThread} to retrieve the subscribers of
* @return The list of {@link ModMailThreadSubscriber} which are currently configured for the given {@link ModMailThread}
*/
List<ModMailThreadSubscriber> getSubscribersForThread(ModMailThread modMailThread);
/**
* This method checks if a {@link AUserInAServer} is stored as a {@link ModMailThreadSubscriber} for the given
* {@link ModMailThread}
* @param aUserInAServer The {@link AUserInAServer} to check for
* @param modMailThread The {@link ModMailThread} to check in
* @return Whether or not the given {@link AUserInAServer} is a subscriber of the mod mail thread
*/
boolean isSubscribedToThread(AUserInAServer aUserInAServer, ModMailThread modMailThread);
/**
* Creates a {@link ModMailThreadSubscriber} with the given parameters and returns the created instance
* @param aUserInAServer The {@link AUserInAServer} to subscribe to a thread
* @param modMailThread The {@link ModMailThread} to which the user should be subscribed to
* @return The created instance of {@link ModMailThreadSubscriber}
*/
ModMailThreadSubscriber createSubscriber(AUserInAServer aUserInAServer, ModMailThread modMailThread);
/**
* Removes the instance of the {@link ModMailThreadSubscriber}, effectively un-subscribing the user from the thread
* @param aUserInAServer The {@link AUserInAServer} to un-subscribe
* @param modMailThread The {@link ModMailThread} to unsubscribe from
*/
void removeSubscriber(AUserInAServer aUserInAServer, ModMailThread modMailThread);
}

View File

@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.modmail.service.management;
import dev.sheldan.abstracto.core.exception.ChannelNotFoundException;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
@@ -9,16 +10,100 @@ import dev.sheldan.abstracto.modmail.models.database.ModMailThreadState;
import java.util.List;
import java.util.Optional;
/**
* Management service to create/retrieve/modify instances of {@link ModMailThread}
*/
public interface ModMailThreadManagementService {
/**
* Retrieves a {@link ModMailThread} found in the {@link net.dv8tion.jda.api.entities.MessageChannel} given by the ID of the channel
* @param channelId The id of the channel to retrieve the {@link ModMailThread} for
* @throws ChannelNotFoundException if an appropriate {@link AChannel} was not found
* @return The instance of {@link ModMailThread} if it exists, null if none was found
*/
ModMailThread getByChannelId(Long channelId);
/**
* Retrieves the {@link ModMailThread} by the given ID in an optional, if it exists, and an {@literal Optional#empty()} otherwise
* @param modMailThreadId The ID of the mod mail to search for
* @return An {@link Optional} containing the mod mail thread or empty
*/
Optional<ModMailThread> getById(Long modMailThreadId);
/**
* Retrieves a {@link ModMailThread} found in the {@link net.dv8tion.jda.api.entities.MessageChannel} given by the
* {@link AChannel} object
* @param channel The {@link AChannel} object to search a mod mail thread for
* @return The found mod mail thread, or null if none was found
*/
ModMailThread getByChannel(AChannel channel);
/**
* Searches for mod mail threads with the appropriate staten which concern the given {@link AUserInAServer}
* @param userInAServer The {@link AUserInAServer} to search mod mail threads for
* @param state The {@link ModMailThreadState} to be used as a criteria
* @return A list of {@link ModMailThread} which were found by the given criteria
*/
List<ModMailThread> getThreadByUserAndState(AUserInAServer userInAServer, ModMailThreadState state);
ModMailThread getOpenModmailThreadForUser(AUserInAServer userInAServer);
ModMailThread getOpenModmailThreadForUser(AUser user);
/**
* Retrieves the *only* open mod mail thread for the given {@link AUserInAServer}, and null if none is in the state open
* @param userInAServer The {@link AUserInAServer} to search an open {@link ModMailThread} for
* @return The found open {@link ModMailThread}, or null if none is found
*/
ModMailThread getOpenModMailThreadForUser(AUserInAServer userInAServer);
/**
* Returns whether or not the {@link AUserInAServer} has a {@link ModMailThread} in a state which is not CLOSED
* @param userInAServer The {@link AUserInAServer} to check for
* @return Boolean whether or not the {@link AUserInAServer} has an open thread
*/
boolean hasOpenModMailThreadForUser(AUserInAServer userInAServer);
/**
* Retrieves all the open {@link ModMailThread} for the {@link AUser}, which means over all the known guilds
* @param user The {@link AUser} for which the open mod mail threads should be retrieved
* @return A list of {@link ModMailThread} which contains all the current threads which are not CLOSED
*/
List<ModMailThread> getOpenModMailThreadsForUser(AUser user);
/**
* Returns whether or not the {@link AUser} has a {@link ModMailThread} in a state which is not CLOSED
* @param user The {@link AUser} to check for open mod mail treads
* @return Boolean whether or not the {@link AUser} has an open thread
*/
boolean hasOpenModMailThread(AUser user);
/**
* Retrieves all the open {@link ModMailThread} for the {@link AUserInAServer}, which means only in one guild, this
* should be at most one
* @param aUserInAServer The {@link AUserInAServer} to retrieve the mod mail threads for
* @return A list of {@link ModMailThread} which contains all the current mod mail threads for the member, should be at most one
*/
List<ModMailThread> getModMailThreadForUser(AUserInAServer aUserInAServer);
/**
* Retrieves the *latest* {@link ModMailThread} of the {@link AUserInAServer}, which means, the latest thread which is in the state
* CLOSED, null other wise.
* @param aUserInAServer The {@link AUserInAServer} to retrieve the latest thread for
* @return If a thread in state CLOSED exists, the latest one, null other wise
*/
ModMailThread getLatestModMailThread(AUserInAServer aUserInAServer);
/**
* Creates an instance of {@link ModMailThread} with the appropriate parameters and returns the created instance.
* @param userInAServer The {@link AUserInAServer} for which the thread was created for
* @param channel An instance of {@link AChannel} in which the conversation with the member is handled
* @return The created instance of {@link ModMailThread}
*/
ModMailThread createModMailThread(AUserInAServer userInAServer, AChannel channel);
/**
* Updates the {@link ModMailThread} with the new state and saves the instance.
* @param modMailThread The {@link ModMailThread} to change the state for
* @param newState The new {@link ModMailThreadState} to change the thread to
*/
void setModMailThreadState(ModMailThread modMailThread, ModMailThreadState newState);
}

View File

@@ -2,5 +2,8 @@ package dev.sheldan.abstracto.modmail.setup;
import dev.sheldan.abstracto.core.interactive.SetupStep;
/**
* Setup step responsible to setup the required {@link java.util.Locale.Category} for mod mail
*/
public interface ModMailCategorySetup extends SetupStep {
}

View File

@@ -4,6 +4,15 @@ import dev.sheldan.abstracto.core.models.FeatureValidationResult;
import dev.sheldan.abstracto.core.service.FeatureValidator;
import net.dv8tion.jda.api.entities.Guild;
/**
* Validator service which validates, whether or not the configured mod mail category is actually a valid category.
*/
public interface ModMailFeatureValidator extends FeatureValidator {
/**
* Validates the category and checks if the given ID is a valid category in the given {@link Guild}
* @param validationResult The object in which the result of the validation will be stored
* @param guild The {@link Guild} to check for the category
* @param modMailCategory The configured ID of the category
*/
void validateModMailCategory(FeatureValidationResult validationResult, Guild guild, Long modMailCategory);
}