mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-03-27 14:23:56 +00:00
[AB-xxx] adding support for automatic setup steps
reducing eventwaiter threads adding abstracto templated exception adding json validation service increasing threads for scheduling adding convenience method to retrieve users
This commit is contained in:
@@ -215,6 +215,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
.newExperience(newExperienceCount)
|
||||
.newMessageCount(newMessageCount)
|
||||
.newLevel(newLevel.getLevel())
|
||||
.serverId(serverId)
|
||||
.userInServerId(userInAServer.getUserInServerId())
|
||||
.build();
|
||||
resultFutures.add(calculationResult);
|
||||
|
||||
@@ -52,7 +52,7 @@ public class PostedImage {
|
||||
@Getter
|
||||
@OneToMany(fetch = FetchType.LAZY,
|
||||
orphanRemoval = true,
|
||||
cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE},
|
||||
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
|
||||
mappedBy = "originalPost")
|
||||
private List<Repost> reposts;
|
||||
|
||||
|
||||
@@ -169,6 +169,11 @@ public class ChannelGroupServiceBean implements ChannelGroupService {
|
||||
return channelGroupManagementService.findByNameAndServer(groupName, server) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChannelInGroup(AChannel channel, AChannelGroup aChannelGroup) {
|
||||
return aChannelGroup.getChannels().contains(channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AChannelGroup> getChannelGroupsOfChannelWithType(AChannel channel, String groupTypeKey) {
|
||||
List<AChannelGroup> channelGroups = channelGroupManagementService.getAllChannelGroupsOfChannel(channel);
|
||||
|
||||
@@ -511,6 +511,33 @@ public class ChannelServiceBean implements ChannelService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CompletableFuture<Message>> sendFileToChannel(String fileContent, String fileName, TextChannel channel) {
|
||||
File tempFile = fileService.createTempFile(fileName);
|
||||
try {
|
||||
fileService.writeContentToFile(tempFile, fileContent);
|
||||
long maxFileSize = channel.getGuild().getMaxFileSize();
|
||||
// in this case, we cannot upload the file, so we need to fail
|
||||
if(tempFile.length() > maxFileSize) {
|
||||
throw new UploadFileTooLargeException(tempFile.length(), maxFileSize);
|
||||
}
|
||||
MessageToSend messageToSend = MessageToSend
|
||||
.builder()
|
||||
.fileToSend(tempFile)
|
||||
.build();
|
||||
return sendMessageToSendToChannel(messageToSend, channel);
|
||||
} catch (IOException e) {
|
||||
log.error("Failed to write local temporary file for template download.", e);
|
||||
throw new AbstractoRunTimeException(e);
|
||||
} finally {
|
||||
try {
|
||||
fileService.safeDelete(tempFile);
|
||||
} catch (IOException e) {
|
||||
log.error("Failed to safely delete local temporary file for template download.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
|
||||
@@ -106,23 +106,33 @@ public class FeatureSetupServiceBean implements FeatureSetupService {
|
||||
TextChannel textChannel = textChannelInGuild.get();
|
||||
String text = templateService.renderTemplate(FEATURE_SETUP_INITIAL_MESSAGE_TEMPLATE_KEY, setupInitialMessageModel, user.getGuildId());
|
||||
channelService.sendTextToChannel(text, textChannel);
|
||||
return executeFeatureSetup(featureConfig, steps, user, new ArrayList<>());
|
||||
ArrayList<DelayedActionConfig> delayedActionConfigs = new ArrayList<>();
|
||||
featureConfig
|
||||
.getAutoSetupSteps()
|
||||
.forEach(autoDelayedAction -> delayedActionConfigs.add(autoDelayedAction.getDelayedActionConfig(user)));
|
||||
return executeFeatureSetup(featureConfig, steps, user, delayedActionConfigs);
|
||||
}
|
||||
throw new ChannelNotInGuildException(user.getChannelId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> executeFeatureSetup(FeatureConfig featureConfig, List<SetupExecution> steps, AServerChannelUserId user, List<DelayedActionConfig> delayedActionConfigs) {
|
||||
SetupExecution nextStep = steps.get(0);
|
||||
return executeStep(user, nextStep, delayedActionConfigs, featureConfig);
|
||||
if(!steps.isEmpty()) {
|
||||
SetupExecution nextStep = steps.get(0);
|
||||
return executeStep(user, nextStep, delayedActionConfigs, featureConfig);
|
||||
} else {
|
||||
log.info("Feature had no setup steps. Executing post setups steps immediately. As there can be automatic steps.");
|
||||
self.executePostSetupSteps(delayedActionConfigs, user, null, featureConfig);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> executeStep(AServerChannelUserId aUserInAServer, SetupExecution execution, List<DelayedActionConfig> delayedActionConfigs, FeatureConfig featureConfig) {
|
||||
log.debug("Executing step {} in server {} in channel {} for user {}.", execution.getStep().getClass(), aUserInAServer.getGuildId(), aUserInAServer.getChannelId(), aUserInAServer.getUserId());
|
||||
return execution.getStep().execute(aUserInAServer, execution.getParameter()).thenAccept(aVoid -> {
|
||||
if(aVoid.getResult().equals(SetupStepResultType.SUCCESS)) {
|
||||
return execution.getStep().execute(aUserInAServer, execution.getParameter()).thenAccept(setpResult -> {
|
||||
if(setpResult.getResult().equals(SetupStepResultType.SUCCESS)) {
|
||||
log.info("Step {} in server {} has been executed successfully. Proceeding.", execution.getStep().getClass(), aUserInAServer.getGuildId());
|
||||
delayedActionConfigs.addAll(aVoid.getDelayedActionConfigList());
|
||||
delayedActionConfigs.addAll(setpResult.getDelayedActionConfigList());
|
||||
if(execution.getNextStep() != null) {
|
||||
log.debug("Executing next step {}.", execution.getNextStep().getStep().getClass());
|
||||
executeStep(aUserInAServer, execution.getNextStep(), delayedActionConfigs, featureConfig);
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package dev.sheldan.abstracto.core.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.JSONValidationResult;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.everit.json.schema.Schema;
|
||||
import org.everit.json.schema.ValidationException;
|
||||
import org.everit.json.schema.loader.SchemaLoader;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONTokener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class JSONValidationServiceBean implements JSONValidationService {
|
||||
|
||||
@Override
|
||||
public JSONValidationResult validateJSONSchema(InputStream schemaStream, File jsonFile) throws IOException {
|
||||
return validateJSONSchema(schemaStream, new FileInputStream(jsonFile));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONValidationResult validateJSONSchema(InputStream schema, InputStream jsonFile) {
|
||||
JSONObject jsonSchemaStream = new JSONObject(new JSONTokener(schema));
|
||||
JSONTokener tokener = new JSONTokener(jsonFile);
|
||||
return validateJSONSchema(jsonSchemaStream, tokener.nextValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONValidationResult validateJSONSchema(JSONObject jsonSchema, Object json) {
|
||||
Schema schema = SchemaLoader.load(jsonSchema);
|
||||
JSONValidationResult jsonValidationResult = JSONValidationResult
|
||||
.builder()
|
||||
.result(Result.SUCCESSFUL)
|
||||
.build();
|
||||
try {
|
||||
schema.validate(json);
|
||||
} catch (ValidationException e) {
|
||||
jsonValidationResult.setResult(Result.ERRONEOUS);
|
||||
if(e.getCausingExceptions().isEmpty()) {
|
||||
jsonValidationResult.setExceptions(new ArrayList<>(Arrays.asList(e)));
|
||||
} else {
|
||||
jsonValidationResult.setExceptions(e.getCausingExceptions());
|
||||
}
|
||||
}
|
||||
return jsonValidationResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONValidationResult validateJSONSchema(String schema, String json) {
|
||||
return validateJSONSchema(new JSONObject(schema), new JSONTokener(json).nextValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONValidationResult validateJSONSchema(File schema, File jsonFile) throws IOException {
|
||||
try (InputStream schemaStream = new FileInputStream(schema); InputStream jsonInputStream = new FileInputStream(jsonFile)) {
|
||||
return validateJSONSchema(schemaStream, jsonInputStream);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ValidationException> getDetailedException(List<ValidationException> exceptions) {
|
||||
return exceptions
|
||||
.stream()
|
||||
.map(this::getDeepestExceptions)
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<ValidationException> getDeepestExceptions(ValidationException validationException) {
|
||||
if(validationException.getCausingExceptions().isEmpty()) {
|
||||
return Arrays.asList(validationException);
|
||||
}
|
||||
|
||||
return validationException
|
||||
.getCausingExceptions()
|
||||
.stream()
|
||||
.map(this::getDeepestExceptions)
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
package dev.sheldan.abstracto.core.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
|
||||
import net.dv8tion.jda.api.entities.SelfUser;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class UserServiceBean implements UserService {
|
||||
@@ -16,4 +20,18 @@ public class UserServiceBean implements UserService {
|
||||
public CompletableFuture<User> retrieveUserForId(Long id) {
|
||||
return botService.getInstance().retrieveUserById(id).submit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFutureList<User> retrieveUsers(List<Long> ids) {
|
||||
List<CompletableFuture<User>> userFutures = ids
|
||||
.stream()
|
||||
.map(this::retrieveUserForId)
|
||||
.collect(Collectors.toList());
|
||||
return new CompletableFutureList<>(userFutures);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelfUser getSelfUser() {
|
||||
return botService.getInstance().getSelfUser();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
abstracto.startup.synchronize=true
|
||||
|
||||
abstracto.eventWaiter.threads=10
|
||||
abstracto.eventWaiter.threads=3
|
||||
server.port=8080
|
||||
|
||||
abstracto.allowedmention.everyone=false
|
||||
|
||||
@@ -48,5 +48,9 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.everit-org.json-schema</groupId>
|
||||
<artifactId>org.everit.json.schema</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.sheldan.abstracto.core.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.interactive.AutoDelayedAction;
|
||||
import dev.sheldan.abstracto.core.interactive.SetupStep;
|
||||
import dev.sheldan.abstracto.core.service.FeatureValidator;
|
||||
|
||||
@@ -21,4 +22,5 @@ public interface FeatureConfig extends Serializable {
|
||||
default List<String> getRequiredEmotes() { return Collections.emptyList(); }
|
||||
default List<FeatureMode> getAvailableModes() { return Collections.emptyList(); }
|
||||
default List<SetupStep> getCustomSetupSteps() { return Collections.emptyList(); }
|
||||
default List<AutoDelayedAction> getAutoSetupSteps() { return Collections.emptyList(); }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package dev.sheldan.abstracto.core.exception;
|
||||
|
||||
import dev.sheldan.abstracto.core.templating.Templatable;
|
||||
|
||||
public abstract class AbstractoTemplatableException extends AbstractoRunTimeException implements Templatable {
|
||||
public AbstractoTemplatableException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public AbstractoTemplatableException() {
|
||||
}
|
||||
|
||||
public AbstractoTemplatableException(Throwable throwable) {
|
||||
super(throwable);
|
||||
}
|
||||
|
||||
public AbstractoTemplatableException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package dev.sheldan.abstracto.core.interactive;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.AServerChannelUserId;
|
||||
|
||||
public interface AutoDelayedAction {
|
||||
DelayedActionConfig getDelayedActionConfig(AServerChannelUserId aServerChannelUserId);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package dev.sheldan.abstracto.core.models;
|
||||
|
||||
import dev.sheldan.abstracto.core.service.JSONValidationService;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.everit.json.schema.ValidationException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class JSONValidationResult {
|
||||
private JSONValidationService.Result result;
|
||||
private List<ValidationException> exceptions;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,13 +7,13 @@ import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Entity
|
||||
@Table(name="channel")
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode
|
||||
public class AChannel implements SnowFlake, Serializable {
|
||||
|
||||
@Id
|
||||
@@ -50,5 +50,16 @@ public class AChannel implements SnowFlake, Serializable {
|
||||
@Transient
|
||||
private boolean fake;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
AChannel channel = (AChannel) o;
|
||||
return id.equals(channel.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ public interface ChannelGroupService {
|
||||
void enableChannelGroup(String channelGroupName, Long serverId);
|
||||
boolean isChannelInEnabledChannelGroupOfType(String channelGroupType, Long channelId);
|
||||
boolean doesGroupExist(String groupName, Long serverId);
|
||||
boolean isChannelInGroup(AChannel channel, AChannelGroup aChannelGroup);
|
||||
List<AChannelGroup> getChannelGroupsOfChannelWithType(AChannel channel, String groupTypeKey);
|
||||
List<ChannelGroupModel> convertAChannelGroupToChannelGroupChannel(List<AChannelGroup> channelGroups);
|
||||
}
|
||||
|
||||
@@ -65,4 +65,5 @@ public interface ChannelService {
|
||||
TextChannel getTextChannelFromServer(Long serverId, Long textChannelId);
|
||||
CompletableFuture<Void> setSlowModeInChannel(TextChannel textChannel, Integer seconds);
|
||||
List<CompletableFuture<Message>> sendFileToChannel(String fileContent, String fileNameTemplate, String messageTemplate, Object model, TextChannel channel);
|
||||
List<CompletableFuture<Message>> sendFileToChannel(String fileContent, String fileName, TextChannel channel);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package dev.sheldan.abstracto.core.service;
|
||||
|
||||
|
||||
import dev.sheldan.abstracto.core.models.JSONValidationResult;
|
||||
import org.everit.json.schema.ValidationException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
public interface JSONValidationService {
|
||||
JSONValidationResult validateJSONSchema(InputStream schema, File jsonFile) throws IOException;
|
||||
JSONValidationResult validateJSONSchema(InputStream schema, InputStream jsonFile);
|
||||
JSONValidationResult validateJSONSchema(JSONObject schema, Object json) throws IOException;
|
||||
JSONValidationResult validateJSONSchema(String schema, String json);
|
||||
JSONValidationResult validateJSONSchema(File schema, File jsonFile) throws IOException;
|
||||
List<ValidationException> getDetailedException(List<ValidationException> exceptions);
|
||||
|
||||
enum Result {
|
||||
SUCCESSFUL, ERRONEOUS
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,14 @@
|
||||
package dev.sheldan.abstracto.core.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
|
||||
import net.dv8tion.jda.api.entities.SelfUser;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface UserService {
|
||||
CompletableFuture<User> retrieveUserForId(Long id);
|
||||
CompletableFutureList<User> retrieveUsers(List<Long> ids);
|
||||
SelfUser getSelfUser();
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ public class MessageToSend {
|
||||
/**
|
||||
* The string content to be used in the first message.
|
||||
*/
|
||||
private List<String> messages;
|
||||
@Builder.Default
|
||||
private List<String> messages = new ArrayList<>();
|
||||
/**
|
||||
* The file handle to send attached to the message.
|
||||
*/
|
||||
|
||||
@@ -49,6 +49,10 @@
|
||||
<name>m2-dv8tion</name>
|
||||
<url>https://m2.dv8tion.net/releases</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jitpack.io</id>
|
||||
<url>https://jitpack.io</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<properties>
|
||||
@@ -75,6 +79,7 @@
|
||||
<code.coverage.overall.data>${basedir}/../target/jacoco.exec</code.coverage.overall.data>
|
||||
<google.api.client.version>1.31.3</google.api.client.version>
|
||||
<google.api.youtube.version>v3-rev222-1.25.0</google.api.youtube.version>
|
||||
<everit.json.schema.version>1.12.2</everit.json.schema.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
@@ -261,6 +266,12 @@
|
||||
<version>${google.api.youtube.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.everit-org.json-schema</groupId>
|
||||
<artifactId>org.everit.json.schema</artifactId>
|
||||
<version>${everit.json.schema.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ spring.quartz.jdbc.initialize-schema=never
|
||||
spring.quartz.properties.org.quartz.scheduler.instanceName=quartz-abstracto-app
|
||||
spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO
|
||||
spring.quartz.properties.org.quartz.scheduler.instanceIdGenerator.class=dev.sheldan.abstracto.scheduling.service.IdGenerationService
|
||||
spring.quartz.properties.org.quartz.threadPool.threadCount=3
|
||||
spring.quartz.properties.org.quartz.threadPool.threadCount=4
|
||||
spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
|
||||
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
|
||||
spring.quartz.properties.org.quartz.jobStore.useProperties=true
|
||||
|
||||
Reference in New Issue
Block a user