[AB-150] creating repost detection feature including configuration and documentation

adding http and hash service
adding ability to add default emotes to a message to message service
adding message embedded listener to wrap the embedded event
adding custom channel groups which can be defined by modules, in case a change on a channel group (only created and updated) happens a listener is available in order to sync the state in dependant areas
changing command receiver re-throwing abstracto runtime exceptions in order to display them better
changing channel group parameter handler to throw an exception in case the channel group was not found
adding User in a server parameter handler
split channel not found exception to be able to differentiate between not found in database and not found in guild
changing exception handling in command received handler to handle the case for only one parameter handler future which failed (the whole single future failed, which was not reported)
changing parameter type of `removeFromChannelGroup` to AChannel in order to be able to delete channels in the database via ID
moving method to mock utils for mocking consumer
removing parameter validation from commands, as it should be done in the command received handler and parameter handlers anyway
This commit is contained in:
Sheldan
2020-12-04 00:38:18 +01:00
parent e966c710ce
commit 325264a325
249 changed files with 5310 additions and 686 deletions

View File

@@ -9,6 +9,6 @@ public interface CommandParameterHandler {
boolean handles(Class clazz);
default boolean async() { return false; }
default Object handle(String input, CommandParameterIterators iterators, Class clazz, Message context) { return new Object();}
default CompletableFuture handleAsync(String input, CommandParameterIterators iterators, Class clazz, Message context) { return CompletableFuture.completedFuture(null); }
default CompletableFuture<Object> handleAsync(String input, CommandParameterIterators iterators, Class clazz, Message context) { return CompletableFuture.completedFuture(null); }
Integer getPriority();
}

View File

@@ -2,5 +2,5 @@ package dev.sheldan.abstracto.core.command.handler.provided;
import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler;
public interface AChanelParameterHandler extends CommandParameterHandler {
public interface AChannelParameterHandler extends CommandParameterHandler {
}

View File

@@ -0,0 +1,6 @@
package dev.sheldan.abstracto.core.command.handler.provided;
import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler;
public interface AUserInAServerParameterHandler extends CommandParameterHandler {
}

View File

@@ -0,0 +1,6 @@
package dev.sheldan.abstracto.core.command.handler.provided;
import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler;
public interface ChannelGroupParameterHandler extends CommandParameterHandler {
}

View File

@@ -0,0 +1,6 @@
package dev.sheldan.abstracto.core.command.handler.provided;
import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler;
public interface ChannelGroupTypeParameterHandler extends CommandParameterHandler {
}

View File

@@ -0,0 +1,25 @@
package dev.sheldan.abstracto.core.exception;
import dev.sheldan.abstracto.core.models.exception.ChannelGroupTypeNotFoundExceptionModel;
import dev.sheldan.abstracto.templating.Templatable;
import java.util.List;
public class ChannelGroupTypeNotFound extends AbstractoRunTimeException implements Templatable {
private final ChannelGroupTypeNotFoundExceptionModel model;
public ChannelGroupTypeNotFound(List<String> channelGroupTypeKeys) {
this.model = ChannelGroupTypeNotFoundExceptionModel.builder().availableGroupTypeKeys(channelGroupTypeKeys).build();
}
@Override
public String getTemplateName() {
return "channel_group_type_not_found_exception";
}
@Override
public Object getTemplateModel() {
return this.model;
}
}

View File

@@ -0,0 +1,24 @@
package dev.sheldan.abstracto.core.exception;
import dev.sheldan.abstracto.core.models.exception.ChannelNotFoundExceptionModel;
import dev.sheldan.abstracto.templating.Templatable;
public class ChannelNotInGuildException extends AbstractoRunTimeException implements Templatable {
private final ChannelNotFoundExceptionModel model;
public ChannelNotInGuildException(Long channelId) {
super("Channel not found in guild");
this.model = ChannelNotFoundExceptionModel.builder().channelId(channelId).build();
}
@Override
public String getTemplateName() {
return "channel_not_in_guild_exception";
}
@Override
public Object getTemplateModel() {
return model;
}
}

View File

@@ -0,0 +1,7 @@
package dev.sheldan.abstracto.core.listener;
import dev.sheldan.abstracto.core.models.listener.GuildMessageEmbedEventModel;
public interface MessageEmbeddedListener extends FeatureAware, Prioritized {
void execute(GuildMessageEmbedEventModel eventModel);
}

View File

@@ -0,0 +1,7 @@
package dev.sheldan.abstracto.core.listener.entity;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
public interface ChannelGroupCreatedListener {
void channelGroupCreated(AChannelGroup channelGroup);
}

View File

@@ -0,0 +1,7 @@
package dev.sheldan.abstracto.core.listener.entity;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
public interface ChannelGroupDeletedListener {
void channelGroupDeleted(AChannelGroup channelGroup);
}

View File

@@ -0,0 +1,25 @@
package dev.sheldan.abstracto.core.models;
import dev.sheldan.abstracto.core.models.database.AChannel;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.TextChannel;
import java.io.Serializable;
@Getter
@Setter
@Builder
public class FullChannel implements Serializable {
private AChannel channel;
private transient TextChannel serverChannel;
public String getChannelRepr() {
if(serverChannel != null) {
return serverChannel.getAsMention();
} else {
return channel.getId().toString();
}
}
}

View File

@@ -9,7 +9,7 @@ import java.time.Instant;
import java.util.List;
@Entity
@Table(name="channelGroup")
@Table(name="channel_group")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@@ -28,11 +28,15 @@ public class AChannelGroup implements Serializable {
private String groupName;
@ManyToOne(fetch = FetchType.LAZY)
@Getter
@Setter
@JoinColumn(name = "group_server", nullable = false)
@JoinColumn(name = "server_id", nullable = false)
private AServer server;
@ManyToOne(fetch = FetchType.LAZY)
@Setter
@JoinColumn(name = "group_type_id")
private ChannelGroupType channelGroupType;
@Column(name = "created")
private Instant created;

View File

@@ -21,6 +21,7 @@ public class AUserInAServer implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_in_server_id")
private Long userInServerId;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})

