Compare commits

...

57 Commits

Author SHA1 Message Date
release-bot
a5d3b970df [maven-release-plugin] prepare release sissi-1.5.17 2025-12-07 12:46:20 +00:00
Sheldan
a47f399d36 [SIS-xxx] slight adaptions for new donation structure 2025-12-07 13:40:52 +01:00
release-bot
29bb752367 Commit from GitHub Actions (Publishes a new version of Sissi) 2025-11-29 13:31:18 +00:00
release-bot
efdb375a83 [maven-release-plugin] prepare for next development iteration 2025-11-29 13:25:49 +00:00
release-bot
f158580897 [maven-release-plugin] prepare release sissi-1.5.16 2025-11-29 13:25:48 +00:00
Sheldan
4411995e65 [SIS-xxx] abstracto upgrade 2025-11-29 14:22:13 +01:00
Sheldan
c9b5258798 [SIS-xxx] changing the setup for donation tracking 2025-11-29 14:21:48 +01:00
Sheldan
ea5a7509bc [SIS-xxx] re-ordering title in leave message 2025-11-27 20:39:02 +01:00
Sheldan
40703005e1 [SIS-xxx] updating join and leave embeds to work with default template 2025-11-23 15:33:06 +01:00
Sheldan
fe036d7010 [SIS-xxx] removing empty spaces and formatting the id better 2025-11-13 00:57:03 +01:00
release-bot
2547d68dfc Commit from GitHub Actions (Publishes a new version of Sissi) 2025-11-12 23:27:53 +00:00
release-bot
b8b59b09c4 [maven-release-plugin] prepare for next development iteration 2025-11-12 23:20:46 +00:00
release-bot
774c142238 [maven-release-plugin] prepare release sissi-1.5.15 2025-11-12 23:20:45 +00:00
Sheldan
5b6160b0d2 [SIS-xxx] upgrading abstracto version
adding custom template for leave message
updating template to fit new leave model
2025-11-13 00:11:01 +01:00
release-bot
453b2214cd Commit from GitHub Actions (Publishes a new version of Sissi) 2025-10-12 18:42:28 +00:00
release-bot
071c603e54 [maven-release-plugin] prepare for next development iteration 2025-10-12 18:37:06 +00:00
release-bot
31538747f5 [maven-release-plugin] prepare release sissi-1.5.14 2025-10-12 18:37:05 +00:00
Sheldan
afb11dc74a [SIS-xxx] upgrading abstracto version 2025-10-12 20:19:40 +02:00
Sheldan
dd5bb63962 [SIS-xxx] fixing meetup display without location 2025-10-03 18:13:58 +02:00
release-bot
28da63db37 Commit from GitHub Actions (Publishes a new version of Sissi) 2025-09-10 23:23:31 +00:00
release-bot
18755afb57 [maven-release-plugin] prepare for next development iteration 2025-09-10 23:16:17 +00:00
release-bot
ccfb64324e [maven-release-plugin] prepare release sissi-1.5.13 2025-09-10 23:16:15 +00:00
Sheldan
d33ce3da6c [SIS-xxx] upgrading abstracto version 2025-09-11 01:11:14 +02:00
release-bot
16553e0299 Commit from GitHub Actions (Publishes a new version of Sissi) 2025-09-10 22:25:34 +00:00
release-bot
dd02b07ff6 [maven-release-plugin] prepare for next development iteration 2025-09-10 22:18:03 +00:00
release-bot
43e372e07a [maven-release-plugin] prepare release sissi-1.5.12 2025-09-10 22:18:01 +00:00
Sheldan
ba42a10122 [SIS-xxx] upgrading abstracto version 2025-09-11 00:12:49 +02:00
Sheldan
28d68b13c7 [SIS-xxx] adding logging to see which quote is sent in the case of random quotes 2025-08-07 19:32:44 +02:00
release-bot
ea0f1fde15 Commit from GitHub Actions (Publishes a new version of Sissi) 2025-08-05 22:16:39 +00:00
release-bot
4904980935 [maven-release-plugin] prepare for next development iteration 2025-08-05 22:11:04 +00:00
release-bot
222e48021f [maven-release-plugin] prepare release sissi-1.5.11 2025-08-05 22:11:02 +00:00
Sheldan
c39996f117 [SIS-xxx] adding docker and helm build to build file 2025-08-06 00:03:56 +02:00
Sheldan
f90defbc64 [SIS-xxx] updating the not properly released version 2025-08-06 00:01:15 +02:00
Sheldan
48c06cf370 [SIS-xxx] fixing dependencies for docker packaging build 2025-08-06 00:00:56 +02:00
release-bot
14d90722b7 [maven-release-plugin] prepare for next development iteration 2025-08-04 19:18:51 +00:00
release-bot
6c48dd790f [maven-release-plugin] prepare release sissi-1.5.10 2025-08-04 19:18:49 +00:00
Sheldan
9e1f7f0263 [SIS-xxx] updating abstracto version to 1.6.12 2025-08-04 21:13:45 +02:00
Sheldan
15ec88c03f [SIS-xxx] fixing name of reason template 2025-07-21 17:42:25 +02:00
release-bot
aeb89533e2 Commit from GitHub Actions (Publishes a new version of Sissi) 2025-07-21 15:33:32 +00:00
release-bot
483d6fde66 [maven-release-plugin] prepare for next development iteration 2025-07-21 15:26:57 +00:00
release-bot
f95beddffa [maven-release-plugin] prepare release sissi-1.5.9 2025-07-21 15:26:55 +00:00
Sheldan
7faafc9ad1 [SIS-xxx] adding multiline support and allowing multiple words for orange sun doge command alternative 2025-07-21 17:18:46 +02:00
Sheldan
1de0cae589 [SIS-xxx] adding self mute command 2025-07-21 16:21:17 +02:00
release-bot
dfbf15ad61 Commit from GitHub Actions (Publishes a new version of Sissi) 2025-07-20 09:55:16 +00:00
release-bot
db271cd448 [maven-release-plugin] prepare for next development iteration 2025-07-20 09:50:00 +00:00
release-bot
8f289baadd [maven-release-plugin] prepare release sissi-1.5.8 2025-07-20 09:49:58 +00:00
Sheldan
2ee5578f4e [SIS-xxx] fixing update issue 2025-07-20 11:43:45 +02:00
Sheldan
b458d8d3a8 [SIS-xxx] adding starboard customization to change color based on disk (semi hardcoded)
upgrading abstracto version
adding avatar to quote response
2025-07-20 11:33:49 +02:00
release-bot
f8353ca19b Commit from GitHub Actions (Publishes a new version of Sissi) 2025-07-13 20:18:05 +00:00
release-bot
023b22b2c2 [maven-release-plugin] prepare for next development iteration 2025-07-13 20:13:09 +00:00
release-bot
9ada2c39a2 [maven-release-plugin] prepare release sissi-1.5.7 2025-07-13 20:13:08 +00:00
Sheldan
d61d378a6a [SIS-xxx] upgrading abstracto to get change for embed cleanup job 2025-07-13 22:09:41 +02:00
release-bot
09af4b516f Commit from GitHub Actions (Publishes a new version of Sissi) 2025-07-13 18:18:03 +00:00
release-bot
0e50a7b826 [maven-release-plugin] prepare for next development iteration 2025-07-13 18:13:04 +00:00
release-bot
d4dc118f66 [maven-release-plugin] prepare release sissi-1.5.6 2025-07-13 18:13:02 +00:00
Sheldan
be35a84dcf [SIS-xxx] upgrading to abstracto version supporting components v2
changing meetup and quote command responses to use components v2
changing column name of quote attachment
2025-07-13 20:09:45 +02:00
release-bot
5f6df14c24 [maven-release-plugin] prepare for next development iteration 2025-05-29 20:30:01 +00:00
143 changed files with 1114 additions and 540 deletions

4
.env
View File

@@ -1,4 +1,4 @@
REGISTRY_PREFIX=harbor.sheldan.dev/sissi/
ABSTRACTO_PREFIX=harbor.sheldan.dev/abstracto/
VERSION=1.5.5
ABSTRACTO_VERSION=1.6.8
VERSION=1.5.16
ABSTRACTO_VERSION=1.6.17

View File

