Skip to content

Commit 16c577b

Browse files
Release 1.5.0 (#98)
2 parents d9999d4 + c0890d4 commit 16c577b

File tree

23 files changed

+378
-26
lines changed

23 files changed

+378
-26
lines changed

.github/workflows/verify.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
- uses: actions/checkout@v4
1212
- uses: gradle/wrapper-validation-action@v1
1313
- name: Set up JDK 18
14-
uses: actions/setup-java@v3
14+
uses: actions/setup-java@v4
1515
with:
1616
distribution: temurin
1717
java-version: 18

build.gradle.kts

+4-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ plugins {
66
}
77

88
group = "de.chojo"
9-
version = "1.4.3"
9+
version = "1.5.0"
1010

1111
repositories {
1212
mavenCentral()
@@ -21,15 +21,16 @@ dependencies {
2121
}
2222

2323
// database
24-
implementation("org.postgresql", "postgresql", "42.7.0")
24+
implementation("org.postgresql", "postgresql", "42.7.1")
2525
implementation(libs.bundles.sadu)
2626

2727
// Download api
2828
implementation("de.chojo", "nexus-api-wrapper", "1.0.5")
29+
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:*")
2930

3031
// Mailing
3132
implementation("org.eclipse.angus", "angus-mail", "2.0.2")
32-
implementation("org.jsoup", "jsoup", "1.16.2")
33+
implementation("org.jsoup", "jsoup", "1.17.2")
3334

3435

3536
// Logging

gradle/wrapper/gradle-wrapper.jar

-19.8 KB
Binary file not shown.

gradle/wrapper/gradle-wrapper.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
44
networkTimeout=10000
55
validateDistributionUrl=true
66
zipStoreBase=GRADLE_USER_HOME

settings.gradle.kts

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,22 @@ dependencyResolutionManagement {
1212
library("sadu-datasource", "de.chojo.sadu", "sadu-datasource").versionRef("sadu")
1313
bundle("sadu", listOf("sadu-queries", "sadu-updater", "sadu-postgresql", "sadu-datasource"))
1414

15-
version("log4j", "2.22.0")
15+
version("log4j", "2.22.1")
1616

17-
library("slf4j-api", "org.slf4j:slf4j-api:2.0.9")
17+
library("slf4j-api", "org.slf4j:slf4j-api:2.0.11")
1818
library("log4j-core", "org.apache.logging.log4j", "log4j-core").versionRef("log4j")
1919
library("log4j-slf4j2", "org.apache.logging.log4j", "log4j-slf4j2-impl").versionRef("log4j")
2020
library("log4j-jsontemplate","org.apache.logging.log4j", "log4j-layout-template-json").versionRef("log4j")
2121
bundle("log4j", listOf("slf4j-api", "log4j-core", "log4j-slf4j2", "log4j-jsontemplate"))
2222

2323
// plugins
24-
plugin("spotless", "com.diffplug.spotless").version("6.22.0")
24+
plugin("spotless", "com.diffplug.spotless").version("6.24.0")
2525
plugin("shadow", "com.github.johnrengelman.shadow").version("8.1.1")
2626

2727
}
2828
}
2929
}
3030

3131
plugins {
32-
id("org.gradle.toolchains.foojay-resolver-convention") version("0.7.0")
32+
id("org.gradle.toolchains.foojay-resolver-convention") version("0.8.0")
3333
}

src/main/java/de/chojo/lyna/Lyna.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ private void init() throws SQLException, IOException, InterruptedException {
2323
Configuration<ConfigFile> configuration = Configuration.create(new ConfigFile());
2424
var threading = new Threading();
2525
Data data = Data.create(threading, configuration);
26-
Web web = Web.create(configuration, data);
2726
MailingService mailingService = MailingService.create(threading, data, configuration);
27+
Web web = Web.create(configuration, data, mailingService);
2828
Bot bot = Bot.create(data, threading, configuration, web, mailingService);
2929
data.inject(bot);
3030
}

src/main/java/de/chojo/lyna/api/Api.java

