Compare commits

...

13 Commits

Author SHA1 Message Date
Sheldan
af5f9a8361 [maven-release-plugin] prepare release v1.5.13 2023-12-10 14:32:05 +01:00
Sheldan
e84b5ecbb5 [AB-30] adding giveaway feature 2023-12-10 14:25:08 +01:00
Sheldan
1ba8219d7b [AB-xxx] fixing using wrong parameter for unSuggest command 2023-11-15 01:06:30 +01:00
Sheldan
60d2c669a2 [maven-release-plugin] prepare for next development iteration 2023-10-29 18:23:09 +01:00
Sheldan
3a122a72e5 [maven-release-plugin] prepare release v1.5.12 2023-10-29 18:23:03 +01:00
Sheldan
d53126e5a5 [AB-xxx] actively limiting auto complete responses to the max allowed values
changing interface of slash command parameter service to be more applicable
adding utility functions to slash command auto complete service bean
2023-10-29 18:21:29 +01:00
Sheldan
208d9a28ed [maven-release-plugin] prepare for next development iteration 2023-10-23 01:27:29 +02:00
Sheldan
6643359953 [maven-release-plugin] prepare release v1.5.11 2023-10-23 01:27:22 +02:00
Sheldan
bd7149d159 [AB-xxx] prepare for release 2023-10-23 01:26:12 +02:00
Sheldan
c0b6a19bca [AB-82] adding instant for cooldown exception model
removing not needed models for payday and slots cooldown exceptions
2023-10-04 23:34:16 +02:00
Sheldan
58eece0814 [AB-xxx] setting duration to zero if it was not provided, for infraction storage 2023-10-04 22:45:51 +02:00
Sheldan
abfd2c9591 [AB-xxx] ignore slash command only commands for message commands 2023-09-26 23:37:04 +02:00
Sheldan
a71a448b4b [maven-release-plugin] prepare for next development iteration 2023-09-26 22:51:02 +02:00
130 changed files with 3151 additions and 122 deletions

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>anti-raid</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>anti-raid</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>assignable-roles</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>assignable-roles</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>assignable-roles-int</artifactId>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>custom-command</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>custom-command</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>dynamic-activity</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>dynamic-activity</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>entertainment</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>entertainment</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -1,12 +0,0 @@
package dev.sheldan.abstracto.entertainment.model.exception;
import lombok.Builder;
import lombok.Getter;
import java.time.Duration;
@Builder
@Getter
public class PayDayCooldownExceptionModel {
private Duration tryAgainDuration;
}

View File