@@ -31,3 +31,23 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
user: Sheldan
token: ${{ secrets.ABSTRACTO_PAT }}
- name: Login to Harbor
uses: docker/login-action@v3
with:
registry: harbor.sheldan.dev
username: ${{ secrets.HARBOR_USERNAME }}
password: ${{ secrets.HARBOR_TOKEN }}
- name: Load env file
id: dotenv
uses: falti/dotenv-action@v1.0.4
with:
path: .env
- name: Docker build
run: docker compose build
env:
REGISTRY_PREFIX: ${{ steps.dotenv.outputs.registry_prefix }}
VERSION: ${{ steps.dotenv.outputs.version }}
- name: Helm package and push
working-directory: ./deployment/helm/
run: |-
helm package sissi

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.application</groupId>
<artifactId>application</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>executable</artifactId>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi</groupId>
<artifactId>sissi</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -34,6 +34,11 @@
<artifactId>rssreader</artifactId>
<version>${rssreader.version}</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>${jsoup.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>dev.sheldan.sissi.application.module.custom</groupId>
<artifactId>sissi-customizations</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<artifactId>image-generation-custom</artifactId>

View File

@@ -50,16 +50,13 @@ public class OrangeSunDogeCommandAlternative implements CommandAlternative {
@Override
public boolean shouldExecute(UnParsedCommandParameter parameter, Guild guild, Message message) {
String contentStripped = message.getContentRaw();
String[] parameters = contentStripped.split(" ");
return parameters.length == 1 && featureFlagService.isFeatureEnabled(imageGenerationFeatureConfig, guild.getIdLong());
return featureFlagService.isFeatureEnabled(imageGenerationFeatureConfig, guild.getIdLong());
}
@Override
public void execute(UnParsedCommandParameter parameter, Message message) {
String contentStripped = message.getContentRaw();
List<String> parameters = Arrays.asList(contentStripped.split(" "));
String inputText = commandRegistry.getCommandName(parameters.get(0), message.getGuild().getIdLong());
String inputText = commandRegistry.getCommandName(contentStripped, message.getGuild().getIdLong());
File triggeredGifFile = imageGenerationService.getOrangeSunDogeImage(inputText);
MessageToSend messageToSend = templateService.renderEmbedTemplate(DOGE_ORANGE_SUN_RESPONSE_TEMPLATE_KEY, new Object(), message.getGuildIdLong());
// template support does not support binary files

View File

@@ -8,6 +8,8 @@ import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@Component
public class ImageGenerationService {
@@ -20,7 +22,7 @@ public class ImageGenerationService {
public File getOrangeSunDogeImage(String inputText) {
try {
return httpService.downloadFileToTempFile(dogeOrangeSunUrl.replace("{1}", inputText));
return httpService.downloadFileToTempFile(dogeOrangeSunUrl.replace("{1}", URLEncoder.encode(inputText, StandardCharsets.UTF_8)));
} catch (IOException e) {
throw new AbstractoRunTimeException(String.format("Failed to download orange doge image for url %s with error %s", inputText, e.getMessage()));
}

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.application.module.custom</groupId>
<artifactId>sissi-customizations</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -0,0 +1,68 @@
package dev.sheldan.sissi.module.custom.moderation.commands;
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.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.sissi.module.custom.moderation.config.ModerationCustomFeatureDefinition;
import dev.sheldan.sissi.module.custom.moderation.service.SelfMuteServiceBean;
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 SelfMute extends AbstractConditionableCommand {
public static final String DURATION_PARAMETER = "duration";
@Autowired
private SelfMuteServiceBean selfMuteServiceBean;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
Duration muteDuration = (Duration) parameters.get(0);
return selfMuteServiceBean.selfMuteMember(commandContext.getAuthor(), muteDuration)
.thenApply(unused -> CommandResult.fromSuccess());
}
@Override
public CommandConfiguration getConfiguration() {
Parameter durationParameter = Parameter
.builder()
.name(DURATION_PARAMETER)
.type(Duration.class)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(durationParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
return CommandConfiguration.builder()
.name("selfMute")
.async(true)
.module(UtilityModuleDefinition.UTILITY)
.templated(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureDefinition getFeature() {
return ModerationCustomFeatureDefinition.MODERATION_CUSTOM;
}
}

View File

@@ -0,0 +1,30 @@
package dev.sheldan.sissi.module.custom.moderation.service;
import dev.sheldan.abstracto.core.service.MemberService;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
@Slf4j
@Component
public class SelfMuteServiceBean {
@Autowired
private MemberService memberService;
@Autowired
private TemplateService templateService;
private static final String SELF_MUTE_REASON_TEMPLATE = "self_mute_reason";
public CompletableFuture<Void> selfMuteMember(Member member, Duration duration) {
String reason = templateService.renderSimpleTemplate(SELF_MUTE_REASON_TEMPLATE, member.getGuild().getIdLong());
log.info("Self muting user {} in server {}.", member.getIdLong(), member.getGuild().getIdLong());
return memberService.timeoutUser(member, duration, reason);
}
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
<include file="seedData/data.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:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
<property name="moderationCustomFeature" value="(SELECT id FROM feature WHERE key = 'moderationCustom')"/>
<property name="utilityModule" value="(SELECT id FROM module WHERE name = 'utility')"/>
<changeSet author="Sheldan" id="moderationCustom_selfmute-commands">
<insert tableName="command">
<column name="name" value="selfMute"/>
<column name="module_id" valueComputed="${utilityModule}"/>
<column name="feature_id" valueComputed="${moderationCustomFeature}"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

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

View File

@@ -5,4 +5,5 @@
<include file="1.1.0/collection.xml" relativeToChangelogFile="true"/>
<include file="1.2.1/collection.xml" relativeToChangelogFile="true"/>
<include file="1.4.45/collection.xml" relativeToChangelogFile="true"/>
<include file="1.5.9/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>application</artifactId>
<groupId>dev.sheldan.sissi.application</groupId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.application</groupId>
<artifactId>sissi-modules</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -15,6 +15,11 @@
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>dev.sheldan.abstracto.scheduling</groupId>
<artifactId>scheduling-int</artifactId>
<version>${abstracto.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
@@ -28,6 +33,10 @@
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
</dependency>
</dependencies>
<build>

View File

@@ -7,10 +7,9 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.RoundingMode;
import java.util.List;
import static dev.sheldan.sissi.module.debra.config.DebraFeatureConfig.DEBRA_DONATION_NOTIFICATION_SERVER_ID_ENV_NAME;
@RestController
@RequestMapping(value = "/debra")
public class DebraDonationStatusController {
@@ -20,50 +19,43 @@ public class DebraDonationStatusController {
@GetMapping(value = "/latestDonations", produces = "application/json")
public DonationStats getLatestDonations() {
Long serverId = Long.parseLong(System.getenv(DEBRA_DONATION_NOTIFICATION_SERVER_ID_ENV_NAME));
DonationsResponse donationResponse = donationService.getSynchronizedCachedDonationAmount(serverId);
DonationsResponse donationResponse = donationService.getSynchronizedCachedDonationAmount();
List<DonationInfo> donations = donationService.getLatestDonations(donationResponse, Integer.MAX_VALUE)
.stream()
.map(DonationInfo::fromDonationItemModel)
.toList();
return DonationStats
.builder()
.totalAmount(donationResponse.getPage().getCollected())
.totalAmount(donationResponse.getCurrentDonationAmount())
.donations(donations)
.build();
}
@GetMapping(value = "/highestDonations", produces = "application/json")
public DonationStats getHighestDonations() {
Long serverId = Long.parseLong(System.getenv(DEBRA_DONATION_NOTIFICATION_SERVER_ID_ENV_NAME));
DonationsResponse donationResponse = donationService.getSynchronizedCachedDonationAmount(serverId);
DonationsResponse donationResponse = donationService.getSynchronizedCachedDonationAmount();
List<DonationInfo> donations = donationService.getHighestDonations(donationResponse, Integer.MAX_VALUE)
.stream()
.map(DonationInfo::fromDonationItemModel)
.toList();
return DonationStats
.builder()
.totalAmount(donationResponse.getPage().getCollected())
.totalAmount(donationResponse.getCurrentDonationAmount())
.donations(donations)
.build();
}
@GetMapping(value = "/campaignInfo", produces = "application/json")
public CampaignInfo getCampaignInfo() {
Long serverId = Long.parseLong(System.getenv(DEBRA_DONATION_NOTIFICATION_SERVER_ID_ENV_NAME));
DonationsResponse donationResponse = donationService.getSynchronizedCachedDonationAmount(serverId);
DonationsResponse donationResponse = donationService.getSynchronizedCachedDonationAmount();
Description pageObject = donationResponse.getPage();
return CampaignInfo
.builder()
.collected(pageObject.getCollected())
.collectedNet(pageObject.getCollectedNet())
.donationCount(donationResponse.getDonationCount())
.currency(pageObject.getCurrency())
.percent(pageObject.getPercent())
.displayName(pageObject.getDisplayName())
.slug(pageObject.getSlug())
.target(pageObject.getTarget())
.collected(donationResponse.getCurrentDonationAmount())
.target(donationResponse.getDonationAmountGoal())
.percent(donationResponse.getCurrentDonationAmount().divide(donationResponse.getDonationAmountGoal(), RoundingMode.CEILING))
.currency("")
.build();
}
}

View File

@@ -36,8 +36,8 @@ public class EndlessStreamController {
public EndlessStreamInfo getLatestDonations(@PathVariable("id") Long id) {
Long serverId = Long.parseLong(System.getenv(DEBRA_DONATION_NOTIFICATION_SERVER_ID_ENV_NAME));
EndlessStream endlessStream = endlessStreamManagementServiceBean.getEndlessStream(id);
DonationsResponse donationInfo = donationService.getSynchronizedCachedDonationAmount(serverId);
BigDecimal collectedAmount = donationInfo.getPage().getCollected();
DonationsResponse donationInfo = donationService.getSynchronizedCachedDonationAmount();
BigDecimal collectedAmount = donationInfo.getCurrentDonationAmount();
Long minuteRate = configService.getLongValueOrConfigDefault(DebraFeatureConfig.ENDLESS_STREAM_MINUTE_RATE, serverId);
Instant endDate = endlessStream.getStartTime().plus(collectedAmount.multiply(new BigDecimal(minuteRate)).toBigInteger().longValue(), ChronoUnit.MINUTES);
return EndlessStreamInfo

View File

@@ -6,9 +6,9 @@ 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.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandParameterKey;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
@@ -26,7 +26,6 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEve
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -70,11 +69,12 @@ public class Donations extends AbstractConditionableCommand {
Integer selectionValue = (Integer) parameters.get(1);
Integer top = null;
Integer latest = null;
switch (type) {
case "top": top = selectionValue; break;
default:
case "latest" :
latest = selectionValue; break;
if(type != null) {
DonationsTypeParameterKey typeKey = CommandParameterKey.getEnumFromKey(DonationsTypeParameterKey.class, type);
switch (typeKey) {
case LATEST -> latest = selectionValue;
case TOP -> top = selectionValue;
}
}
messageToSend = getDonationMessageToSend(commandContext.getGuild().getIdLong(), top, latest);
}
@@ -98,11 +98,10 @@ public class Donations extends AbstractConditionableCommand {
Integer top = null;
Integer latest = null;
if(selectionType != null) {
switch (selectionType) {
case "top": top = selectionValue; break;
default:
case "latest" :
latest = selectionValue; break;
DonationsTypeParameterKey typeKey = CommandParameterKey.getEnumFromKey(DonationsTypeParameterKey.class, selectionType);
switch (typeKey) {
case LATEST -> latest = selectionValue;
case TOP -> top = selectionValue;
}
}
@@ -113,7 +112,7 @@ public class Donations extends AbstractConditionableCommand {
private MessageToSend getDonationMessageToSend(Long serverId, Integer top, Integer latest) {
DonationsModel donationModel;
DonationsResponse donationResponse = donationService.fetchCurrentDonationAmount(serverId);
DonationsResponse donationResponse = donationService.fetchCurrentDonations();
donationModel = donationConverter.convertDonationResponse(donationResponse);
if(top != null) {
donationModel.setDonations(donationService.getHighestDonations(donationResponse, top));
@@ -146,7 +145,7 @@ public class Donations extends AbstractConditionableCommand {
.templated(true)
.name(SELECTION_PARAMETER)
.optional(true)
.type(String.class)
.type(DonationsTypeParameterKey.class)
.build();

View File

@@ -0,0 +1,13 @@
package dev.sheldan.sissi.module.debra.commands;
import dev.sheldan.abstracto.core.command.execution.CommandParameterKey;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum DonationsTypeParameterKey implements CommandParameterKey {
TOP("top"), LATEST("latest");
private String key;
}

View File

@@ -13,7 +13,6 @@ public class DebraFeatureConfig implements FeatureConfig {
public static final String DEBRA_DONATION_NOTIFICATION_DELAY_CONFIG_KEY = "debraDonationNotificationDelayMillis";
public static final String ENDLESS_STREAM_MINUTE_RATE = "endlessStreamMinuteRate";
public static final String DEBRA_DONATION_API_FETCH_SIZE_KEY = "debraDonationApiFetchSize";
public static final String DEBRA_DONATION_NOTIFICATION_SERVER_ID_ENV_NAME = "DEBRA_DONATION_NOTIFICATION_SERVER_ID";
@Override
public FeatureDefinition getFeature() {
@@ -27,6 +26,6 @@ public class DebraFeatureConfig implements FeatureConfig {
@Override
public List<String> getRequiredSystemConfigKeys() {
return Arrays.asList(DEBRA_DONATION_NOTIFICATION_DELAY_CONFIG_KEY, DEBRA_DONATION_API_FETCH_SIZE_KEY, ENDLESS_STREAM_MINUTE_RATE);
return Arrays.asList(DEBRA_DONATION_NOTIFICATION_DELAY_CONFIG_KEY, ENDLESS_STREAM_MINUTE_RATE);
}
}

View File

@@ -10,6 +10,5 @@ import org.springframework.context.annotation.Configuration;
@Setter
@ConfigurationProperties(prefix = "sissi.debra")
public class DebraProperties {
private String websocketURL;
private String donationAPIUrl;
private String donationPageUrl;
}

View File

@@ -1,6 +1,6 @@
package dev.sheldan.sissi.module.debra.converter;
import dev.sheldan.sissi.module.debra.model.api.Donation;
import dev.sheldan.sissi.module.debra.model.api.DonationDto;
import dev.sheldan.sissi.module.debra.model.api.DonationsResponse;
import dev.sheldan.sissi.module.debra.model.commands.DonationItemModel;
import dev.sheldan.sissi.module.debra.model.commands.DonationsModel;
@@ -9,20 +9,19 @@ import org.springframework.stereotype.Component;
@Component
public class DonationConverter {
public DonationItemModel convertDonation(Donation donation) {
public DonationItemModel convertDonation(DonationDto donation) {
return DonationItemModel
.builder()
.donationAmount(donation.getAmount())
.firstName(donation.getFirstname())
.lastName(donation.getLastname())
.anonymous(BooleanUtils.toBoolean(donation.getAnonym()))
.name(donation.getName())
.anonymous(BooleanUtils.toBoolean(donation.getAnonymous()))
.build();
}
public DonationsModel convertDonationResponse(DonationsResponse response) {
return DonationsModel
.builder()
.totalAmount(response.getPage().getCollected())
.totalAmount(response.getCurrentDonationAmount())
.build();
}
}

View File

@@ -0,0 +1,31 @@
package dev.sheldan.sissi.module.debra.job;
import dev.sheldan.sissi.module.debra.service.DonationService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
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 DonationFetchJob extends QuartzJobBean {
@Autowired
private DonationService donationService;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
try {
log.info("Checking for new donations.");
donationService.checkForNewDonations();
} catch (Exception e) {
log.error("Failed to check for new donations.", e);
}
}
}

View File

@@ -1,96 +0,0 @@
package dev.sheldan.sissi.module.debra.listener;
import dev.sheldan.abstracto.core.listener.AsyncStartupListener;
import dev.sheldan.abstracto.core.service.ConfigService;
import dev.sheldan.sissi.module.debra.config.DebraProperties;
import dev.sheldan.sissi.module.debra.model.listener.DonationResponseModel;
import dev.sheldan.sissi.module.debra.service.DonationService;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Nullable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import static dev.sheldan.sissi.module.debra.config.DebraFeatureConfig.DEBRA_DONATION_NOTIFICATION_DELAY_CONFIG_KEY;
import static dev.sheldan.sissi.module.debra.config.DebraFeatureConfig.DEBRA_DONATION_NOTIFICATION_SERVER_ID_ENV_NAME;
@Component
@Slf4j
public class WebsocketListener extends WebSocketListener implements AsyncStartupListener {
@Autowired
private DonationService donationService;
@Autowired
private DebraProperties debraProperties;
@Autowired
private ConfigService configService;
private WebSocket webSocketObj;
private OkHttpClient clientObj;
@Override
public void onOpen(WebSocket webSocket, Response response) {
log.info("Connected to donation websocket.");
super.onOpen(webSocket, response);
}
@Override
public void onMessage(WebSocket webSocket, String text) {
CompletableFuture.runAsync(() -> {
log.info("Handling received message on websocket.");
try {
Long targetServerId = Long.parseLong(System.getenv(DEBRA_DONATION_NOTIFICATION_SERVER_ID_ENV_NAME));
Long delayMillis = configService.getLongValueOrConfigDefault(DEBRA_DONATION_NOTIFICATION_DELAY_CONFIG_KEY, targetServerId);
log.info("Waiting {} milli seconds to send notification.", delayMillis);
Thread.sleep(delayMillis);
log.info("Loading new donation amount and sending notification.");
DonationResponseModel donation = donationService.parseDonationFromMessage(text);
donationService.sendDonationNotification(donation).thenAccept(unused -> {
log.info("Successfully notified about donation.");
}).exceptionally(throwable -> {
log.error("Failed to notify about donation.", throwable);
return null;
});
} catch (Exception exception) {
log.error("Failed to handle websocket message.", exception);
}
});
}
@Override
public void onFailure(WebSocket webSocket, Throwable t, @Nullable Response response) {
log.warn("Websocket connection failed...", t);
}
@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
log.info("Closing websocket connection. It was closed with code {} and reason {}.", code, reason);
}
@Override
public void execute() {
if(clientObj != null) {
clientObj.connectionPool().evictAll();
clientObj.dispatcher().executorService().shutdownNow();
}
clientObj = new OkHttpClient.Builder()
.readTimeout(0, TimeUnit.MILLISECONDS)
.retryOnConnectionFailure(true)
.build();
startConnection(clientObj);
clientObj.dispatcher().executorService().shutdown();
}
private void startConnection(OkHttpClient client) {
log.info("Starting websocket connection.");
Request request = new Request.Builder()
.url(debraProperties.getWebsocketURL())
.build();
this.webSocketObj = client.newWebSocket(request, this);
}
}

View File

@@ -4,17 +4,13 @@ import lombok.Builder;
import lombok.Getter;
import java.math.BigDecimal;
import java.math.BigInteger;
@Builder
@Getter
public class CampaignInfo {
private BigInteger donationCount;
private Integer donationCount;
private BigDecimal collected;
private BigDecimal target;
private String currency;
private String slug;
private String displayName;
private BigDecimal collectedNet;
private BigDecimal percent;
}

View File

@@ -1,28 +0,0 @@
package dev.sheldan.sissi.module.debra.model.api;
import com.google.gson.annotations.SerializedName;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.math.BigDecimal;
@Getter
@Setter
@Builder
public class Description {
@SerializedName("collected")
private BigDecimal collected;
@SerializedName("target")
private BigDecimal target;
@SerializedName("currency")
private String currency;
@SerializedName("slug")
private String slug;
@SerializedName("displayname")
private String displayName;
@SerializedName("collectednet")
private BigDecimal collectedNet;
@SerializedName("percent")
private BigDecimal percent;
}

View File

@@ -1,26 +0,0 @@
package dev.sheldan.sissi.module.debra.model.api;
import com.google.gson.annotations.SerializedName;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.math.BigDecimal;
@Getter
@Setter
@Builder
public class Donation {
@SerializedName("amount")
private BigDecimal amount;
@SerializedName("currency")
private String currency;
@SerializedName("text")
private String text;
@SerializedName("anonym")
private Integer anonym;
@SerializedName("firstname")
private String firstname;
@SerializedName("lastname")
private String lastname;
}

View File

@@ -0,0 +1,27 @@
package dev.sheldan.sissi.module.debra.model.api;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
@Getter
@Setter
@Builder
@ToString
public class DonationDto {
private BigDecimal amount;
private String currency;
private String text;
private Boolean anonymous;
private String name;
private LocalDate date;
public String stringRepresentation() {
return String.format("%s %s %s %s %s", name, amount, text, anonymous, date.format(DateTimeFormatter.ISO_DATE));
}
}

View File

@@ -11,7 +11,7 @@ import java.math.BigDecimal;
@Setter
@Builder
public class DonationInfo {
private String firstName;
private String name;
private BigDecimal donationAmount;
private Boolean anonymous;
@@ -20,7 +20,7 @@ public class DonationInfo {
.builder()
.donationAmount(donationItemModel.getDonationAmount())
.anonymous(donationItemModel.getAnonymous())
.firstName(donationItemModel.getFirstName())
.name(donationItemModel.getName())
.build();
}
}

View File

@@ -1,21 +1,18 @@
package dev.sheldan.sissi.module.debra.model.api;
import com.google.gson.annotations.SerializedName;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.math.BigInteger;
import java.math.BigDecimal;
import java.util.List;
@Getter
@Setter
@Builder
public class DonationsResponse {
@SerializedName("page")
private Description page;
@SerializedName("donation_count")
private BigInteger donationCount;
@SerializedName("donations")
private List<Donation> donations;
private BigDecimal currentDonationAmount;
private BigDecimal donationAmountGoal;
private int donationCount;
private List<DonationDto> donations;
}

View File

@@ -5,13 +5,14 @@ import lombok.Getter;
import lombok.Setter;
import java.math.BigDecimal;
import java.time.LocalDate;
@Getter
@Setter
@Builder
public class DonationItemModel {
private String firstName;
private String lastName;
private String name;
private LocalDate date;
private BigDecimal donationAmount;
private Boolean anonymous;
}

View File

@@ -0,0 +1,30 @@
package dev.sheldan.sissi.module.debra.model.database;
import jakarta.persistence.*;
import lombok.*;
import java.time.Instant;
@Builder
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "donation")
@Getter
@Setter
@EqualsAndHashCode
public class Donation {
@Id
@Column(name = "id", nullable = false)
private String id;
// we cant be sure about duplicates
@Column(name = "count")
private Integer count;
@Column(name = "created")
private Instant created;
@Column(name = "updated")
private Instant updated;
}

View File

@@ -11,6 +11,7 @@ import java.math.BigDecimal;
@ToString
public class DonationResponseModel {
private String donatorName;
private Boolean anonymous;
private BigDecimal amount;
private String message;
}

View File

@@ -0,0 +1,9 @@
package dev.sheldan.sissi.module.debra.repository;
import dev.sheldan.sissi.module.debra.model.database.Donation;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface DonationRepository extends JpaRepository<Donation, String> {
}

View File

@@ -1,52 +1,52 @@
package dev.sheldan.sissi.module.debra.service;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.interaction.ComponentPayloadService;
import dev.sheldan.abstracto.core.interaction.ComponentService;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.ConfigService;
import dev.sheldan.abstracto.core.service.HashService;
import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
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.core.utils.FutureUtils;
import dev.sheldan.sissi.module.debra.exception.DonationAmountNotFoundException;
import dev.sheldan.sissi.module.debra.config.DebraPostTarget;
import dev.sheldan.sissi.module.debra.config.DebraProperties;
import dev.sheldan.sissi.module.debra.converter.DonationConverter;
import dev.sheldan.sissi.module.debra.model.api.Donation;
import dev.sheldan.sissi.module.debra.model.api.DonationDto;
import dev.sheldan.sissi.module.debra.model.api.DonationsResponse;
import dev.sheldan.sissi.module.debra.model.commands.DebraInfoButtonPayload;
import dev.sheldan.sissi.module.debra.model.commands.DebraInfoModel;
import dev.sheldan.sissi.module.debra.model.commands.DonationItemModel;
import dev.sheldan.sissi.module.debra.model.commands.DonationsModel;
import dev.sheldan.sissi.module.debra.model.database.Donation;
import dev.sheldan.sissi.module.debra.model.listener.DonationResponseModel;
import dev.sheldan.sissi.module.debra.model.listener.DonationNotificationModel;
import dev.sheldan.sissi.module.debra.service.management.DonationManagementServiceBean;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.lang3.tuple.Pair;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static dev.sheldan.sissi.module.debra.config.DebraFeatureConfig.DEBRA_DONATION_API_FETCH_SIZE_KEY;
import static dev.sheldan.sissi.module.debra.config.DebraFeatureConfig.DEBRA_DONATION_NOTIFICATION_SERVER_ID_ENV_NAME;
@Component
@@ -62,15 +62,9 @@ public class DonationService {
@Autowired
private TemplateService templateService;
@Autowired
private OkHttpClient okHttpClient;
@Autowired
private DonationConverter donationConverter;
@Autowired
private ConfigService configService;
@Autowired
private ChannelService channelService;
@@ -83,100 +77,209 @@ public class DonationService {
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private DonationManagementServiceBean donationManagementServiceBean;
@Autowired
private HashService hashService;
@Autowired
private DonationService self;
private static final String DEBRA_DONATION_NOTIFICATION_TEMPLATE_KEY = "debra_donation_notification";
private static final Pattern MESSAGE_PATTERN = Pattern.compile("(.*) hat (\\d{1,9},\\d{2}) Euro gespendet!<br \\/>Vielen Dank!<br \\/>Nachricht:<br \\/>(.*)");
private static final String DEBRA_INFO_BUTTON_MESSAGE_TEMPLATE_KEY = "debraInfoButton";
public static final String DEBRA_INFO_BUTTON_ORIGIN = "DEBRA_INFO_BUTTON";
public DonationResponseModel parseDonationFromMessage(String message) {
Matcher matcher = MESSAGE_PATTERN.matcher(message);
if (matcher.find()) {
String donatorName = matcher.group(1);
String amountString = matcher.group(2);
BigDecimal amount = new BigDecimal(amountString.replace(',', '.'));
String donationMessage = Optional.ofNullable(matcher.group(3)).map(msg -> msg.replaceAll("(<br>)+", " ")).map(String::trim).orElse("");
return DonationResponseModel
.builder()
.message(donationMessage)
.donatorName(donatorName)
.amount(amount)
.build();
} else {
throw new IllegalArgumentException("String in wrong format");
}
}
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("d.M.y");
public List<DonationItemModel> getHighestDonations(DonationsResponse response, Integer maxCount) {
List<Donation> topDonations = response
return response
.getDonations()
.stream()
.sorted(Comparator.comparing(Donation::getAmount)
.sorted(Comparator.comparing(DonationDto::getAmount)
.reversed())
.collect(Collectors.toList());
return topDonations
.stream()
.limit(maxCount)
.map(donation -> donationConverter.convertDonation(donation))
.collect(Collectors.toList());
.toList();
}
public List<DonationItemModel> getLatestDonations(DonationsResponse response, Integer maxCount) {
return response
.getDonations()
.stream()
.sorted(Comparator.comparing(DonationDto::getDate).reversed())
.limit(maxCount)
.map(donation -> donationConverter.convertDonation(donation))
.collect(Collectors.toList());
}
public synchronized DonationsResponse getSynchronizedCachedDonationAmount(Long serverId) {
return self.getCachedDonationAmount(serverId);
public synchronized DonationsResponse getSynchronizedCachedDonationAmount() {
return self.getCachedDonationAmount();
}
@Cacheable(value = "donation-cache")
public synchronized DonationsResponse getCachedDonationAmount(Long serverId) {
return self.fetchCurrentDonationAmount(serverId);
public synchronized DonationsResponse getCachedDonationAmount() {
return self.fetchCurrentDonations();
}
public DonationsResponse fetchCurrentDonationAmount(Long serverId) {
public DonationsResponse fetchCurrentDonations() {
try {
Long fetchSize = configService.getLongValueOrConfigDefault(DEBRA_DONATION_API_FETCH_SIZE_KEY, serverId);
Request request = new Request.Builder()
.url(String.format(debraProperties.getDonationAPIUrl(), fetchSize))
.get()
.build();
Response response = okHttpClient.newCall(request).execute();
if(!response.isSuccessful()) {
log.error("Failed to retrieve donation response. Response had code {} with body {} and headers {}.",
response.code(), response.body().string(), response.headers());
throw new DonationAmountNotFoundException();
Document donationPage = Jsoup.connect(debraProperties.getDonationPageUrl()).get();
DecimalFormat decimalFormat = getDecimalFormat();
Element endValueElement = donationPage.getElementById("end-value");
String endValueString = endValueElement.text();
Elements currentValueElement = donationPage.getElementsByClass("current_amount").get(0).getElementsByClass("value");
String[] valueArray = currentValueElement.text().split(" ");
String currentValueString = valueArray[0];
String currency = valueArray[1];
BigDecimal currentValue = (BigDecimal) decimalFormat.parse(currentValueString);
BigDecimal endValue = (BigDecimal) decimalFormat.parse(endValueString);
Element list = donationPage.getElementsByClass("donor-list").first();
Elements donationElements = list.getElementsByClass("list-item");
List<DonationDto> donations = new ArrayList<>();
for (Element donationMainElement : donationElements.asList()) {
Elements nameElement = donationMainElement.getElementsByClass("donor-list-name");
Elements dateElement = donationMainElement.getElementsByClass("donor-list-date");
Elements amountElement = donationMainElement.getElementsByClass("donor-list-amount");
Elements textElement = donationMainElement.getElementsByClass("donor-list-amount-text");
LocalDate dateValue;
if (dateElement.hasText()) {
dateValue = LocalDate.parse(dateElement.text(), DATE_FORMAT);
} else {
dateValue = null;
}
BigDecimal amount;
if (amountElement.hasText()) {
String amountText = amountElement.text().split(" ")[0];
amount = (BigDecimal) decimalFormat.parse(amountText);
} else {
amount = null;
}
String additionalText = textElement.text();
String name = nameElement.text();
boolean anonymous = name.isBlank();
donations.add(DonationDto
.builder()
.anonymous(anonymous)
.name(nameElement.text())
.amount(amount)
.currency(currency)
.name(name)
.text(additionalText)
.date(dateValue)
.build());
}
Gson gson = getGson();
return gson.fromJson(response.body().string(), DonationsResponse.class);
return DonationsResponse
.builder()
.donations(donations)
.currentDonationAmount(currentValue)
.donationAmountGoal(endValue)
.donationCount(donations.size())
.build();
} catch (Exception exception) {
throw new AbstractoRunTimeException(exception);
}
}
private Gson getGson() {
return new GsonBuilder()
.registerTypeAdapter(BigDecimal.class, new BigDecimalGsonAdapter())
.create();
private DecimalFormat getDecimalFormat() {
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
symbols.setGroupingSeparator('.');
symbols.setDecimalSeparator(',');
String pattern = "#,##0.0#";
DecimalFormat decimalFormat = new DecimalFormat(pattern, symbols);
decimalFormat.setParseBigDecimal(true);
return decimalFormat;
}
private DonationsModel getDonationInfoModel(Long serverId) {
return donationConverter.convertDonationResponse(fetchCurrentDonationAmount(serverId));
private DonationsModel getDonationInfoModel() {
return donationConverter.convertDonationResponse(fetchCurrentDonations());
}
public CompletableFuture<Void> sendDonationNotification(DonationResponseModel donation) throws IOException {
private String hashDonation(DonationDto donation) {
return hashService.sha256HashString(donation.stringRepresentation());
}
@Transactional
public void checkForNewDonations() {
List<Donation> allDonations = donationManagementServiceBean.getAllDonations();
Map<String, Integer> existingHashes = allDonations
.stream()
.collect(Collectors.toMap(Donation::getId, Donation::getCount));
DonationsResponse donationResponse = fetchCurrentDonations();
Map<String, Pair<Integer, DonationDto>> donationFromPageHashes = new HashMap<>();
donationResponse.getDonations().forEach(donationDto -> {
String thisHash = hashDonation(donationDto);
if(donationFromPageHashes.containsKey(thisHash)) {
donationFromPageHashes.put(thisHash, Pair.of(donationFromPageHashes.get(thisHash).getLeft() + 1, donationDto));
} else {
donationFromPageHashes.put(thisHash, Pair.of(1, donationDto));
}
});
Set<String> pageHashesToRemove = new HashSet<>();
donationFromPageHashes.entrySet().forEach(pageHash -> {
if(existingHashes.containsKey(pageHash.getKey())) {
Integer existingDonation = existingHashes.get(pageHash.getKey());
int amountDifference = pageHash.getValue().getKey() - existingDonation;
if(amountDifference == 0) {
pageHashesToRemove.add(pageHash.getKey()); // it matches 1:1, we know about all of them already
} if(amountDifference < 0) {
pageHashesToRemove.add(pageHash.getKey());
log.warn("We have more donations than on the page of hash {}:{}.", pageHash.getKey(), amountDifference);
} else {
pageHash.setValue(Pair.of(amountDifference, pageHash.getValue().getRight()));
}
}
});
pageHashesToRemove.forEach(donationFromPageHashes::remove);
if(donationFromPageHashes.isEmpty()) {
log.info("No new donations - ending search.");
return;
}
List<CompletableFuture<Void>> notificationFutures = new ArrayList<>();
donationFromPageHashes.values().forEach(donationInfo -> {
for (int i = 0; i < donationInfo.getLeft(); i++) {
DonationDto donationDto = donationInfo.getRight();
DonationResponseModel model = DonationResponseModel
.builder()
.message(donationDto.getText())
.donatorName(donationDto.getName())
.amount(donationDto.getAmount())
.anonymous(donationDto.getAnonymous())
.build();
notificationFutures.add(sendDonationNotification(model));
}
});
new CompletableFutureList<>(notificationFutures).getMainFuture().thenAccept(unused -> {
log.info("All {} notifications send.", notificationFutures.size());
}).exceptionally(throwable -> {
log.warn("Failed to send notifications about {} new donations.", notificationFutures.size(), throwable);
return null;
});
log.info("Creating/updating {} donation entries.", donationFromPageHashes.size());
allDonations.forEach(donation -> {
Set<String> donationsToRemoveBecauseUpdate = new HashSet<>();
donationFromPageHashes.forEach((key, value) -> {
// its assumed that donationFromPageHashes only contains donations that need to be created
if (donation.getId().equals(key)) {
donation.setCount(value.getLeft() + donation.getCount());
donationManagementServiceBean.updateDonation(donation);
donationsToRemoveBecauseUpdate.add(key);
}
});
donationsToRemoveBecauseUpdate.forEach(donationFromPageHashes::remove);
});
donationFromPageHashes.forEach((key, value) ->
donationManagementServiceBean.saveDonation(key, value.getLeft()));
}
public CompletableFuture<Void> sendDonationNotification(DonationResponseModel donation) {
Long targetServerId = Long.parseLong(System.getenv(DEBRA_DONATION_NOTIFICATION_SERVER_ID_ENV_NAME));
DonationsModel donationInfoModel = getDonationInfoModel(targetServerId);
DonationsModel donationInfoModel = getDonationInfoModel();
DonationNotificationModel model = DonationNotificationModel
.builder()
.donation(donation)

View File

@@ -0,0 +1,33 @@
package dev.sheldan.sissi.module.debra.service.management;
import dev.sheldan.sissi.module.debra.model.database.Donation;
import dev.sheldan.sissi.module.debra.repository.DonationRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class DonationManagementServiceBean {
@Autowired
private DonationRepository donationRepository;
public List<Donation> getAllDonations() {
return donationRepository.findAll();
}
public void updateDonation(Donation donation) {
donationRepository.save(donation);
}
public Donation saveDonation(String hash, Integer count) {
Donation donation = Donation
.builder()
.id(hash)
.count(count)
.build();
return donationRepository.save(donation);
}
}

View File

@@ -4,8 +4,7 @@ abstracto.featureFlags.debra.enabled=false
abstracto.postTargets.debraDonationNotification.name=debraDonationNotification
abstracto.postTargets.debraDonationNotification2.name=debraDonationNotification2
sissi.debra.websocketURL=ws://spenden.baba.fm:8765/
sissi.debra.donationAPIUrl=https://www.altruja.de/api/page/discord-schmetterlingsaktion-2024?details=1&num=%s&ort=0
sissi.debra.donationPageUrl=https://secure.sicherhelfen.org/campaigns/07a3baf6-5cdc-4300-854b-ea2b36b0b218/show
abstracto.systemConfigs.debraDonationNotificationDelayMillis.name=debraDonationNotificationDelayMillis
abstracto.systemConfigs.debraDonationNotificationDelayMillis.longValue=60000

View File

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

View File

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

View File

@@ -0,0 +1,15 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
<changeSet author="Sheldan" id="donation_fetch_job-insert">
<insert tableName="scheduler_job">
<column name="name" value="donationFetchJob"/>
<column name="group_name" value="debra"/>
<column name="clazz" value="dev.sheldan.sissi.module.debra.job.DonationFetchJob"/>
<column name="active" value="true"/>
<column name="cron_expression" value="0 */2 * * * ?"/>
<column name="recovery" value="false"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,28 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
<changeSet author="Sheldan" id="donation-table">
<createTable tableName="donation">
<column name="id" type="TEXT">
<constraints nullable="false"/>
</column>
<column name="count" type="NUMERIC">
<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>
<sql>
DROP TRIGGER IF EXISTS donation_update_trigger ON donation;
CREATE TRIGGER donation_update_trigger BEFORE UPDATE ON donation FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();
</sql>
<sql>
DROP TRIGGER IF EXISTS donation_insert_trigger ON donation;
CREATE TRIGGER donation_insert_trigger BEFORE INSERT ON donation FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
</sql>
</changeSet>
</databaseChangeLog>

View File

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

View File

@@ -5,4 +5,5 @@
<include file="1.3.6/collection.xml" relativeToChangelogFile="true"/>
<include file="1.4.21/collection.xml" relativeToChangelogFile="true"/>
<include file="1.4.29/collection.xml" relativeToChangelogFile="true"/>
<include file="1.5.16/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.application</groupId>
<artifactId>sissi-modules</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -166,6 +166,7 @@ public class CreateMeetup extends AbstractConditionableCommand {
Parameter topicParameter = Parameter
.builder()
.templated(true)
.validators(Arrays.asList(MaxStringLengthValidator.max(256)))
.name(TOPIC_PARAMETER)
.type(String.class)
.build();
@@ -174,6 +175,7 @@ public class CreateMeetup extends AbstractConditionableCommand {
.builder()
.templated(true)
.name(DESCRIPTION_PARAMETER)
.validators(Arrays.asList(MaxStringLengthValidator.max(2048)))
.remainder(true)
.optional(true)
.type(String.class)
@@ -184,6 +186,7 @@ public class CreateMeetup extends AbstractConditionableCommand {
.templated(true)
.name(LOCATION_PARAMETER)
.remainder(true)
.validators(Arrays.asList(MaxStringLengthValidator.max(100)))
.optional(true)
.slashCommandOnly(true)
.type(String.class)

View File

@@ -60,7 +60,7 @@ public class MeetupDecisionListener implements ButtonClickedListener {
MeetupMessageModel meetupMessageModel = meetupServiceBean.getMeetupMessageModel(meetup);
addParticipationToModel(meetupMessageModel, userInAServer, payload.getMeetupDecision());
MessageToSend messageToSend = meetupServiceBean.getMeetupMessage(meetupMessageModel, model.getServerId());
channelService.editEmbedMessageInAChannel(messageToSend.getEmbeds().get(0), model.getEvent().getChannel(), meetup.getMessageId())
channelService.editMessageInAChannelFuture(messageToSend, model.getEvent().getChannel(), meetup.getMessageId())
.thenAccept(message -> log.info("Updated message of meetup {} in channel {} in server {}.", meetup.getId().getId(), meetup.getMeetupChannel().getId(), meetup.getServer().getId()))
.exceptionally(throwable -> {
log.info("Failed to update message of meetup {} in channel {} in server {}.", meetup.getId().getId(), meetup.getMeetupChannel().getId(), meetup.getServer().getId(), throwable);

View File

@@ -372,7 +372,7 @@ public class MeetupServiceBean {
List<Long> userIdsToNotify = participants
.stream()
.map(meetupParticipator -> meetupParticipator.getParticipator().getUserReference().getId())
.collect(Collectors.toList());
.toList();
Long serverId = meetup.getServer().getId();
@@ -415,7 +415,7 @@ public class MeetupServiceBean {
List<Long> userInServerIds = participants
.stream()
.map(meetupParticipant -> meetupParticipant.getParticipator().getUserInServerId())
.collect(Collectors.toList());
.toList();
meetup
.getParticipants().removeIf(meetupParticipant -> userInServerIds.contains(meetupParticipant.getParticipator().getUserInServerId()));
MeetupMessageModel meetupMessageModel = getMeetupMessageModel(meetup);

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>sissi-modules</artifactId>
<groupId>dev.sheldan.sissi.application</groupId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.application</groupId>
<artifactId>application</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -14,6 +14,7 @@
<module>quotes</module>
<module>meetup</module>
<module>debra</module>
<module>miepscord</module>
<module>rss-news</module>
</modules>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.application</groupId>
<artifactId>sissi-modules</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -23,6 +23,7 @@ import dev.sheldan.sissi.module.quotes.config.QuotesModuleDefinition;
import dev.sheldan.sissi.module.quotes.exception.QuoteNotFoundException;
import dev.sheldan.sissi.module.quotes.model.database.Quote;
import dev.sheldan.sissi.module.quotes.service.QuoteServiceBean;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
@@ -37,6 +38,7 @@ import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class QuoteCommand extends AbstractConditionableCommand {
private static final String QUOTE_COMMAND = "quote";
@@ -76,6 +78,7 @@ public class QuoteCommand extends AbstractConditionableCommand {
foundQuote = quoteServiceBean.getRandomQuoteForMember(user);
}
Quote quoteToDisplay = foundQuote.orElseThrow(QuoteNotFoundException::new);
log.info("Displaying quote {} in server {}.", quoteToDisplay.getId(), quoteToDisplay.getServer().getId());
return quoteServiceBean.renderQuoteToMessageToSend(quoteToDisplay)
.thenCompose(messageToSend -> self.sendMessageToChannel(messageToSend, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromSuccess());
@@ -98,6 +101,7 @@ public class QuoteCommand extends AbstractConditionableCommand {
foundQuote = quoteServiceBean.getRandomQuote(server);
}
Quote quoteToDisplay = foundQuote.orElseThrow(QuoteNotFoundException::new);
log.info("Displaying quote {} in server {}.", quoteToDisplay.getId(), quoteToDisplay.getServer().getId());
return quoteServiceBean.renderQuoteToMessageToSend(quoteToDisplay)
.thenCompose(messageToSend -> self.replyMessage(event, messageToSend))
.thenApply(unused -> CommandResult.fromSuccess());

View File

@@ -1,6 +1,8 @@
package dev.sheldan.sissi.module.quotes.model.command;
import dev.sheldan.abstracto.core.models.ServerChannelMessage;
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
import dev.sheldan.abstracto.core.models.template.display.UserDisplay;
import lombok.Builder;
import lombok.Getter;
@@ -11,14 +13,14 @@ import java.util.List;
@Builder
public class QuoteResponseModel {
private Long quoteId;
private String authorAvatarURL;
private String authorName;
private UserDisplay authorUserDisplay;
private MemberDisplay authorMemberDisplay;
private ServerChannelMessage quotedMessage;
private String quoteContent;
private List<String> imageAttachmentURLs;
private List<String> mediaAttachmentURLs;
private List<String> fileAttachmentURLs;
private String adderAvatarURL;
private String adderName;
private UserDisplay adderUserDisplay;
private MemberDisplay adderMemberDisplay;
private Instant creationDate;
private String sourceChannelName;
}

View File

@@ -41,8 +41,8 @@ public class QuoteAttachment {
@Getter
@Setter
@Column(name = "is_image", nullable = false)
@Column(name = "is_media", nullable = false)
@Builder.Default
private Boolean isImage = false;
private Boolean isMedia = false;
}

View File

@@ -4,6 +4,8 @@ import dev.sheldan.abstracto.core.models.ServerChannelMessage;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
import dev.sheldan.abstracto.core.models.template.display.UserDisplay;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.MemberService;
import dev.sheldan.abstracto.core.service.UserService;
@@ -103,21 +105,21 @@ public class QuoteServiceBean {
List<String> imageAttachments = quote
.getAttachments()
.stream()
.filter(QuoteAttachment::getIsImage)
.filter(QuoteAttachment::getIsMedia)
.map(QuoteAttachment::getUrl)
.collect(Collectors.toList());
List<String> fileAttachments = quote
.getAttachments()
.stream()
.filter(quoteAttachment -> !quoteAttachment.getIsImage())
.filter(quoteAttachment -> !quoteAttachment.getIsMedia())
.map(QuoteAttachment::getUrl)
.collect(Collectors.toList());
QuoteResponseModel.QuoteResponseModelBuilder modelBuilder = QuoteResponseModel
.builder()
.quoteContent(quote.getText())
.imageAttachmentURLs(imageAttachments)
.mediaAttachmentURLs(imageAttachments)
.quoteId(quote.getId())
.fileAttachmentURLs(fileAttachments)
.creationDate(quote.getCreated())
@@ -166,42 +168,14 @@ public class QuoteServiceBean {
.filter(user -> user.getIdLong() == quoteAdderUserId)
.findFirst()
.orElse(null);
String adderAvatar = Optional
.ofNullable(adderMember)
.map(member -> member.getUser().getAvatarUrl())
.orElse(Optional
.ofNullable(adderUser)
.map(User::getAvatarUrl)
.orElse(null));
String authorAvatar = Optional
.ofNullable(authorMember)
.map(member -> member.getUser().getAvatarUrl())
.orElse(Optional
.ofNullable(authorUser)
.map(User::getAvatarUrl)
.orElse(null));
String adderName = Optional
.ofNullable(adderMember)
.map(Member::getEffectiveName)
.orElse(Optional
.ofNullable(adderUser)
.map(User::getName)
.orElse(null));
String authorName = Optional
.ofNullable(authorMember)
.map(Member::getEffectiveName)
.orElse(Optional
.ofNullable(authorUser)
.map(User::getName)
.orElse(null));
String channelName = sourceChannel
.map(Channel::getName)
.orElse(null);
QuoteResponseModel model = modelBuilder
.adderAvatarURL(adderAvatar)
.authorAvatarURL(authorAvatar)
.adderName(adderName)
.authorName(authorName)
.authorMemberDisplay(authorMember != null ? MemberDisplay.fromMember(authorMember) : null)
.authorUserDisplay(authorUser != null ? UserDisplay.fromUser(authorUser) : UserDisplay.fromServerUser(ServerUser.fromId(serverId, quotedUserId)))
.adderMemberDisplay(adderMember != null ? MemberDisplay.fromMember(adderMember) : null)
.adderUserDisplay(adderUser != null ? UserDisplay.fromUser(adderUser) : UserDisplay.fromServerUser(ServerUser.fromId(serverId, quoteAdderUserId)))
.sourceChannelName(channelName)
.build();
return templateService.renderEmbedTemplate(QUOTE_RESPONSE_TEMPLATE_KEY, model, serverId);
@@ -260,7 +234,7 @@ public class QuoteServiceBean {
List<Pair<String, Boolean>> attachments = quoteMessage
.getAttachments()
.stream()
.map(attachment -> Pair.of(attachment.getProxyUrl(), attachment.isImage()))
.map(attachment -> Pair.of(attachment.getProxyUrl(), attachment.isImage() || attachment.isVideo()))
.toList();
return quoteManagementService.createQuote(author, adder, quoteMessage.getContentDisplay(), ServerChannelMessage.fromMessage(quoteMessage), attachments);
}

View File

@@ -45,7 +45,7 @@ public class QuoteManagementService {
.url(stringBooleanPair.getLeft())
.quote(quote)
.server(adder.getServerReference())
.isImage(stringBooleanPair.getRight())
.isMedia(stringBooleanPair.getRight())
.build())
.toList();

View File

@@ -0,0 +1,6 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
<include file="tables/tables.xml" relativeToChangelogFile="true"/>
</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:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
<changeSet author="Sheldan" id="quote_attachment-rename-media-column">
<renameColumn
tableName="quote_attachment"
newColumnName="is_media"
oldColumnName="is_image" />
</changeSet>
</databaseChangeLog>

View File

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

View File

@@ -5,4 +5,5 @@
<include file="1.0.2/collection.xml" relativeToChangelogFile="true"/>
<include file="1.4.56/collection.xml" relativeToChangelogFile="true"/>
<include file="1.4.57/collection.xml" relativeToChangelogFile="true"/>
<include file="1.5.6/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>sissi-modules</artifactId>
<groupId>dev.sheldan.sissi.application</groupId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -2,4 +2,4 @@ apiVersion: v2
name: sissi
description: A Helm chart for Kubernetes
type: application
version: 1.5.5
version: 1.5.16

View File

@@ -60,7 +60,7 @@ spec:
- name: DB_SCHEMA
value: {{ .Values.dbCredentials.schema }}
- name: DEBRA_DONATION_NOTIFICATION_SERVER_ID
value: "297910194841583616"
value: "{{ .Values.bot.config.debraNotificationServerId }}"
- name: WEEKLY_TEXT_SERVER_ID
value: "{{ .Values.bot.config.weeklyTextServerId }}"
- name: TOKEN

View File

@@ -3,7 +3,7 @@ bot:
repository: harbor.sheldan.dev/sissi
pullPolicy: Always
image: sissi-bot
tag: 1.5.5
tag: 1.5.16
livenessProbe:
initialDelaySeconds: 60
periodSeconds: 5
@@ -17,12 +17,13 @@ bot:
host: null
config:
weeklyTextServerId: null
debraNotificationServerId: null
restApi:
enabled: true
repository: harbor.sheldan.dev/sissi
pullPolicy: Always
image: sissi-rest-api
tag: 1.5.5
tag: 1.5.16
podAnnotations: {}
podSecurityContext: {}
securityContext: {}
@@ -62,7 +63,7 @@ privateRestApi:
repository: harbor.sheldan.dev/sissi
pullPolicy: Always
image: sissi-private-rest-api
tag: 1.5.5
tag: 1.5.16
podAnnotations: {}
podSecurityContext: {}
securityContext: {}
@@ -93,23 +94,23 @@ templateDeployment:
repository: harbor.sheldan.dev/abstracto
pullPolicy: Always
image: abstracto-template-deployment
tag: 1.6.8
tag: 1.6.17
templateDeploymentData:
repository: harbor.sheldan.dev/sissi
pullPolicy: Always
image: sissi-template-data
tag: 1.5.5
tag: 1.5.16
dbConfigDeployment:
enabled: true
repository: harbor.sheldan.dev/abstracto
pullPolicy: Always
image: abstracto-db-deployment
tag: 1.6.8
tag: 1.6.17
dbConfigDeploymentData:
repository: harbor.sheldan.dev/sissi
pullPolicy: Always
image: sissi-db-data
tag: 1.5.5
tag: 1.5.16
dbCredentials:
host: null
port: null

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi</groupId>
<artifactId>deployment</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -885,6 +885,16 @@
<destFileName>logging-template-overrides.zip</destFileName>
</artifactItem>
<artifactItem>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>starboard-template-overrides</artifactId>
<version>${project.version}</version>
<type>zip</type>
<overWrite>true</overWrite>
<outputDirectory>${file.basedir}/template-data/template-artifacts/</outputDirectory>
<destFileName>starboard-template-overrides.zip</destFileName>
</artifactItem>
<!-- overrides translations -->
<artifactItem>

View File

@@ -1,4 +1,4 @@
FROM alpine:3.19.1
FROM alpine:3.22.1
MAINTAINER Sheldan
ADD config/ /var/db-config/
ADD liquibase-artifacts /var/db-config/liquibase-zips

View File

@@ -4,7 +4,7 @@ ARG VERSION
ARG ABSTRACTO_VERSION
FROM ${REGISTRY_PREFIX}abstracto-rest-api-image-gen:${ABSTRACTO_VERSION:-latest} AS image-gen-api
FROM ${SISSI_REGISTRY_PREFIX}sissi-image-gen-api:${VERSION:-latest} AS sissi-image-gen-api
FROM image_gen AS sissi-image-gen-api
FROM ${REGISTRY_PREFIX}abstracto-rest-api:${ABSTRACTO_VERSION:-latest} AS running-image
COPY --from=image-gen-api /python /python

View File

@@ -2,7 +2,7 @@ ARG REGISTRY_PREFIX
ARG SISSI_REGISTRY_PREFIX
ARG VERSION
ARG ABSTRACTO_VERSION
FROM ${SISSI_REGISTRY_PREFIX}sissi-debra-rest-api:${VERSION:-latest} AS debra-api
FROM debra_rest AS debra-api
FROM ${REGISTRY_PREFIX}abstracto-rest-api-experience:${ABSTRACTO_VERSION:-latest} AS experience-api
FROM ${REGISTRY_PREFIX}abstracto-rest-api-core:${ABSTRACTO_VERSION:-latest} AS core-api

View File

@@ -12,7 +12,7 @@ RUN $JAVA_HOME/bin/jlink \
--compress=2 \
--output /customjre
FROM alpine:3.21
FROM alpine:3.22.1
ENV JAVA_HOME=/jre
ENV PATH="${JAVA_HOME}/bin:${PATH}"

View File

@@ -1,4 +1,4 @@
FROM alpine:3.19.1
FROM alpine:3.22.1
MAINTAINER Sheldan
ADD config /var/template-config/
ADD template-artifacts /var/template-config/templates

View File

@@ -5,7 +5,7 @@
"image-generation",
"quotes", "meetup", "debra", "rss-news", "miepscord",
"moderation-custom", "image-generation-custom",
"moderation-template-overrides", "experience-template-overrides", "logging-template-overrides"
"moderation-template-overrides", "experience-template-overrides", "logging-template-overrides", "starboard-template-overrides"
],
"translation_artifacts": [
"core",

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi</groupId>
<artifactId>sissi</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -1,4 +1,3 @@
version: "3.7"
services:
bot-packaging:
@@ -23,9 +22,9 @@ services:
REGISTRY_PREFIX: ${ABSTRACTO_PREFIX}
VERSION: ${VERSION}
ABSTRACTO_VERSION: ${ABSTRACTO_VERSION}
additional_contexts:
debra_rest: "service:debra-rest-api"
image: ${REGISTRY_PREFIX}sissi-rest-api:${VERSION:-latest}
depends_on:
- debra-rest-api
private-rest-api-packaging:
build:
context: deployment/image-packaging/src/main/docker/private-rest-api
@@ -34,9 +33,9 @@ services:
SISSI_REGISTRY_PREFIX: ${REGISTRY_PREFIX}
ABSTRACTO_VERSION: ${ABSTRACTO_VERSION}
VERSION: ${VERSION}
additional_contexts:
image_gen: "service:image-gen-api"
image: ${REGISTRY_PREFIX}sissi-private-rest-api:${VERSION:-latest}
depends_on:
- image-gen-api
db-data:
build:
context: deployment/image-packaging/src/main/docker/db-data

10
pom.xml
View File

@@ -13,22 +13,22 @@
<groupId>dev.sheldan.sissi</groupId>
<artifactId>sissi</artifactId>
<name>Sissi</name>
<version>1.5.5</version>
<version>1.5.17</version>
<properties>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<abstracto.version>1.6.8</abstracto.version>
<abstracto.templates.version>1.4.56</abstracto.templates.version>
<abstracto.version>1.6.17</abstracto.version>
<abstracto.templates.version>1.4.63</abstracto.templates.version>
<apache-jena.version>4.9.0</apache-jena.version>
<rssreader.version>3.5.0</rssreader.version>
<jsoup.version>1.21.2</jsoup.version>
</properties>
<modules>
<module>application</module>
<module>templates</module>
<module>deployment</module>
<module>application/sissi-modules/miepscord</module>
</modules>
<repositories>
@@ -73,7 +73,7 @@
<connection>scm:git:${project.scm.url}</connection>
<developerConnection>scm:git:${project.scm.url}</developerConnection>
<url>https://github.com/Sheldan/Sissi.git</url>
<tag>sissi-1.5.5</tag>
<tag>sissi-1.5.17</tag>
</scm>
</project>

View File

@@ -239,7 +239,7 @@ def rendering_donation_image(donation_stats, parameters):
height = parameters.font_size
it = 0
for donation in donations_to_draw:
name = donation['firstName'] if not donation['anonymous'] else 'anonym'
name = donation['name'] if not donation['anonymous'] and 'name' in donation else 'anonym'
d1.text((0, height * it), f"{donation['donationAmount']}€ von {name}", fill=parameters.color, font=font)
it += 1
return flask_utils.serve_pil_image(img)

View File

@@ -0,0 +1,76 @@
{
<#assign mapping={
'bp': '340380695585095680',
'np': '400642855682572288',
'bk': '299162473775366144',
'mi': '400642854248120330',
'na': '400642590267146240',
'br': '400642587620278273',
'lo': '400643490020851712',
'lr': '400642584617418753',
'lm': '400642579881787402',
'bo': '400642539889229825',
'bm': '299162333668835328',
'gm': '400642460713484308',
'up': '299162129284726784',
'ap': '336786889589915659',
'dd': '336786578103992323',
'dr': '298790326943088670',
'ms': '298790213453479937',
'bs': '298790020192403456',
'di': '298790014974820356',
'in': '298789520084566018'
}>
<#assign groups={
'1': {'bp': 1, 'np': 2, 'bk': 3, 'mi': 4, 'na': 5, 'br': 6, 'lo': 7, 'lr': 8, 'lm': 9, 'bo': 10, 'bm': 11, 'gm': 12},
'2': {'up': 1, 'ap': 2},
'3': {'dd': 1, 'dr': 2},
'4': {'ms': 1, 'bs': 2},
'5': {'di': 1},
'6': {'in': 1}
}>
<#assign allowedRoleIds=[]>
<#assign reverseMapping={}>
<#list mapping as key, value>
<#assign allowedRoleIds=allowedRoleIds + [value]>
<#assign reverseMapping=reverseMapping + {value: key}>
</#list>
<#assign relevantRoles={}>
<#assign relevantRoleIds=[]>
<#list roles as role>
<#if allowedRoleIds?seq_contains(role.roleId?c)>
<#assign relevantRoles=relevantRoles + {role.roleId?c:role.roleName}>
<#assign relevantRoleIds=relevantRoleIds+[role.roleId?c]>
</#if>
</#list>
<#function is_printed role_id>
<#assign group={}>
<#assign found_prio=1>
<#list groups as key,members>
<#list members as roleshortcut,prio>
<#if role_id=mapping[roleshortcut]>
<#assign group=members>
<#assign found_prio=prio>
</#if>
</#list>
</#list>
<#assign print=true>
<#list group as shortcut,prio>
<#if relevantRoleIds?seq_contains(mapping[shortcut])>
<#if prio < found_prio>
<#assign print=false>
</#if>
</#if>
</#list>
<#return print>
</#function>
<#macro get_title key>
<#assign role_id=mapping[key]><#rt>
<#if is_printed(role_id) && relevantRoleIds?seq_contains(role_id)><#rt>
${relevantRoles[role_id]}<#rt>
</#if>
</#macro>
<#include "user_detail">
<#assign userText><@get_title 'bp'/><@get_title 'np'/><@get_title 'bk'/><@get_title 'mi'/><@get_title 'na'/><@get_title 'br'/><@get_title 'lo'/><@get_title 'lr'/><@get_title 'lm'/><@get_title 'bo'/><@get_title 'bm'/><@get_title 'gm'/><@get_title 'up'/><@get_title 'ap'/><@get_title 'dd'/><@get_title 'dr'/><@get_title 'di'/><@get_title 'in'/> ${user.name} <@get_title 'ms'/><@get_title 'bs'/> (${user.id?c})</#assign>
"additionalMessage": "<#compress><@safe_include "user_left_text"/></#compress>"
}

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi</groupId>
<artifactId>sissi</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -4,7 +4,7 @@
<parent>
<artifactId>customization-templates</artifactId>
<groupId>dev.sheldan.sissi.templates</groupId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<artifactId>image-generation-customization-templates</artifactId>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>customization-templates</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>sissi-templates</artifactId>
<groupId>dev.sheldan.sissi.templates</groupId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>module-templates</artifactId>
<groupId>dev.sheldan.sissi.templates</groupId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -13,7 +13,7 @@
,"fields": [
<#list donations as donation>
{
"name": "<#if donation.anonymous><#include "donations_response_anonymous"><#else>${donation.firstName}</#if>",
"name": "<#if donation.anonymous><#include "donations_response_anonymous"><#else>${donation.name}</#if>",
"value": "${donation.donationAmount}€",
"inline": true
}

View File

@@ -2,12 +2,14 @@
"embeds": [
{
"title": {
<#assign donatorName=donation.donatorName>
<#assign donatorName><#if donation.anonymous><#include "donations_response_anonymous"><#else>${donation.donatorName}</#if></#assign>
<#assign donationAmount=donation.amount>
"title": "<@safe_include "debra_donation_notification_embed_title"/>"
},
<#assign donationMessage=donation.message>
"description": "${donationMessage?json_string}",
<#if donation.message != 'gespendet'>
<#assign donationMessage=donation.message>
"description": "${donationMessage?json_string}",
</#if>
"fields": [
{
<#assign totalDonationAmount=totalDonationAmount>
@@ -24,7 +26,7 @@
"buttons": [
{
"label": "<@safe_include "debra_donation_notification_link_button_label"/>",
"url": "http://tiny.cc/schmetterling2024",
"url": "https://tinyurl.com/debra25",
"buttonStyle": "link",
"metaConfig": {
"persistCallback": false

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>module-templates</artifactId>
<groupId>dev.sheldan.sissi.templates</groupId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -1,33 +1,30 @@
<#include "format_instant">
{
"embeds": [
"components": [
{
<#include "abstracto_color">,
"title": {
"title": "${topic?json_string}"
},
"description": "<@format_instant_long_date_time instant=meetupTime/>
${description?json_string}"
<#if location?? && location != "%22%22">,
"fields": [
{
"name": "<@safe_include "createMeetup_confirmation_location_field_title"/>",
"value": "https://www.google.com/maps?q=${location?json_string}"
}
]
</#if>
}
],
"buttons": [
{
"label": "<@safe_include "createMeetup_confirm_button_label"/>",
"id": "${confirmationId}",
"buttonStyle": "success"
<#assign hasLocation=location?? && location != "%22%22">
"type": "textDisplay",
"content": "<#include "createMeetup_meetup_information">"
},
{
"label": "<@safe_include "createMeetup_cancel_button_label"/>",
"id": "${cancelId}",
"buttonStyle": "danger"
"type": "actionRow",
"actionRowItems": [
{
"label": "<@safe_include "createMeetup_confirm_button_label"/>",
"id": "${confirmationId}",
"buttonStyle": "success",
"type": "button"
},
{
"label": "<@safe_include "createMeetup_cancel_button_label"/>",
"id": "${cancelId}",
"buttonStyle": "danger",
"type": "button"
}
]
}
]
],
"messageConfig": {
"useComponentsV2": true
}
}

View File

@@ -1,10 +1,36 @@
<#include "format_instant">
{
"embeds": [
"components": [
<#list meetups as meetup>
<#assign meetup=meetup>
<#assign topic=meetup.topic>
<#assign time><@format_instant_long_date_time instant=meetup.meetupTime/>
</#assign><#assign timeRelative><@format_instant_relative instant=meetup.meetupTime/></#assign>
<#assign link=meetup.meetupMessage.jumpUrl>
{
<#include "abstracto_color">,
"description": "<#list meetups as meetup><#assign meetup=meetup><#assign topic=meetup.topic><#assign time><@format_instant_long_date_time instant=meetup.meetupTime/></#assign><#assign timeRelative><@format_instant_relative instant=meetup.meetupTime/></#assign><#assign link=meetup.meetupMessage.jumpUrl><#include "meetup_list_meetup_display">
<#else><#include "meetup_list_no_meetups"></#list>"
"type": "section",
"components": [
{
"type": "textDisplay",
"content": "<#include "meetup_list_meetup_display">"
}
]
,"accessory": {
"type": "button",
"label": "<#include "meetup_list_jump_button_label"/>",
"url": "${link}",
"buttonStyle": "link"
}
}
]
<#sep>,</#sep>
<#else>
{
"type": "textDisplay",
"content": "<#include "meetup_list_no_meetups">"
}
</#list>
],
"messageConfig": {
"useComponentsV2": true
}
}

View File

@@ -1,63 +1,78 @@
<#include "format_instant">
{
<#assign roleMention="<@&371419588619141121>"/>
"additionalMessage": "${roleMention?json_string}",
"embeds": [
"components": [
{
"type": "textDisplay",
<#assign roleMention="<@&371419588619141121>"/>
"content": "<#if cancelled>~~</#if>${roleMention?json_string} ${topic?json_string} - <@safe_include "meetup_message_id_display"/><#if cancelled>~~</#if>"
},
<#if description?has_content>
{
<#assign descriptionText>${description?json_string}</#assign>
<#assign organizerText>${organizer.memberMention}</#assign>
"type": "textDisplay",
"content": "<#if cancelled>~~</#if><@safe_include "meetup_description_component"/><#if cancelled>~~</#if>"
},
</#if>
{
<#include "abstracto_color">,
"title": {
"title": "${topic?json_string} - <@safe_include "meetup_message_id_display"/>"
},
<#assign time><@format_instant_long_date_time instant=meetupTime/></#assign>
<#assign timeRelative><@format_instant_relative instant=meetupTime/></#assign>
<#assign organizerText>${organizer.memberMention}</#assign>
<#assign meetupId=meetupId/>
<#assign descriptionText>${description?json_string}</#assign>
<#assign participantsText> (${participants?size}) <#list participants as member>${member.memberMention}<#sep>, </#sep><#else><#include "meetup_message_no_member"></#list></#assign>
<#assign maybeParticipantsText> (${maybeParticipants?size}) <#list maybeParticipants as member>${member.memberMention}<#sep>, </#sep><#else><#include "meetup_message_no_member"></#list></#assign>
<#assign noTimeParticipantsText> (${noTimeParticipants?size}) <#list noTimeParticipants as member>${member.memberMention}<#sep>, </#sep><#else><#include "meetup_message_no_member"></#list></#assign>
<#assign declinedParticipantsText> (${declinedParticipants?size}) <#list declinedParticipants as member>${member.memberMention}<#sep>, </#sep><#else><#include "meetup_message_no_member"></#list></#assign>
"description": "<#if cancelled>~~</#if><@safe_include "meetup_display_description"/><#if cancelled>~~</#if>"
}
],
"buttons": [
{
"label": "<@safe_include "meetup_message_yes_button_label"/>",
"id": "${yesId}",
"buttonStyle": "success"
},
{
"label": "<@safe_include "meetup_message_maybe_button_label"/>",
"id": "${maybeId}",
"buttonStyle": "secondary"
},
{
"label": "<@safe_include "meetup_message_no_time_button_label"/>",
"id": "${noTimeId}",
"buttonStyle": "danger"
},
{
"label": "<@safe_include "meetup_message_no_button_label"/>",
"id": "${noId}",
"buttonStyle": "danger"
}
<#if location?? && location != "%22%22">,
{
"label": "<@safe_include "meetup_message_location_button_label"/>",
"url": "https://www.google.com/maps?q=${location?json_string}",
"buttonStyle": "link"
<#if location?? && location != "%22%22">
"type": "section",
"components": [
{
"type": "textDisplay",
"content": "<@safe_include "meetup_display_time_component"/>"
}
],
"accessory": {
"type": "button",
"label": "<@safe_include "meetup_message_location_button_label"/>",
"url": "https://www.google.com/maps?q=${location?json_string}",
"buttonStyle": "link"
}
<#else>
"type": "textDisplay",
"content": "<@safe_include "meetup_display_time_component"/>"
</#if>
}
<#macro decision_component button_id button_style label_template content_template user>
{
"type": "section",
"components": [
{
"type": "textDisplay",
"content": "<@safe_include content_template/>"
}
]
,"accessory": {
"type": "button",
"id": "${button_id}",
"label": "<@safe_include label_template/>",
"buttonStyle": "${button_style}"
}
}
</#macro>
<#assign participantsText> (${participants?size}) <#list participants as member>${member.memberMention}<#sep>, </#sep><#else><#include "meetup_message_no_member"></#list></#assign>
<#assign maybeParticipantsText> (${maybeParticipants?size}) <#list maybeParticipants as member>${member.memberMention}<#sep>, </#sep><#else><#include "meetup_message_no_member"></#list></#assign>
<#assign noTimeParticipantsText> (${noTimeParticipants?size}) <#list noTimeParticipants as member>${member.memberMention}<#sep>, </#sep><#else><#include "meetup_message_no_member"></#list></#assign>
<#assign declinedParticipantsText> (${declinedParticipants?size}) <#list declinedParticipants as member>${member.memberMention}<#sep>, </#sep><#else><#include "meetup_message_no_member"></#list></#assign>
,<@decision_component yesId "success" "meetup_message_yes_button_label" "meetup_user_display_participants" participantsText/>
,<@decision_component maybeId "secondary" "meetup_message_maybe_button_label" "meetup_user_display_maybe_participants" maybeParticipantsText/>
,<@decision_component noId "danger" "meetup_message_no_button_label" "meetup_user_display_declined_participants" declinedParticipantsText/>
,<@decision_component noTimeId "danger" "meetup_message_no_time_button_label" "meetup_user_display_no_time_participants" noTimeParticipantsText/>
<#if meetupIcsModel.attachIcsFile>
,{
"type": "fileDisplay",
"fileName": "<@safe_include "meetup_ics_file_name"/>.ics",
"fileContent": "<@safe_include "meetup_ice_file_download"/>"
}
</#if>
],
<#if meetupIcsModel.attachIcsFile>
"files": [
{
"fileName": "<@safe_include "meetup_ics_file_name"/>.ics",
"fileContent": "<@safe_include "meetup_ice_file_download"/>"
}
],
</#if>
"messageConfig": {
"allowsRoleMention": true
"allowsRoleMention": true,
"allowsUserMention": false,
"useComponentsV2": true
}
}

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>module-templates</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<artifactId>miepscord-templates</artifactId>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>sissi-templates</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>module-templates</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -1,26 +1,83 @@
<#include "format_instant">
{
"embeds": [
"components": [
{
<#include "abstracto_color">,
"author": {
<#assign authorName><@default_template_if_null authorName "quote_response_default_author_name"/></#assign>
<#assign channelName><@default_template_if_null sourceChannelName "quote_response_default_channel_name"/></#assign>
"name": "<@safe_include "quote_response_header_author_name"/>"
<#if authorAvatarURL??>,"avatar": "${authorAvatarURL}"</#if>
},
<#assign quoteId=quoteId>
<#assign quoteDescription=quoteContent>
<#assign quoteJumpUrl=quotedMessage.jumpUrl>
"description": "<@safe_include "quote_response_description"/>",
"footer": {
<#assign adderUserName><@default_template_if_null adderName "quote_response_default_adder_name"/></#assign>
"text": "<@safe_include "quote_response_footer_adder_name" />"
<#if adderAvatarURL??>,"icon": "${adderAvatarURL}"</#if>
},
<#if imageAttachmentURLs?size = 1>
"imageUrl": "${imageAttachmentURLs[0]}",
<#assign userFound=authorUserDisplay?has_content>
<#assign authorName><#if authorMemberDisplay?has_content>${authorMemberDisplay.name}<#elseif authorUserDisplay?has_content>${authorUserDisplay.name}<#else><@safe_include "quote_response_default_author_name"/></#if></#assign>
<#assign adderUserName><#if adderMemberDisplay?has_content>${adderMemberDisplay.name}<#elseif adderUserDisplay?has_content>${adderUserDisplay.name}<#else><@safe_include "quote_response_default_adder_name"/></#if></#assign>
<#assign channelName><@default_template_if_null sourceChannelName "quote_response_default_channel_name"/></#assign>
<#assign creationDate><@format_instant_date_time instant=creationDate/></#assign>
<#if userFound>
<#assign authorAvatar><#if userFound>${authorUserDisplay.avatarUrl}</#if></#assign>
"type": "section",
"components": [
{
"type": "textDisplay",
"content": "<@safe_include "quote_response_header_author_name"/>"
}
],
"accessory": {
"type": "thumbnail",
"url": "${authorAvatar}"
}
<#else>
"type": "textDisplay",
"content": "<@safe_include "quote_response_header_author_name"/>"
</#if>
"timeStamp": "${creationDate}"
},
{
"type": "section",
"components": [
{
<#assign quoteId=quoteId>
"type": "textDisplay",
"content": "<@safe_include "quote_response_title"/>"
}
],
<#assign quoteJumpUrl=quotedMessage.jumpUrl>
"accessory": {
"type": "button",
"label": "<@safe_include "quote_response_jump_label"/>",
"url": "${quoteJumpUrl}",
"buttonStyle": "link"
}
},
{
"type": "container",
"components": [
<#assign hasContent=false>
<#if quoteContent?has_content>
<#assign hasContent=true>
{
"type": "textDisplay",
<#assign quoteDescription=quoteContent?json_string>
"content": "${quoteDescription}"
}
</#if>
<#if mediaAttachmentURLs?size gt 0>
<#assign hasContent=true>
,{
"type": "mediaGallery",
"images": [
<#list mediaAttachmentURLs as image>
{
"url": "${image}"
}<#sep>,</#list>
]
}
</#if>
<#if hasContent==false>
{
"type": "textDisplay",
"content": "<@safe_include "quote_response_no_content"/>"
}
</#if>
]
}
]
],
"messageConfig": {
"allowsUserMention": false,
"useComponentsV2": true
}
}

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>module-templates</artifactId>
<groupId>dev.sheldan.sissi.templates</groupId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>templates</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>template-overrides</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>template-overrides</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -1,5 +1,5 @@
{
<#assign userMention>${member.asMention}</#assign>
<#assign user>${member.user.name} (${member.asMention}: ${member.id})</#assign>
<#assign userText>${member.user.name} (${member.asMention}: ${member.id?c})</#assign>
"additionalMessage": "<@safe_include "user_joined_text"/>"
}

View File

@@ -1,5 +1,5 @@
{
<#include "user_detail">
<#assign user><@user_detail user=user/></#assign>
<#assign userText>${user.name} (${user.userMention}: ${user.id?c})</#assign>
"additionalMessage": "<@safe_include "user_left_text"/>"
}

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>template-overrides</artifactId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>sissi-templates</artifactId>
<groupId>dev.sheldan.sissi.templates</groupId>
<version>1.5.5</version>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -13,6 +13,7 @@
<module>moderation-template-overrides</module>
<module>experience-template-overrides</module>
<module>logging-template-overrides</module>
<module>starboard-template-overrides</module>
</modules>
</project>

View File

@@ -0,0 +1,35 @@
<?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">
<parent>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>template-overrides</artifactId>
<version>1.5.17</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>starboard-template-overrides</artifactId>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>moderation-template-overrides-${project.version}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/main/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

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