+10-6
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@
44
import de.chojo.lyna.api.v1.V1;
55
import de.chojo.lyna.configuration.ConfigFile;
66
import de.chojo.lyna.core.Data;
7+
import de.chojo.lyna.mail.MailingService;
78
import de.chojo.nexus.NexusRest;
89
import io.javalin.Javalin;
910
import io.javalin.http.ContentType;
1011
import org.slf4j.Logger;
1112

13+
import java.util.Objects;
1214
import java.util.stream.Collectors;
1315

1416
import static io.javalin.apibuilder.ApiBuilder.after;
1517
import static io.javalin.apibuilder.ApiBuilder.before;
16-
import static io.javalin.apibuilder.ApiBuilder.get;
1718
import static io.javalin.apibuilder.ApiBuilder.path;
1819
import static org.slf4j.LoggerFactory.getLogger;
1920

@@ -25,16 +26,16 @@ public class Api {
2526

2627
private static final Logger log = getLogger(Api.class);
2728

28-
private Api(Javalin javalin, Configuration<ConfigFile> configuration, Data data) {
29+
private Api(Javalin javalin, Configuration<ConfigFile> configuration, Data data, MailingService mailingService) {
2930
this.javalin = javalin;
3031
this.configuration = configuration;
3132
this.nexus = data.nexus();
32-
v1 = new V1(this, data.products());
33+
v1 = new V1(this, data.products(), mailingService, data.kofi());
3334
}
3435

35-
public static Api create(Configuration<ConfigFile> configuration, Data data) {
36+
public static Api create(Configuration<ConfigFile> configuration, Data data, MailingService mailingService) {
3637
Javalin javalin = Javalin.create();
37-
Api api = new Api(javalin, configuration, data);
38+
Api api = new Api(javalin, configuration, data, mailingService);
3839
api.init();
3940
return api;
4041
}
@@ -60,7 +61,10 @@ private void init() {
6061
ctx.status(),
6162
ctx.res.getHeaderNames().stream().map(h -> " " + h + ": " + ctx.res.getHeader(h))
6263
.collect(Collectors.joining("\n")),
63-
ContentType.OCTET_STREAM.equals(ctx.contentType()) ? "Bytes" : ctx.resultString().substring(0, Math.min(ctx.resultString().length(), 180)));
64+
ContentType.OCTET_STREAM.equals(ctx.contentType()) ? "Bytes"
65+
: Objects.requireNonNullElse(ctx.resultString(), "")
66+
.substring(0, Math.min(
67+
Objects.requireNonNullElse(ctx.resultString(), "").length(), 180)));
6468
});
6569

