From 20d999336b65fc0b68b1f77096c209877ac77245 Mon Sep 17 00:00:00 2001
From: Vitaly Takmazov
Date: Sat, 11 Nov 2023 02:09:21 +0300
Subject: Do not use outdated Patreon library, use Rest API directly
---
pom.xml | 5 --
src/main/java/com/juick/config/AppConfig.java | 15 +---
.../java/com/juick/service/PatreonService.java | 92 ++++++++++++++++++++++
.../com/juick/www/api/webhooks/PatreonWebhook.java | 28 +++----
4 files changed, 102 insertions(+), 38 deletions(-)
create mode 100644 src/main/java/com/juick/service/PatreonService.java
diff --git a/pom.xml b/pom.xml
index 28f2bbfb..1fcbfa1f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -281,11 +281,6 @@
org.postgresql
postgresql
-
- com.patreon
- patreon
- 0.4.2
-
com.kohlschutter.junixsocket
junixsocket-core
diff --git a/src/main/java/com/juick/config/AppConfig.java b/src/main/java/com/juick/config/AppConfig.java
index 2963ee27..77229d1b 100644
--- a/src/main/java/com/juick/config/AppConfig.java
+++ b/src/main/java/com/juick/config/AppConfig.java
@@ -19,16 +19,10 @@ package com.juick.config;
import com.juick.*;
import com.juick.model.User;
-import com.juick.service.HelpService;
-import com.juick.service.SignatureService;
-import com.juick.service.StorageService;
-import com.juick.service.FileSystemStorageService;
-import com.juick.service.UserService;
+import com.juick.service.*;
import com.mitchellbosecke.pebble.extension.FormatterExtension;
import com.overzealous.remark.Options;
import com.overzealous.remark.Remark;
-
-import com.patreon.PatreonAPI;
import io.pebbletemplates.pebble.PebbleEngine;
import io.pebbletemplates.pebble.loader.ClasspathLoader;
import io.pebbletemplates.pebble.loader.Loader;
@@ -66,8 +60,6 @@ public class AppConfig {
private Resource keystore;
@Value("${keystore_password:secret}")
private String keystorePassword;
- @Value("${patreon_creator_access_token:secret}")
- private String creatorAccessToken;
@Bean
KeystoreManager keystoreManager() {
@@ -171,11 +163,6 @@ public class AppConfig {
return new TopManager();
}
- @Bean
- PatreonAPI patreonClient() {
- return new PatreonAPI(creatorAccessToken);
- }
-
@Bean
ViewResolver viewResolver() {
diff --git a/src/main/java/com/juick/service/PatreonService.java b/src/main/java/com/juick/service/PatreonService.java
new file mode 100644
index 00000000..fdd6d3dd
--- /dev/null
+++ b/src/main/java/com/juick/service/PatreonService.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2008-2023, Juick
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.juick.service;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import javax.inject.Inject;
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.StreamSupport;
+
+@Component
+public class PatreonService {
+
+ @Inject
+ private OkHttpClient httpClient;
+ @Inject
+ private ObjectMapper jsonMapper;
+ @Value("${patreon_creator_access_token:secret}")
+ private String creatorAccessToken;
+
+ public List fetchCampaigns() {
+ var resourceUri = UriComponentsBuilder.fromPath("/api/oauth2/v2/campaigns")
+ .host("www.patreon.com")
+ .scheme("https").build().toUriString();
+ var request = new Request.Builder()
+ .url(resourceUri)
+ .addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
+ .addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + creatorAccessToken)
+ .build();
+ try {
+ try (var response = httpClient.newCall(request).execute()) {
+ if (response.isSuccessful() && response.body() != null) {
+ var body = jsonMapper.readTree(response.body().string());
+ var data = body.get("data");
+ return StreamSupport.stream(data.spliterator(), false)
+ .map(campaign -> campaign.get("id").textValue())
+ .toList();
+ }
+ }
+ } catch (IOException e) {
+ return List.of();
+ }
+ return List.of();
+ }
+ public List fetchPledges(String campaignId) {
+ var resourceUri = UriComponentsBuilder.fromPath(String.format("/api/oauth2/api/campaigns/%s/pledges?include=patron.null", campaignId))
+ .host("www.patreon.com")
+ .scheme("https").build().toUriString();
+ var request = new Request.Builder()
+ .url(resourceUri)
+ .addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
+ .addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + creatorAccessToken)
+ .build();
+ try {
+ try (var response = httpClient.newCall(request).execute()) {
+ if (response.isSuccessful() && response.body() != null) {
+ var body = jsonMapper.readTree(response.body().string());
+ var data = body.get("included");
+ return StreamSupport.stream(data.spliterator(), false)
+ .map(campaign -> campaign.get("attributes").get("email").textValue())
+ .toList();
+ }
+ }
+ } catch (IOException e) {
+ return List.of();
+ }
+ return List.of();
+ }
+}
diff --git a/src/main/java/com/juick/www/api/webhooks/PatreonWebhook.java b/src/main/java/com/juick/www/api/webhooks/PatreonWebhook.java
index 2bdeb020..99999838 100644
--- a/src/main/java/com/juick/www/api/webhooks/PatreonWebhook.java
+++ b/src/main/java/com/juick/www/api/webhooks/PatreonWebhook.java
@@ -18,11 +18,9 @@
package com.juick.www.api.webhooks;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.github.jasminb.jsonapi.JSONAPIDocument;
+import com.juick.service.PatreonService;
import com.juick.service.UserService;
import com.juick.util.HttpForbiddenException;
-import com.patreon.PatreonAPI;
-import com.patreon.resources.User;
import org.apache.commons.codec.digest.HmacUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
@@ -35,7 +33,6 @@ import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import javax.inject.Inject;
-import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@@ -48,7 +45,7 @@ public class PatreonWebhook {
@Value("${patreon_secret:}")
private String secretKey;
@Inject
- private PatreonAPI patreonClient;
+ private PatreonService patreonService;
@Inject
private ObjectMapper jsonMapper;
@Inject
@@ -70,21 +67,14 @@ public class PatreonWebhook {
var updatedEmails = StreamSupport.stream(json.get("included").spliterator(), false)
.filter(node -> node.get("type").textValue().equals("user"))
.map(node -> node.get("attributes").get("email").textValue()).toList();
- JSONAPIDocument userResponse = patreonClient.fetchUser();
- User creator = userResponse.get();
- logger.info("Patreon user: {}", jsonMapper.writeValueAsString(creator));
- var campainsResponse = patreonClient.fetchCampaigns();
+ var campainsResponse = patreonService.fetchCampaigns();
List activeEmails = new ArrayList<>();
- campainsResponse.get().forEach(campaign -> {
- try {
- var pledgesResponse = patreonClient.fetchAllPledges(campaign.getId());
- pledgesResponse.forEach(pledge -> {
- logger.info("Pledge: {}, email: {}", pledge.getPatron().getFullName(), pledge.getPatron().getEmail());
- activeEmails.add(pledge.getPatron().getEmail());
- });
- } catch (IOException e) {
- logger.warn("Patreon exception: {}", e.getMessage());
- }
+ campainsResponse.forEach(campaign -> {
+ var pledgesResponse = patreonService.fetchPledges(campaign);
+ pledgesResponse.forEach(pledge -> {
+ logger.info("Pledge email: {}", pledge);
+ activeEmails.add(pledge);
+ });
});
activeEmails.forEach(email -> {
var user = userService.getUserByEmail(email);
--
cgit v1.2.3