View File

@@ -0,0 +1,27 @@
package dev.sheldan.abstracto.core.models.database;
import lombok.*;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.*;
@Entity
@Table(name = "channel_group_type")
@Getter
@Builder
@Setter
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class ChannelGroupType {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column(name = "group_type_key")
private String groupTypeKey;
}

View File

@@ -0,0 +1,17 @@
package dev.sheldan.abstracto.core.models.exception;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Setter
@Getter
@Builder
public class ChannelGroupTypeNotFoundExceptionModel implements Serializable {
@Builder.Default
private List<String> availableGroupTypeKeys = new ArrayList<>();
}

View File

@@ -0,0 +1,20 @@
package dev.sheldan.abstracto.core.models.listener;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.TextChannel;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@Builder
public class GuildMessageEmbedEventModel {
@Builder.Default
private List<MessageEmbed> embeds = new ArrayList<>();
private Long messageId;
private TextChannel channel;
}

View File

@@ -11,5 +11,6 @@ import java.util.List;
@Builder
public class ChannelGroupModel {
private String name;
private String typeKey;
private List<ChannelGroupChannelModel> channels;
}

View File

@@ -32,7 +32,8 @@ public interface BotService {
Optional<Emote> getEmote(Long serverId, AEmote emote);
Optional<Emote> getEmote(AEmote emote);
Optional<TextChannel> getTextChannelFromServerOptional(Guild serverId, Long textChannelId);
TextChannel getTextChannelFromServer(Guild serverId, Long textChannelId);
TextChannel getTextChannelFromServer(Guild guild, Long textChannelId);
TextChannel getTextChannelFromServerNullable(Guild guild, Long textChannelId);
Optional<TextChannel> getTextChannelFromServerOptional(Long serverId, Long textChannelId);
TextChannel getTextChannelFromServer(Long serverId, Long textChannelId);
Optional<Guild> getGuildByIdOptional(Long serverId);

View File

@@ -2,10 +2,13 @@ package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.ChannelGroupType;
import net.dv8tion.jda.api.entities.TextChannel;
import java.util.List;
public interface ChannelGroupService {
AChannelGroup createChannelGroup(String name, Long serverId);
AChannelGroup createChannelGroup(String name, Long serverId, ChannelGroupType channelGroupType);
void deleteChannelGroup(String name, Long serverId);
void addChannelToChannelGroup(String channelGroupName, TextChannel textChannel);
void addChannelToChannelGroup(String channelGroupName, Long channelId, Long serverId);
@@ -16,4 +19,5 @@ public interface ChannelGroupService {
void disableCommandInChannelGroup(String commandName, String channelGroupName, Long serverId);
void enableCommandInChannelGroup(String commandName, String channelGroupName, Long serverId);
boolean doesGroupExist(String groupName, Long serverId);
List<AChannelGroup> getChannelGroupsOfChannelWithType(AChannel channel, String groupTypeKey);
}

View File

@@ -0,0 +1,9 @@
package dev.sheldan.abstracto.core.service;
import java.io.File;
import java.io.IOException;
public interface HashService {
String sha256HashFileContent(File file) throws IOException;
String sha256HashString(String text);
}

View File

@@ -0,0 +1,8 @@
package dev.sheldan.abstracto.core.service;
import java.io.File;
import java.io.IOException;
public interface HttpService {
File downloadFileToTempFile(String url) throws IOException;
}

View File

@@ -11,6 +11,8 @@ import java.util.concurrent.CompletableFuture;
public interface MessageService {
void addReactionToMessage(String emoteKey, Long serverId, Message message);
void addDefaultReactionToMessage(String unicode, Message message);
CompletableFuture<Void> addDefaultReactionToMessageAsync(String unicode, Message message);
CompletableFuture<Void> addReactionToMessageWithFuture(String emoteKey, Long serverId, Message message);
CompletableFuture<Void> addReactionToMessageWithFuture(String emoteKey, Guild guild, Message message);
CompletableFuture<Void> addReactionToMessageWithFuture(AEmote emote, Long serverId, Message message);

View File

@@ -3,17 +3,23 @@ package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.ChannelGroupType;
import java.util.List;
import java.util.Optional;
public interface ChannelGroupManagementService {
AChannelGroup createChannelGroup(String name, AServer server);
AChannelGroup createChannelGroup(String name, AServer server, ChannelGroupType channelGroupType);
boolean doesChannelGroupExist(String name, AServer server);
void deleteChannelGroup(String name, AServer server);
AChannelGroup addChannelToChannelGroup(AChannelGroup channelGroup, AChannel channel);
void removeChannelFromChannelGroup(AChannelGroup channelGroup, AChannel channel);
AChannelGroup findByNameAndServer(String name, AServer server);
Optional<AChannelGroup> findByNameAndServerOptional(String name, AServer server);
AChannelGroup findByNameAndServerAndType(String name, AServer server, String expectedType);
List<AChannelGroup> findAllInServer(AServer server);
List<String> getAllAvailableAsString(AServer server);
List<AChannelGroup> findAllInServer(Long serverId);
List<AChannelGroup> getAllChannelGroupsOfChannel(AChannel channel);
List<AChannelGroup> findAllInServerWithType(Long serverId, String type);
}

View File

@@ -0,0 +1,14 @@
package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.models.database.ChannelGroupType;
import java.util.List;
import java.util.Optional;
public interface ChannelGroupTypeManagementService {
Optional<ChannelGroupType> findChannelGroupTypeByKeyOptional(String key);
ChannelGroupType findChannelGroupTypeByKey(String key);
boolean doesChannelGroupTypeExist(String key);
List<ChannelGroupType> getAllChannelGroupTypes();
List<String> getAllChannelGroupTypesAsString();
}

View File

@@ -17,4 +17,5 @@ public interface UserInServerManagementService {
AUserInAServer createUserInServer(Member member);
AUserInAServer createUserInServer(Long guildId, Long userId);
List<AUserInAServer> getUserInAllServers(Long userId);
Optional<AUserInAServer> loadAUserInAServerOptional(Long serverId, Long userId);
}

View File

@@ -3,8 +3,11 @@ package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.models.database.AUser;
import net.dv8tion.jda.api.entities.Member;
import java.util.Optional;
public interface UserManagementService {
AUser createUser(Member member);
AUser createUser(Long userId);
AUser loadUser(Long userId);
Optional<AUser> loadUserOptional(Long userId);
}

View File

@@ -14,7 +14,10 @@ public class FileUtils {
fw.write(content);
fw.flush();
}
}
public void writeBytesToFile(File file, byte[] content) throws IOException {
Files.write(content, file);
}
public File createTempFile(String fileName) {

View File

@@ -1,6 +1,12 @@
package dev.sheldan.abstracto.core.test;
import dev.sheldan.abstracto.core.models.database.*;
import net.dv8tion.jda.api.requests.RestAction;
import java.util.function.Consumer;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
public class MockUtils {
@@ -30,4 +36,26 @@ public class MockUtils {
public static ARole getRole(Long id, AServer server) {
return ARole.builder().server(server).id(id).build();
}
public static void mockQueueDoubleVoidConsumer(RestAction action) {
doAnswer(invocationOnMock -> {
Object consumerObj = invocationOnMock.getArguments()[0];
if(consumerObj instanceof Consumer) {
Consumer<Void> consumer = (Consumer) consumerObj;
consumer.accept(null);
}
return null;
}).when(action).queue(any(Consumer.class), any(Consumer.class));
}
public static void mockQueueVoidConsumer(RestAction action) {
doAnswer(invocationOnMock -> {
Object consumerObj = invocationOnMock.getArguments()[0];
if(consumerObj instanceof Consumer) {
Consumer<Void> consumer = (Consumer) consumerObj;
consumer.accept(null);
}
return null;
}).when(action).queue(any(Consumer.class));
}
}

View File

@@ -42,28 +42,6 @@ public class CommandTestUtilities {
com.execute(context);
}
public static void executeNoParametersTestAsync(Command com) {
CommandContext context = CommandTestUtilities.getNoParameters();
com.executeAsync(context);
}
public static void executeWrongParametersTest(Command com) {
executeWrongParametersTest(com, new ArrayList<>());
}
public static void executeWrongParametersTest(Command com, Object value) {
CommandContext context = CommandTestUtilities.getWithParameters(Arrays.asList(value));
com.execute(context);
}
public static void executeWrongParametersTestAsync(Command com) {
executeWrongParametersTestAsync(com, new ArrayList<>());
}
public static void executeWrongParametersTestAsync(Command com, Object value) {
CommandContext context = CommandTestUtilities.getWithParameters(Arrays.asList(value));
com.executeAsync(context);
}
public static CommandContext getNoParameters() {
AServer server = MockUtils.getServer();