6670
path("api", () -> {

src/main/java/de/chojo/lyna/api/v1/V1.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,34 @@
22

33
import de.chojo.lyna.api.Api;
44
import de.chojo.lyna.api.v1.download.Download;
5+
import de.chojo.lyna.api.v1.kofi.KoFiApi;
56
import de.chojo.lyna.api.v1.update.Update;
7+
import de.chojo.lyna.data.access.KoFiProducts;
68
import de.chojo.lyna.data.access.Products;
9+
import de.chojo.lyna.mail.MailingService;
710

811
import static io.javalin.apibuilder.ApiBuilder.path;
912

1013
public class V1 {
1114
private final Download download;
1215
private final Update update;
1316
private final Api api;
17+
private final KoFiProducts koFiProducts;
18+
private final KoFiApi kofi;
1419

15-
public V1(Api api, Products products) {
20+
public V1(Api api, Products products, MailingService mailingService, KoFiProducts koFiProducts) {
1621
this.api = api;
22+
this.koFiProducts = koFiProducts;
1723
download = new Download(this);
1824
update = new Update(this, products);
25+
kofi = new KoFiApi(this, koFiProducts, mailingService);
1926
}
2027

2128
public void init() {
2229
path("v1", () -> {
2330
download.init();
2431
update.init();
32+
kofi.init();
2533
});
2634
}
2735

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package de.chojo.lyna.api.v1.kofi;
2+
3+
import com.fasterxml.jackson.core.json.JsonReadFeature;
4+
import com.fasterxml.jackson.databind.MapperFeature;
5+
import com.fasterxml.jackson.databind.ObjectMapper;
6+
import com.fasterxml.jackson.databind.json.JsonMapper;
7+
import de.chojo.lyna.api.v1.V1;
8+
import de.chojo.lyna.api.v1.kofi.payloads.DataType;
9+
import de.chojo.lyna.api.v1.kofi.payloads.KofiPost;
10+
import de.chojo.lyna.api.v1.kofi.payloads.ShopItem;
11+
import de.chojo.lyna.data.access.KoFiProducts;
12+
import de.chojo.lyna.data.dao.licenses.License;
13+
import de.chojo.lyna.data.dao.products.Product;
14+
import de.chojo.lyna.data.dao.products.mailings.Mailing;
15+
import de.chojo.lyna.mail.MailCreator;
16+
import de.chojo.lyna.mail.MailingService;
17+
import de.chojo.lyna.util.Urls;
18+
import io.javalin.http.HttpCode;
19+
20+
import java.util.Optional;
21+
22+
import static io.javalin.apibuilder.ApiBuilder.path;
23+
import static io.javalin.apibuilder.ApiBuilder.post;
24+
25+
public class KoFiApi {
26+
private final V1 v1;
27+
28+
private final KoFiProducts kofi;
29+
private final MailingService mailing;
30+
private final ObjectMapper mapper = JsonMapper.builder()
31+
.configure(JsonReadFeature.ALLOW_MISSING_VALUES, true)
32+
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS)
33+
.findAndAddModules()
34+
.build();
35+
36+
public KoFiApi(V1 v1, KoFiProducts kofi, MailingService mailing) {
37+
this.v1 = v1;
38+
this.kofi = kofi;
39+
this.mailing = mailing;
40+
}
41+
42+
public void init() {
43+
path("kofi", () -> {
44+
post(ctx -> {
45+
var results = Urls.splitQuery(ctx.body());
46+
var json = results.get("data");
47+
var post = mapper.readValue(json, KofiPost.class);
48+
if (post.type() == DataType.SHOP_ORDER) {
49+
for (ShopItem shopItem : post.shopItems()) {
50+
Optional<Product> optProduct = kofi.byCode(shopItem.directLinkCode());
51+
kofi.logTransaction(post, json, shopItem);
52+
if (optProduct.isEmpty()) continue;
53+
Product product = optProduct.get();
54+
Optional<Mailing> optProductMail = product.mailings().get();
55+
if (optProductMail.isEmpty()) continue;
56+
Mailing productMail = optProductMail.get();
57+
Optional<License> license = product.createLicense("kofi:%s".formatted(post.email()));
58+
if(license.isEmpty()) continue;
59+
var mail = MailCreator.createLicenseMessage(productMail, license.get().key(), post.from(), post.email());
60+
mailing.sendMail(mail);
61+
}
62+
} else {
63+
kofi.logTransaction(post, json, null);
64+
}
65+
ctx.status(HttpCode.OK);
66+
});
67+
});
68+
}
69+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package de.chojo.lyna.api.v1.kofi.payloads;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
5+
public enum DataType {
6+
@JsonProperty("Shop Order")
7+
SHOP_ORDER, SUBSCRIPTION, DONATION, COMMISSION
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package de.chojo.lyna.api.v1.kofi.payloads;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import org.jetbrains.annotations.Nullable;
5+
6+
import java.time.OffsetDateTime;
7+
import java.util.List;
8+
import java.util.UUID;
9+
10+
public record KofiPost(@JsonProperty("verification_token") UUID verificationToken,
11+
@JsonProperty("message_id") UUID messageId,
12+
@JsonProperty("timestamp") OffsetDateTime timestamp,
13+
@JsonProperty("type") DataType type,
14+
@JsonProperty("is_public") boolean isPublic,
15+
@JsonProperty("from_name") String from,
16+
@JsonProperty("message") @Nullable String message,
17+
@JsonProperty("amount") Float amount,
18+
@JsonProperty("url") String url,
19+
@JsonProperty("email") String email,
20+
@JsonProperty("currency") String currency,
21+
@JsonProperty("is_subscription_payment") boolean isSubscriptionPayment,
22+
@JsonProperty("is_first_subscription_payment") boolean isFirstSubscriptionPayment,
23+
@JsonProperty("kofi_transaction_id") UUID kofiTransactionId,
24+
@JsonProperty("shop_items") @Nullable List<ShopItem> shopItems,
25+
@JsonProperty("tier_name") String tierName,
26+
@JsonProperty("shipping") Shipping shipping
27+
28+
) {
29+
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package de.chojo.lyna.api.v1.kofi.payloads;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
5+
public record Shipping(@JsonProperty("full_name")String fullName,
6+
@JsonProperty("street_address")String streetAddress,
7+
@JsonProperty("city")String city,
8+
@JsonProperty("state_or_province")String stateOrProvince,
9+
@JsonProperty("postal_code")String postalCode,
10+
@JsonProperty("country")String country,
11+
@JsonProperty("country_code")String countryCode,
12+
@JsonProperty("telephone")String telephone) {
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package de.chojo.lyna.api.v1.kofi.payloads;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
5+
public record ShopItem(@JsonProperty("direct_link_code") String directLinkCode,
6+
@JsonProperty("variation_name") String variationName,
7+
@JsonProperty("quantity") int quantity) {
8+
}

src/main/java/de/chojo/lyna/commands/download/handler/Default.java

+7-3
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@
2525
import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
2626
import net.dv8tion.jda.api.interactions.components.selections.StringSelectMenu;
2727

28-
import java.text.CharacterIterator;
29-
import java.text.StringCharacterIterator;
3028
import java.time.format.DateTimeFormatter;
3129
import java.util.List;
3230
import java.util.Optional;
@@ -46,7 +44,13 @@ public Default(Guilds guilds, Api api) {
4644
@Override
4745
public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) {
4846
var guild = guilds.guild(event.getGuild());
49-
Optional<Product> optProduct = guild.products().byId(event.getOption("product", OptionMapping::getAsInt));
47+
Optional<Product> optProduct;
48+
try {
49+
optProduct = guild.products().byId(event.getOption("product", OptionMapping::getAsInt));
50+
} catch (NumberFormatException e) {
51+
event.reply("Invalid Product. Please use the auto completion.").setEphemeral(true).queue();
52+
return;
53+
}
5054
if (optProduct.isEmpty()) {
5155
event.reply("Invalid Product").setEphemeral(true).queue();
5256
return;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package de.chojo.lyna.commands.kofi;
2+
3+
import de.chojo.jdautil.interactions.slash.Argument;
4+
import de.chojo.jdautil.interactions.slash.Slash;
5+
import de.chojo.jdautil.interactions.slash.SubCommand;
6+
import de.chojo.jdautil.interactions.slash.provider.SlashProvider;
7+
import de.chojo.lyna.commands.kofi.handler.Link;
8+
import de.chojo.lyna.data.access.Guilds;
9+
import de.chojo.lyna.data.access.KoFiProducts;
10+
11+
public class KoFi implements SlashProvider<Slash> {
12+
private final Guilds guilds;
13+
14+
private final KoFiProducts products;
15+
16+
public KoFi(Guilds guilds, KoFiProducts products) {
17+
this.guilds = guilds;
18+
this.products = products;
19+
}
20+
21+
22+
@Override
23+
public Slash slash() {
24+
return Slash.of("kofi", "Manage kofi products")
25+
.unlocalized()
26+
.adminCommand()
27+
.guildOnly()
28+
.subCommand(SubCommand.of("link", "link a link to a produce")
29+
.handler(new Link(products, guilds))
30+
.argument(Argument.text("link", "kofi link code").asRequired())
31+
.argument(Argument.text("product", "product you want to link").asRequired().withAutoComplete()))
32+
.build();
33+
}
34+
}

0 commit comments

Comments
 (0)