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 --- src/main/java/com/juick/config/AppConfig.java | 15 +--- .../java/com/juick/service/PatreonService.java | 92 ++++++++++++++++++++++ .../com/juick/www/api/webhooks/PatreonWebhook.java | 28 +++---- 3 files changed, 102 insertions(+), 33 deletions(-) create mode 100644 src/main/java/com/juick/service/PatreonService.java (limited to 'src') 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