@@ -1,12 +0,0 @@
package dev.sheldan.abstracto.entertainment.model.exception;
import lombok.Builder;
import lombok.Getter;
import java.time.Duration;
@Builder
@Getter
public class SlotsCooldownExceptionModel {
private Duration tryAgainDuration;
}

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>experience-tracking</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>experience-tracking</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>giveaway</artifactId>
<version>1.5.13</version>
</parent>
<artifactId>giveaway-impl</artifactId>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>src/main/assembly/liquibase.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>giveaway-int</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.sheldan.abstracto.core</groupId>
<artifactId>metrics-int</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,18 @@
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
<id>liquibase</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<outputDirectory>.</outputDirectory>
<directory>${project.basedir}/src/main/resources/migrations</directory>
<includes>
<include>**/*</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View File

@@ -0,0 +1,103 @@
package dev.sheldan.abstracto.giveaway.command;
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
import dev.sheldan.abstracto.giveaway.config.GiveawayFeatureDefinition;
import dev.sheldan.abstracto.giveaway.config.GiveawaySlashCommandNames;
import dev.sheldan.abstracto.giveaway.service.GiveawayService;
import jakarta.transaction.Transactional;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
public class CancelGiveaway extends AbstractConditionableCommand {
private static final String COMMAND_NAME = "cancelGiveaway";
private static final String ID_PARAMETER = "id";
private static final String CANCEL_GIVEAWAY_RESPONSE_TEMPLATE_KEY = "cancelGiveaway_response";
@Autowired
private InteractionService interactionService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private GiveawayService giveawayService;
@Autowired
private CancelGiveaway self;
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
return event.deferReply().submit().thenAccept(interactionHook -> {
self.cancelGiveaway(event);
}).thenCompose(unused -> {
List<CompletableFuture<Message>> futures = interactionService.sendMessageToInteraction(CANCEL_GIVEAWAY_RESPONSE_TEMPLATE_KEY, new Object(), event.getHook());
return new CompletableFutureList<>(futures).getMainFuture();
})
.thenApply(unused -> CommandResult.fromSuccess());
}
@Transactional
public void cancelGiveaway(SlashCommandInteractionEvent event) {
Long giveawayId = slashCommandParameterService.getCommandOption(ID_PARAMETER, event, Integer.class).longValue();
giveawayService.cancelGiveaway(giveawayId, event.getGuild().getIdLong());
}
@Override
public CommandConfiguration getConfiguration() {
Parameter giveawayIdParameter = Parameter
.builder()
.templated(true)
.name(ID_PARAMETER)
.type(Integer.class)
.build();
List<Parameter> parameters = Arrays.asList(giveawayIdParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(GiveawaySlashCommandNames.GIVEAWAY)
.commandName("cancel")
.build();
return CommandConfiguration.builder()
.name(COMMAND_NAME)
.module(UtilityModuleDefinition.UTILITY)
.templated(true)
.slashCommandConfig(slashCommandConfig)
.async(true)
.supportsEmbedException(true)
.causesReaction(false)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureDefinition getFeature() {
return GiveawayFeatureDefinition.GIVEAWAY;
}
}

View File

@@ -0,0 +1,182 @@
package dev.sheldan.abstracto.giveaway.command;
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.utils.ParseUtils;
import dev.sheldan.abstracto.giveaway.config.GiveawayFeatureDefinition;
import dev.sheldan.abstracto.giveaway.config.GiveawaySlashCommandNames;
import dev.sheldan.abstracto.giveaway.model.GiveawayCreationRequest;
import dev.sheldan.abstracto.giveaway.service.GiveawayService;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
public class GreateGiveaway extends AbstractConditionableCommand {
private static final String COMMAND_NAME = "createGiveaway";
private static final String TITLE_PARAMETER = "title";
private static final String DESCRIPTION_PARAMETER = "description";
private static final String BENEFACTOR_PARAMETER = "benefactor";
private static final String CHANNEL_PARAMETER = "channel";
private static final String DURATION_PARAMETER = "duration";
private static final String WINNERS_PARAMETER = "winners";
private static final String CREATE_GIVEAWAY_RESPONSE_TEMPLATE_KEY = "createGiveaway_response";
@Autowired
private InteractionService interactionService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private GiveawayService giveawayService;
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
return event.deferReply()
.submit()
.thenCompose(interactionHook -> {
String title = slashCommandParameterService.getCommandOption(TITLE_PARAMETER, event, String.class);
String description;
if(slashCommandParameterService.hasCommandOption(DESCRIPTION_PARAMETER, event)) {
description = slashCommandParameterService.getCommandOption(DESCRIPTION_PARAMETER, event, String.class);
} else {
description = null;
}
String durationString = slashCommandParameterService.getCommandOption(DURATION_PARAMETER, event, Duration.class, String.class);
Duration duration = ParseUtils.parseDuration(durationString);
GuildMessageChannel target = null;
if(slashCommandParameterService.hasCommandOption(CHANNEL_PARAMETER, event)) {
target = slashCommandParameterService.getCommandOption(CHANNEL_PARAMETER, event, GuildMessageChannel.class);
}
Integer winners = 1;
if(slashCommandParameterService.hasCommandOption(WINNERS_PARAMETER, event)) {
winners = slashCommandParameterService.getCommandOption(WINNERS_PARAMETER, event, Integer.class);
}
Member benefactor;
if(slashCommandParameterService.hasCommandOption(BENEFACTOR_PARAMETER, event)) {
benefactor = slashCommandParameterService.getCommandOption(BENEFACTOR_PARAMETER, event, Member.class);
} else {
benefactor = null;
}
Member creator = event.getMember();
GiveawayCreationRequest request = GiveawayCreationRequest
.builder()
.benefactor(benefactor)
.creator(creator)
.description(description)
.duration(duration)
.targetChannel(target)
.winnerCount(winners)
.title(title)
.build();
return giveawayService.createGiveaway(request)
.thenAccept(unused -> interactionService.sendEmbed(CREATE_GIVEAWAY_RESPONSE_TEMPLATE_KEY, interactionHook));
}).thenApply(unused -> CommandResult.fromSuccess());
}
@Override
public CommandConfiguration getConfiguration() {
Parameter titleParameter = Parameter
.builder()
.templated(true)
.name(TITLE_PARAMETER)
.type(String.class)
.build();
Parameter descriptionParameter = Parameter
.builder()
.templated(true)
.name(DESCRIPTION_PARAMETER)
.type(String.class)
.optional(true)
.build();
Parameter channelParameter = Parameter
.builder()
.name(CHANNEL_PARAMETER)
.type(GuildMessageChannel.class)
.optional(true)
.templated(true)
.build();
Parameter durationParameter = Parameter
.builder()
.name(DURATION_PARAMETER)
.type(Duration.class)
.templated(true)
.build();
Parameter winnersParameter = Parameter
.builder()
.name(WINNERS_PARAMETER)
.type(Integer.class)
.optional(true)
.templated(true)
.build();
Parameter benefactorParameter = Parameter
.builder()
.templated(true)
.name(BENEFACTOR_PARAMETER)
.type(Member.class)
.optional(true)
.build();
List<Parameter> parameters = Arrays.asList(titleParameter, durationParameter, benefactorParameter, descriptionParameter,
channelParameter, winnersParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(GiveawaySlashCommandNames.GIVEAWAY)
.commandName("create")
.build();
return CommandConfiguration.builder()
.name(COMMAND_NAME)
.module(UtilityModuleDefinition.UTILITY)
.templated(true)
.slashCommandConfig(slashCommandConfig)
.async(true)
.supportsEmbedException(true)
.causesReaction(false)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureDefinition getFeature() {
return GiveawayFeatureDefinition.GIVEAWAY;
}
}

View File

@@ -0,0 +1,103 @@
package dev.sheldan.abstracto.giveaway.command;
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
import dev.sheldan.abstracto.giveaway.config.GiveawayFeatureDefinition;
import dev.sheldan.abstracto.giveaway.config.GiveawaySlashCommandNames;
import dev.sheldan.abstracto.giveaway.service.GiveawayService;
import jakarta.transaction.Transactional;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
public class ReRollGiveaway extends AbstractConditionableCommand {
private static final String COMMAND_NAME = "reRollGiveaway";
private static final String ID_PARAMETER = "id";
private static final String RE_ROLL_GIVEAWAY_RESPONSE_TEMPLATE_KEY = "reRollGiveaway_response";
@Autowired
private InteractionService interactionService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private GiveawayService giveawayService;
@Autowired
private ReRollGiveaway self;
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
return event.deferReply().submit().thenAccept(interactionHook -> {
self.reRollGiveaway(event);
}).thenCompose(unused -> {
List<CompletableFuture<Message>> futures = interactionService.sendMessageToInteraction(RE_ROLL_GIVEAWAY_RESPONSE_TEMPLATE_KEY, new Object(), event.getHook());
return new CompletableFutureList<>(futures).getMainFuture();
})
.thenApply(unused -> CommandResult.fromSuccess());
}
@Transactional
public void reRollGiveaway(SlashCommandInteractionEvent event) {
Long giveawayId = slashCommandParameterService.getCommandOption(ID_PARAMETER, event, Integer.class).longValue();
giveawayService.evaluateGiveaway(giveawayId, event.getGuild().getIdLong());
}
@Override
public CommandConfiguration getConfiguration() {
Parameter giveawayIdParameter = Parameter
.builder()
.templated(true)
.name(ID_PARAMETER)
.type(Integer.class)
.build();
List<Parameter> parameters = Arrays.asList(giveawayIdParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(GiveawaySlashCommandNames.GIVEAWAY)
.commandName("reroll")
.build();
return CommandConfiguration.builder()
.name(COMMAND_NAME)
.module(UtilityModuleDefinition.UTILITY)
.templated(true)
.slashCommandConfig(slashCommandConfig)
.async(true)
.supportsEmbedException(true)
.causesReaction(false)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureDefinition getFeature() {
return GiveawayFeatureDefinition.GIVEAWAY;
}
}

View File

@@ -0,0 +1,10 @@
package dev.sheldan.abstracto.giveaway.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource("classpath:giveaway-config.properties")
public class GiveawayConfig {
}

View File

@@ -0,0 +1,41 @@
package dev.sheldan.abstracto.giveaway.job;
import dev.sheldan.abstracto.giveaway.service.GiveawayService;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.PersistJobDataAfterExecution;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;
@Slf4j
@DisallowConcurrentExecution
@Component
@PersistJobDataAfterExecution
public class GiveawayEvaluationJob extends QuartzJobBean {
@Getter
@Setter
private Long giveawayId;
@Getter
@Setter
private Long serverId;
@Autowired
private GiveawayService giveawayService;
@Override
protected void executeInternal(JobExecutionContext context) {
try {
log.info("Executing giveaway evaluation job for giveaway {} in server {}", giveawayId, serverId);
giveawayService.evaluateGiveaway(giveawayId, serverId);
} catch (Exception exception) {
log.error("Giveaway evaluation job failed.", exception);
}
}
}

View File

@@ -0,0 +1,94 @@
package dev.sheldan.abstracto.giveaway.listener;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.button.listener.ButtonClickedListener;
import dev.sheldan.abstracto.core.interaction.button.listener.ButtonClickedListenerModel;
import dev.sheldan.abstracto.core.interaction.button.listener.ButtonClickedListenerResult;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.giveaway.config.GiveawayFeatureDefinition;
import dev.sheldan.abstracto.giveaway.exception.GiveawayNotFoundException;
import dev.sheldan.abstracto.giveaway.model.JoinGiveawayPayload;
import dev.sheldan.abstracto.giveaway.model.database.Giveaway;
import dev.sheldan.abstracto.giveaway.service.GiveawayService;
import dev.sheldan.abstracto.giveaway.service.GiveawayServiceBean;
import dev.sheldan.abstracto.giveaway.service.management.GiveawayManagementService;
import dev.sheldan.abstracto.giveaway.service.management.GiveawayParticipantManagementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
@Component
@Slf4j
public class GiveawayJoinListener implements ButtonClickedListener {
private static final String GIVEAWAY_JOIN_RESPONSE_TEMPLATE_KEY = "giveaway_join_response";
private static final String GIVEAWAY_ALREADY_JOINED_RESPONSE_TEMPLATE_KEY = "giveaway_already_joined_response";
@Autowired
private GiveawayManagementService giveawayManagementService;
@Autowired
private GiveawayService giveawayService;
@Autowired
private InteractionService interactionService;
@Autowired
private GiveawayParticipantManagementService giveawayParticipantManagementService;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Override
public ButtonClickedListenerResult execute(ButtonClickedListenerModel model) {
JoinGiveawayPayload payload = (JoinGiveawayPayload) model.getDeserializedPayload();
Optional<Giveaway> optionalGiveaway = giveawayManagementService.loadGiveawayById(payload.getGiveawayId(), payload.getServerId());
if(optionalGiveaway.isPresent()) {
Giveaway giveaway = optionalGiveaway.get();
AUserInAServer user = userInServerManagementService.loadOrCreateUser(model.getEvent().getMember());
Long joiningUserId = model.getEvent().getMember().getIdLong();
if(!giveawayParticipantManagementService.userIsAlreadyParticipating(giveaway, user)) {
log.info("Adding user {} to giveaway {}.", joiningUserId, payload.getGiveawayId());
giveawayService.addGiveawayParticipant(giveaway, model.getEvent().getMember(), model.getEvent().getMessageChannel())
.thenAccept(unused -> {
log.info("Notified user {} in giveaway {} join event.", joiningUserId, payload.getGiveawayId());
interactionService.replyEmbed(GIVEAWAY_JOIN_RESPONSE_TEMPLATE_KEY, model.getEvent());
}).exceptionally(throwable -> {
log.error("Failed to add {} to giveaway {}.", joiningUserId, payload.getGiveawayId(), throwable);
return null;
});
} else {
log.info("User {} was already part of giveaway {}.", joiningUserId, payload.getGiveawayId());
interactionService.replyEmbed(GIVEAWAY_ALREADY_JOINED_RESPONSE_TEMPLATE_KEY, model.getEvent());
}
return ButtonClickedListenerResult.ACKNOWLEDGED;
} else {
throw new GiveawayNotFoundException();
}
}
@Override
public Boolean handlesEvent(ButtonClickedListenerModel model) {
return GiveawayServiceBean.GIVEAWAY_JOIN_ORIGIN.equals(model.getOrigin());
}
@Override
public FeatureDefinition getFeature() {
return GiveawayFeatureDefinition.GIVEAWAY;
}
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
@Override
public Boolean autoAcknowledgeEvent() {
return false;
}
}

View File

@@ -0,0 +1,10 @@
package dev.sheldan.abstracto.giveaway.repository;
import dev.sheldan.abstracto.giveaway.model.database.GiveawayParticipant;
import dev.sheldan.abstracto.giveaway.model.database.embed.GiveawayParticipationId;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface GiveawayParticipantRepository extends JpaRepository<GiveawayParticipant, GiveawayParticipationId> {
}

View File

@@ -0,0 +1,10 @@
package dev.sheldan.abstracto.giveaway.repository;
import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.giveaway.model.database.Giveaway;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface GiveawayRepository extends JpaRepository<Giveaway, ServerSpecificId> {
}

View File

@@ -0,0 +1,275 @@
package dev.sheldan.abstracto.giveaway.service;
import dev.sheldan.abstracto.core.interaction.ComponentPayloadService;
import dev.sheldan.abstracto.core.interaction.ComponentService;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.CounterService;
import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
import dev.sheldan.abstracto.giveaway.config.GiveawayPostTarget;
import dev.sheldan.abstracto.giveaway.exception.GiveawayNotFoundException;
import dev.sheldan.abstracto.giveaway.model.GiveawayCreationRequest;
import dev.sheldan.abstracto.giveaway.model.JoinGiveawayPayload;
import dev.sheldan.abstracto.giveaway.model.database.Giveaway;
import dev.sheldan.abstracto.giveaway.model.database.GiveawayParticipant;
import dev.sheldan.abstracto.giveaway.model.template.GiveawayMessageModel;
import dev.sheldan.abstracto.giveaway.model.template.GiveawayResultMessageModel;
import dev.sheldan.abstracto.giveaway.service.management.GiveawayManagementService;
import dev.sheldan.abstracto.giveaway.service.management.GiveawayParticipantManagementService;
import dev.sheldan.abstracto.scheduling.model.JobParameters;
import dev.sheldan.abstracto.scheduling.service.SchedulerService;
import jakarta.transaction.Transactional;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.security.SecureRandom;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class GiveawayServiceBean implements GiveawayService {
private static final String GIVEAWAY_MESSAGE_TEMPLATE_KEY = "giveaway_post";
private static final String GIVEAWAY_RESULT_MESSAGE_TEMPLATE_KEY = "giveaway_result";
public static final String GIVEAWAY_JOIN_ORIGIN = "JOIN_GIVEAWAY";
public static final String GIVEAWAY_COUNTER = "giveaways";
@Autowired
private ChannelManagementService channelManagementService;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private GiveawayManagementService giveawayManagementService;
@Autowired
private ComponentService componentService;
@Autowired
private PostTargetService postTargetService;
@Autowired
private ChannelService channelService;
@Autowired
private TemplateService templateService;
@Autowired
private ComponentPayloadService componentPayloadService;
@Autowired
private GiveawayParticipantManagementService giveawayParticipantManagementService;
@Autowired
private SchedulerService schedulerService;
@Autowired
private SecureRandom secureRandom;
@Autowired
private CounterService counterService;
@Autowired
private GiveawayServiceBean self;
@Override
public CompletableFuture<Void> createGiveaway(GiveawayCreationRequest giveawayCreationRequest) {
String componentId = componentService.generateComponentId();
Instant targetDate = Instant.now().plus(giveawayCreationRequest.getDuration());
Long serverId = giveawayCreationRequest.getCreator().getGuild().getIdLong();
Long giveawayId = counterService.getNextCounterValue(serverId, GIVEAWAY_COUNTER);
GiveawayMessageModel model = GiveawayMessageModel
.builder()
.title(giveawayCreationRequest.getTitle())
.description(giveawayCreationRequest.getDescription())
.giveawayId(giveawayId)
.benefactor(giveawayCreationRequest.getBenefactor() != null ? MemberDisplay.fromMember(giveawayCreationRequest.getBenefactor()) : null)
.creator(MemberDisplay.fromMember(giveawayCreationRequest.getCreator()))
.winnerCount(giveawayCreationRequest.getWinnerCount())
.targetDate(targetDate)
.joinComponentId(componentId)
.build();
List<CompletableFuture<Message>> messageFutures;
log.info("Rendering giveaway message in server {} by user {}", serverId, giveawayCreationRequest.getCreator().getIdLong());
MessageToSend messageToSend = templateService.renderEmbedTemplate(GIVEAWAY_MESSAGE_TEMPLATE_KEY, model, serverId);
if(giveawayCreationRequest.getTargetChannel() == null) {
log.info("Sending giveaway to post target in server {}", serverId);
postTargetService.validatePostTarget(GiveawayPostTarget.GIVEAWAYS, giveawayCreationRequest.getCreator().getGuild().getIdLong());
messageFutures = postTargetService.sendEmbedInPostTarget(messageToSend, GiveawayPostTarget.GIVEAWAYS, serverId);
} else {
log.info("Sending giveaway to channel {} in server {}.", giveawayCreationRequest.getTargetChannel().getId(), serverId);
messageFutures = channelService.sendMessageToSendToChannel(messageToSend, giveawayCreationRequest.getTargetChannel());
}
CompletableFutureList<Message> messageFutureList = new CompletableFutureList<>(messageFutures);
return messageFutureList.getMainFuture().thenAccept(o -> {
Message createdMessage = messageFutureList.getFutures().get(0).join();
giveawayCreationRequest.setTargetChannel(createdMessage.getGuildChannel());
self.persistGiveaway(giveawayCreationRequest, giveawayId, createdMessage.getIdLong(), componentId);
});
}
@Override
public CompletableFuture<Void> addGiveawayParticipant(Giveaway giveaway, Member member, MessageChannel messageChannel) {
GiveawayMessageModel giveawayMessageModel = GiveawayMessageModel.fromGiveaway(giveaway);
giveawayMessageModel.setJoinedUserCount(giveaway.getParticipants().size() + 1L);
Long giveawayId = giveaway.getGiveawayId().getId();
log.info("Adding giveaway participating of user {} to giveaway {} in server {}.", member.getIdLong(), giveawayId, member.getGuild().getIdLong());
MessageToSend messageToSend = templateService.renderEmbedTemplate(GIVEAWAY_MESSAGE_TEMPLATE_KEY, giveawayMessageModel);
return channelService.editEmbedMessageInAChannel(messageToSend.getEmbeds().get(0), messageChannel, giveaway.getMessageId())
.thenAccept(message -> {
self.persistAddedParticipant(member, giveawayId);
});
}
@Override
@Transactional
public CompletableFuture<Void> evaluateGiveaway(Long giveawayId, Long serverId) {
Optional<Giveaway> giveAwayOptional = giveawayManagementService.loadGiveawayById(giveawayId, serverId);
if(giveAwayOptional.isEmpty()) {
throw new GiveawayNotFoundException();
}
log.info("Evaluating giveaway {} in server {}.", giveawayId, serverId);
Giveaway giveaway = giveAwayOptional.get();
Set<Long> winners = new HashSet<>();
Integer winnerCount = giveaway.getWinnerCount();
List<Long> potentialWinners = new ArrayList<>(giveaway
.getParticipants()
.stream()
.map(giveawayParticipant -> giveawayParticipant.getParticipant().getUserInServerId())
.toList());
if(potentialWinners.size() <= winnerCount) {
winners.addAll(potentialWinners);
log.debug("Less participants than total winners - selecting all for giveaway {} in server {}.", giveawayId, serverId);
} else {
for (int i = 0; i < winnerCount; i++) {
int winnerIndex = secureRandom.nextInt(potentialWinners.size());
Long winner = potentialWinners.get(winnerIndex);
potentialWinners.remove(winnerIndex);
winners.add(winner);
}
}
List<GiveawayParticipant> winningParticipants = giveaway
.getParticipants()
.stream()
.filter(giveawayParticipant -> winners.contains(giveawayParticipant.getParticipant().getUserInServerId()))
.toList();
List<MemberDisplay> winnerDisplays = winningParticipants
.stream()
.map(giveawayParticipant -> MemberDisplay.fromAUserInAServer(giveawayParticipant.getParticipant()))
.toList();
GiveawayResultMessageModel resultModel = GiveawayResultMessageModel
.builder()
.messageId(giveaway.getMessageId())
.title(giveaway.getTitle())
.winners(winnerDisplays)
.build();
log.info("Sending result message for giveaway {} in server {}.", giveawayId, serverId);
MessageToSend messageToSend = templateService.renderEmbedTemplate(GIVEAWAY_RESULT_MESSAGE_TEMPLATE_KEY, resultModel);
List<CompletableFuture<Message>> resultFutures = channelService.sendMessageEmbedToSendToAChannel(messageToSend, giveaway.getGiveawayChannel());
GiveawayMessageModel giveawayMessageModel = GiveawayMessageModel.fromGiveaway(giveaway);
giveawayMessageModel.setWinners(winnerDisplays);
giveawayMessageModel.setEnded(true);
MessageToSend giveawayMessageToSend = templateService.renderEmbedTemplate(GIVEAWAY_MESSAGE_TEMPLATE_KEY, giveawayMessageModel);
log.info("Updating original giveaway message for giveaway {} in server {}.", giveawayId, serverId);
GuildMessageChannel messageChannel = channelService.getMessageChannelFromServer(giveaway.getServer().getId(), giveaway.getGiveawayChannel().getId());
CompletableFuture<Message> giveawayUpdateFuture = channelService.editMessageInAChannelFuture(giveawayMessageToSend, messageChannel, giveaway.getMessageId());
resultFutures.add(giveawayUpdateFuture);
return new CompletableFutureList<>(resultFutures).getMainFuture();
}
@Override
public CompletableFuture<Void> cancelGiveaway(Long giveawayId, Long serverId) {
Optional<Giveaway> giveAwayOptional = giveawayManagementService.loadGiveawayById(giveawayId, serverId);
if(giveAwayOptional.isEmpty()) {
throw new GiveawayNotFoundException();
}
Giveaway giveaway = giveAwayOptional.get();
log.info("Cancelling giveaway with id {} in server {}.", giveawayId, serverId);
GiveawayMessageModel giveawayMessageModel = GiveawayMessageModel.fromGiveaway(giveaway);
giveawayMessageModel.setCancelled(true);
schedulerService.stopTrigger(giveaway.getReminderTriggerKey());
MessageToSend giveawayMessageToSend = templateService.renderEmbedTemplate(GIVEAWAY_MESSAGE_TEMPLATE_KEY, giveawayMessageModel);
GuildMessageChannel messageChannel = channelService.getMessageChannelFromServer(giveaway.getServer().getId(), giveaway.getGiveawayChannel().getId());
log.debug("Updating original giveaway message to consider cancellation for giveaway {} in server {}.", giveawayId, serverId);
return channelService.editMessageInAChannelFuture(giveawayMessageToSend, messageChannel, giveaway.getMessageId())
.thenAccept(message -> {
self.persistGiveawayCancellation(giveawayId, serverId);
});
}
@Transactional
public void persistGiveawayCancellation(Long giveawayId, Long serverId) {
Optional<Giveaway> giveAwayOptional = giveawayManagementService.loadGiveawayById(giveawayId, serverId);
if(giveAwayOptional.isEmpty()) {
throw new GiveawayNotFoundException();
}
log.info("Persisting cancellation of giveaway {} in server {}.", giveawayId, serverId);
Giveaway giveaway = giveAwayOptional.get();
giveaway.setCancelled(true);
}
@Transactional
public void persistAddedParticipant(Member member, Long giveawayId) {
log.info("Storing user {} as participant to giveaway {} in server {}.", member.getIdLong(), giveawayId, member.getGuild().getIdLong());
Optional<Giveaway> giveAwayOptional = giveawayManagementService.loadGiveawayById(giveawayId, member.getGuild().getIdLong());
giveAwayOptional.ifPresent(giveaway -> {
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
giveawayParticipantManagementService.addParticipant(giveaway, aUserInAServer);
});
}
@Transactional
public void persistGiveaway(GiveawayCreationRequest giveawayCreationRequest, Long giveawayId, Long messageId, String componentId) {
Member creatorMember = giveawayCreationRequest.getCreator();
log.info("Persisting giveaway in server {} with message id {}.", creatorMember.getGuild().getIdLong(), messageId);
Instant targetDate = Instant.now().plus(giveawayCreationRequest.getDuration());
AChannel targetChannel = channelManagementService.loadChannel(giveawayCreationRequest.getTargetChannel().getIdLong());
AUserInAServer creator = userInServerManagementService.loadOrCreateUser(creatorMember);
AUserInAServer benefactor;
if(giveawayCreationRequest.getBenefactor() != null) {
benefactor = userInServerManagementService.loadOrCreateUser(giveawayCreationRequest.getBenefactor());
} else {
benefactor = null;
}
Giveaway giveaway = giveawayManagementService.createGiveaway(creator, benefactor, targetChannel, targetDate,
giveawayCreationRequest.getTitle(), giveawayCreationRequest.getDescription(), giveawayCreationRequest.getWinnerCount(),
messageId, componentId, giveawayId);
HashMap<Object, Object> parameters = new HashMap<>();
parameters.put("giveawayId", giveaway.getGiveawayId().getId().toString());
parameters.put("serverId", giveaway.getGiveawayId().getServerId().toString());
JobParameters jobParameters = JobParameters
.builder()
.parameters(parameters)
.build();
log.info("Scheduling giveaway reminder for giveaway {} originating from message {} in server {}.", giveaway.getGiveawayId().getId(), messageId, creatorMember.getGuild().getIdLong());
String triggerKey = schedulerService.executeJobWithParametersOnce("giveawayEvaluationJob", "giveaway", jobParameters, Date.from(giveaway.getTargetDate()));
giveaway.setReminderTriggerKey(triggerKey);
JoinGiveawayPayload joinPayload = JoinGiveawayPayload
.builder()
.giveawayId(giveaway.getGiveawayId().getId())
.serverId(giveaway.getGiveawayId().getServerId())
.build();
componentPayloadService.createButtonPayload(componentId, joinPayload, GIVEAWAY_JOIN_ORIGIN, creator.getServerReference());
}
}

View File

@@ -0,0 +1,46 @@
package dev.sheldan.abstracto.giveaway.service.management;
import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.giveaway.model.database.Giveaway;
import dev.sheldan.abstracto.giveaway.repository.GiveawayRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.util.Optional;
@Component
public class GiveawayManagementServiceBean implements GiveawayManagementService {
@Autowired
private GiveawayRepository giveawayRepository;
@Override
public Giveaway createGiveaway(AUserInAServer creator, AUserInAServer benefactor, AChannel target,
Instant targetDate, String title, String description, Integer winnerCount,
Long messageId, String componentId, Long giveawayId) {
Giveaway giveaway = Giveaway
.builder()
.giveawayId(new ServerSpecificId(creator.getServerReference().getId(), giveawayId))
.creator(creator)
.benefactor(benefactor)
.messageId(messageId)
.componentId(componentId)
.server(creator.getServerReference())
.winnerCount(winnerCount)
.cancelled(false)
.title(title)
.giveawayChannel(target)
.description(description)
.targetDate(targetDate)
.build();
return giveawayRepository.save(giveaway);
}
@Override
public Optional<Giveaway> loadGiveawayById(Long giveawayId, Long serverId) {
return giveawayRepository.findById(new ServerSpecificId(serverId, giveawayId));
}
}

View File

@@ -0,0 +1,34 @@
package dev.sheldan.abstracto.giveaway.service.management;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.giveaway.model.database.Giveaway;
import dev.sheldan.abstracto.giveaway.model.database.GiveawayParticipant;
import dev.sheldan.abstracto.giveaway.model.database.embed.GiveawayParticipationId;
import dev.sheldan.abstracto.giveaway.repository.GiveawayParticipantRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class GiveawayParticipantManagementServiceBean implements GiveawayParticipantManagementService {
@Autowired
private GiveawayParticipantRepository repository;
@Override
public void addParticipant(Giveaway giveaway, AUserInAServer aUserInAServer) {
GiveawayParticipationId id = new GiveawayParticipationId(aUserInAServer.getUserInServerId(), giveaway.getGiveawayId().getId(), giveaway.getServer().getId());
GiveawayParticipant participant = GiveawayParticipant
.builder()
.id(id)
.giveaway(giveaway)
.participant(aUserInAServer)
.won(false)
.build();
repository.save(participant);
}
@Override
public boolean userIsAlreadyParticipating(Giveaway giveaway, AUserInAServer aUserInAServer) {
return repository.existsById(new GiveawayParticipationId(aUserInAServer.getUserInServerId(), giveaway.getGiveawayId().getId(), giveaway.getServer().getId()));
}
}

View File

@@ -0,0 +1,4 @@
abstracto.featureFlags.giveaway.featureName=giveaway
abstracto.featureFlags.giveaway.enabled=false
abstracto.postTargets.giveaways.name=giveaways

View File

@@ -0,0 +1,11 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="tables/tables.xml" relativeToChangelogFile="true"/>
<include file="seedData/data.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,29 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<property name="utilityModule" value="(SELECT id FROM module WHERE name = 'utility')"/>
<property name="giveawayFeature" value="(SELECT id FROM feature WHERE key = 'giveaway')"/>
<changeSet author="Sheldan" id="giveaway-commands">
<insert tableName="command">
<column name="name" value="createGiveaway"/>
<column name="module_id" valueComputed="${utilityModule}"/>
<column name="feature_id" valueComputed="${giveawayFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="reRollGiveaway"/>
<column name="module_id" valueComputed="${utilityModule}"/>
<column name="feature_id" valueComputed="${giveawayFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="cancelGiveaway"/>
<column name="module_id" valueComputed="${utilityModule}"/>
<column name="feature_id" valueComputed="${giveawayFeature}"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,12 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="feature.xml" relativeToChangelogFile="true"/>
<include file="command.xml" relativeToChangelogFile="true"/>
<include file="giveaway_evaluation_job.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,14 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="giveaway_feature-insertion">
<insert tableName="feature">
<column name="key" value="giveaway"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,18 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="giveaway_evaluation_job-insert">
<insert tableName="scheduler_job">
<column name="name" value="giveawayEvaluationJob"/>
<column name="group_name" value="giveaway"/>
<column name="clazz" value="dev.sheldan.abstracto.giveaway.job.GiveawayEvaluationJob"/>
<column name="active" value="true"/>
<column name="recovery" value="false"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,75 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="giveaway-table">
<createTable tableName="giveaway">
<column name="id" type="BIGINT">
<constraints nullable="false" />
</column>
<column name="creator_user_id" type="INTEGER">
<constraints nullable="false"/>
</column>
<column name="benefactor_user_id" type="INTEGER">
<constraints nullable="true"/>
</column>
<column name="title" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="component_id" type="VARCHAR(100)">
<constraints nullable="false"/>
</column>
<column name="description" type="VARCHAR(255)">
<constraints nullable="true"/>
</column>
<column name="reminder_trigger_key" type="VARCHAR(255)">
<constraints nullable="true"/>
</column>
<column name="giveaway_channel_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="message_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="cancelled" type="BOOLEAN">
<constraints nullable="false"/>
</column>
<column name="target_date" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="false"/>
</column>
<column name="winner_count" type="INTEGER">
<constraints nullable="false"/>
</column>
<column name="server_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="false"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
</createTable>
<addPrimaryKey tableName="giveaway" columnNames="id, server_id"/>
<addForeignKeyConstraint baseColumnNames="creator_user_id" baseTableName="giveaway" constraintName="fk_giveaway_creator" deferrable="false"
initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="user_in_server_id"
referencedTableName="user_in_server" validate="true"/>
<addForeignKeyConstraint baseColumnNames="benefactor_user_id" baseTableName="giveaway" constraintName="fk_giveaway_benefactor" deferrable="false"
initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="user_in_server_id"
referencedTableName="user_in_server" validate="true"/>
<addForeignKeyConstraint baseColumnNames="giveaway_channel_id" baseTableName="giveaway" constraintName="fk_giveaway_channel" deferrable="false"
initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="channel" validate="true"/>
<addForeignKeyConstraint baseColumnNames="server_id" baseTableName="giveaway" constraintName="fk_giveaway_server" deferrable="false" initiallyDeferred="false"
onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="server" validate="true"/>
<sql>
DROP TRIGGER IF EXISTS giveaway_update_trigger ON giveaway;
CREATE TRIGGER giveaway_update_trigger BEFORE UPDATE ON giveaway FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();
</sql>
<sql>
DROP TRIGGER IF EXISTS giveaway_insert_trigger ON giveaway;
CREATE TRIGGER giveaway_insert_trigger BEFORE INSERT ON giveaway FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
</sql>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,45 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="giveaway_participant-table">
<createTable tableName="giveaway_participant">
<column name="participant_user_in_server_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="giveaway_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="server_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="won" type="BOOLEAN">
<constraints nullable="false"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="false"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
</createTable>
<addPrimaryKey columnNames="participant_user_in_server_id, giveaway_id, server_id" tableName="giveaway_participant" constraintName="pk_giveaway_participant" validate="true"/>
<addForeignKeyConstraint baseColumnNames="participant_user_in_server_id" baseTableName="giveaway_participant" constraintName="fk_giveaway_participant_participant"
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="user_in_server_id"
referencedTableName="user_in_server" validate="true"/>
<addForeignKeyConstraint baseColumnNames="giveaway_id, server_id" baseTableName="giveaway_participant" constraintName="fk_giveaway_participant_giveaway"
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id, server_id"
referencedTableName="giveaway" validate="true"/>
<sql>
DROP TRIGGER IF EXISTS giveaway_participant_update_trigger ON giveaway_participant;
CREATE TRIGGER giveaway_participant_update_trigger BEFORE UPDATE ON giveaway_participant FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();
</sql>
<sql>
DROP TRIGGER IF EXISTS giveaway_participant_insert_trigger ON giveaway_participant;
CREATE TRIGGER giveaway_participant_insert_trigger BEFORE INSERT ON giveaway_participant FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
</sql>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,11 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="giveaway.xml" relativeToChangelogFile="true"/>
<include file="giveaway_participant.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,10 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="1.5.13/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>giveaway</artifactId>
<version>1.5.13</version>
</parent>
<artifactId>giveaway-int</artifactId>
<dependencies>
<dependency>
<groupId>dev.sheldan.abstracto.scheduling</groupId>
<artifactId>scheduling-int</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,23 @@
package dev.sheldan.abstracto.giveaway.config;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.config.PostTargetEnum;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class GiveawayFeatureConfig implements FeatureConfig {
@Override
public FeatureDefinition getFeature() {
return GiveawayFeatureDefinition.GIVEAWAY;
}
@Override
public List<PostTargetEnum> getRequiredPostTargets() {
return Arrays.asList(GiveawayPostTarget.GIVEAWAYS);
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.giveaway.config;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import lombok.Getter;
@Getter
public enum GiveawayFeatureDefinition implements FeatureDefinition {
GIVEAWAY("giveaway");
private String key;
GiveawayFeatureDefinition(String key) {
this.key = key;
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.giveaway.config;
import dev.sheldan.abstracto.core.config.PostTargetEnum;
import lombok.Getter;
@Getter
public enum GiveawayPostTarget implements PostTargetEnum {
GIVEAWAYS("giveaways");
private String key;
GiveawayPostTarget(String key) {
this.key = key;
}
}

View File

@@ -0,0 +1,5 @@
package dev.sheldan.abstracto.giveaway.config;
public class GiveawaySlashCommandNames {
public static final String GIVEAWAY = "giveaway";
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.giveaway.exception;
import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException;
public class GiveawayNotFoundException extends AbstractoTemplatableException {
@Override
public String getTemplateName() {
return "giveaway_not_found_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,23 @@
package dev.sheldan.abstracto.giveaway.model;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
import java.time.Duration;
@Builder
@Getter
public class GiveawayCreationRequest {
private Member creator;
private Member benefactor;
private String title;
private String description;
private Duration duration;
@Setter
private GuildMessageChannel targetChannel;
private Integer winnerCount;
}

View File

@@ -0,0 +1,12 @@
package dev.sheldan.abstracto.giveaway.model;
import dev.sheldan.abstracto.core.interaction.button.ButtonPayload;
import lombok.Builder;
import lombok.Getter;
@Getter
@Builder
public class JoinGiveawayPayload implements ButtonPayload {
private Long giveawayId;
private Long serverId;
}

View File

@@ -0,0 +1,82 @@
package dev.sheldan.abstracto.giveaway.model.database;
import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import jakarta.persistence.*;
import lombok.*;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
@Builder
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "giveaway")
@Getter
@Setter
@EqualsAndHashCode
public class Giveaway {
@Id
@EmbeddedId
private ServerSpecificId giveawayId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "creator_user_id", nullable = false)
private AUserInAServer creator;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "benefactor_user_id")
private AUserInAServer benefactor;
@Column(name = "title", nullable = false)
private String title;
@Column(name = "description")
private String description;
@Column(name = "component_id")
private String componentId;
@Column(name = "winner_count", nullable = false)
private Integer winnerCount;
@Column(name = "target_date", nullable = false)
private Instant targetDate;
@Column(name = "cancelled", nullable = false)
private Boolean cancelled;
@Column(name = "reminder_trigger_key")
private String reminderTriggerKey;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "giveaway_channel_id", nullable = false)
private AChannel giveawayChannel;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@MapsId("serverId")
@JoinColumn(name = "server_id", referencedColumnName = "id", nullable = false)
private AServer server;
@Column(name = "message_id", nullable = false)
private Long messageId;
@Column(name = "created", nullable = false, insertable = false, updatable = false)
private Instant created;
@Column(name = "updated", insertable = false, updatable = false)
private Instant updated;
@OneToMany(
fetch = FetchType.LAZY,
orphanRemoval = true,
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
mappedBy = "giveaway")
@Builder.Default
private List<GiveawayParticipant> participants = new ArrayList<>();
}

View File

@@ -0,0 +1,45 @@
package dev.sheldan.abstracto.giveaway.model.database;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.giveaway.model.database.embed.GiveawayParticipationId;
import jakarta.persistence.*;
import lombok.*;
import java.time.Instant;
@Builder
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "giveaway_participant")
@Getter
@Setter
@EqualsAndHashCode
public class GiveawayParticipant {
@EmbeddedId
@Getter
private GiveawayParticipationId id;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
@MapsId("participantId")
@JoinColumn(name = "participant_user_in_server_id", nullable = false)
private AUserInAServer participant;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns(
{
@JoinColumn(updatable = false, insertable = false, name = "giveaway_id", referencedColumnName = "id"),
@JoinColumn(updatable = false, insertable = false, name = "server_id", referencedColumnName = "server_id")
})
private Giveaway giveaway;
@Column(name = "won", nullable = false)
private Boolean won;
@Column(name = "created", nullable = false, insertable = false, updatable = false)
private Instant created;
@Column(name = "updated", insertable = false, updatable = false)
private Instant updated;
}

View File

@@ -0,0 +1,26 @@
package dev.sheldan.abstracto.giveaway.model.database.embed;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.*;
import java.io.Serializable;
@Embeddable
@Getter
@Setter
@Builder
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
public class GiveawayParticipationId implements Serializable {
@Column(name = "participant_user_in_server_id")
private Long participantId;
@Column(name = "giveaway_id")
private Long giveawayId;
@Column(name = "server_id")
private Long serverId;
}

View File

@@ -0,0 +1,48 @@
package dev.sheldan.abstracto.giveaway.model.template;
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
import dev.sheldan.abstracto.giveaway.model.database.Giveaway;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
@Builder
@Getter
@Setter
public class GiveawayMessageModel {
private String title;
private String description;
private Integer winnerCount;
private Long giveawayId;
@Builder.Default
private Boolean ended = false;
@Builder.Default
private Boolean cancelled = false;
@Builder.Default
private Long joinedUserCount = 0L;
private MemberDisplay creator;
private MemberDisplay benefactor;
private Instant targetDate;
private String joinComponentId;
@Builder.Default
private List<MemberDisplay> winners = new ArrayList<>();
public static GiveawayMessageModel fromGiveaway(Giveaway giveaway) {
return GiveawayMessageModel
.builder()
.title(giveaway.getTitle())
.description(giveaway.getDescription())
.benefactor(giveaway.getBenefactor() != null ? MemberDisplay.fromAUserInAServer(giveaway.getBenefactor()) : null)
.creator(MemberDisplay.fromAUserInAServer(giveaway.getCreator()))
.winnerCount(giveaway.getWinnerCount())
.joinedUserCount((long) giveaway.getParticipants().size())
.joinComponentId(giveaway.getComponentId())
.giveawayId(giveaway.getGiveawayId().getId())
.targetDate(giveaway.getTargetDate())
.build();
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.giveaway.model.template;
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
import lombok.Builder;
import lombok.Getter;
import java.util.List;
@Getter
@Builder
public class GiveawayResultMessageModel {
private String title;
private Long messageId;
private List<MemberDisplay> winners;
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.giveaway.service;
import dev.sheldan.abstracto.giveaway.model.GiveawayCreationRequest;
import dev.sheldan.abstracto.giveaway.model.database.Giveaway;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import java.util.concurrent.CompletableFuture;
public interface GiveawayService {
CompletableFuture<Void> createGiveaway(GiveawayCreationRequest giveawayCreationRequest);
CompletableFuture<Void> addGiveawayParticipant(Giveaway giveaway, Member member, MessageChannel messageChannel);
CompletableFuture<Void> evaluateGiveaway(Long giveawayId, Long serverId);
CompletableFuture<Void> cancelGiveaway(Long giveawayId, Long serverId);
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.giveaway.service.management;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.giveaway.model.database.Giveaway;
import java.time.Instant;
import java.util.Optional;
public interface GiveawayManagementService {
Giveaway createGiveaway(AUserInAServer creator, AUserInAServer benefactor, AChannel target,
Instant targetDate, String title, String description, Integer winnerCount, Long messageId,
String componentId, Long giveawayId);
Optional<Giveaway> loadGiveawayById(Long giveawayId, Long serverId);
}

View File

@@ -0,0 +1,9 @@
package dev.sheldan.abstracto.giveaway.service.management;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.giveaway.model.database.Giveaway;
public interface GiveawayParticipantManagementService {
void addParticipant(Giveaway giveaway, AUserInAServer aUserInAServer);
boolean userIsAlreadyParticipating(Giveaway giveaway, AUserInAServer aUserInAServer);
}

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.13</version>
</parent>
<artifactId>giveaway</artifactId>
<packaging>pom</packaging>
<modules>
<module>giveaway-int</module>
<module>giveaway-impl</module>
</modules>
<dependencies>
<dependency>
<groupId>dev.sheldan.abstracto.core</groupId>
<artifactId>core-int</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>invite-filter</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>invite-filter</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>link-embed</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>link-embed</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>logging</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>logging</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>moderation</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -88,6 +88,9 @@ public class BanServiceBean implements BanService {
AUserInAServer bannedUser = userInServerManagementService.loadOrCreateUser(guild.getIdLong(), user.getIdLong());
AUserInAServer banningUser = userInServerManagementService.loadOrCreateUser(banningMember);
Map<String, String> parameters = new HashMap<>();
if(deletionDuration == null) {
deletionDuration = Duration.ZERO;
}
parameters.put(INFRACTION_PARAMETER_DELETION_DURATION_KEY, deletionDuration.toString());
return infractionService.createInfractionWithNotification(bannedUser, infractionPoints, BAN_INFRACTION_TYPE, reason, banningUser, parameters, banLogMessage)
.thenApply(Infraction::getId);

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>moderation</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>modmail</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>modmail</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto</groupId>
<artifactId>abstracto-application</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -32,6 +32,7 @@
<module>anti-raid</module>
<module>custom-command</module>
<module>twitch</module>
<module>giveaway</module>
</modules>
</project>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>profanity-filter</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>profanity-filter</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>remind</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>remind</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>repost-detection</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>repost-detection</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>starboard</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>starboard</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>statistic</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>statistic</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>suggestion</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -48,7 +48,7 @@ public class UnSuggest extends AbstractConditionableCommand {
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Long suggestionId = slashCommandParameterService.getCommandOption(SUGGESTION_ID_PARAMETER, event, Long.class, Integer.class).longValue();
return suggestionService.removeSuggestion(event.getMember().getIdLong(), suggestionId, event.getMember())
return suggestionService.removeSuggestion(event.getGuild().getIdLong(), suggestionId, event.getMember())
.thenCompose(unused -> interactionService.replyEmbed(UN_SUGGEST_RESPONSE, event))
.thenApply(aVoid -> CommandResult.fromSuccess());
}

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>suggestion</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>twitch</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>twitch</artifactId>
<version>1.5.10</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Some files were not shown because too many files have changed in this diff Show More