Skip to content

Commit

Permalink
Handle sponsor adding automatically
Browse files Browse the repository at this point in the history
  • Loading branch information
rtm516 committed Aug 24, 2024
1 parent db9a3ac commit 45dfa6c
Show file tree
Hide file tree
Showing 13 changed files with 630 additions and 4 deletions.
13 changes: 12 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
plugins {
id 'java-library'
id 'application'
id("com.apollographql.apollo").version("4.0.0")
}

group 'org.rtm516.discordbot'
Expand Down Expand Up @@ -58,10 +59,20 @@ dependencies {
implementation 'commons-net:commons-net:3.11.1'

// Github API
implementation 'org.kohsuke:github-api:1.323'
implementation 'org.kohsuke:github-api:1.324'

// For adding users to the user cache in JDA
implementation 'net.sf.trove4j:core:3.1.0'

// GraphQL
implementation 'com.apollographql.java:client:0.0.2'
}

apollo {
service("service") {
packageName.set("com.rtm516.discordbot.graphql")
generateKotlinModels.set(false)
}
}

jar {
Expand Down
44 changes: 44 additions & 0 deletions src/main/graphql/SponsorsQuery.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
query SponsorsQuery($username: String!, $count: Int!, $cursor: String!) {
user(login: $username) {
sponsors(first: $count, after: $cursor) {
totalCount
pageInfo {
endCursor
hasNextPage
}
nodes {
__typename
... on User {
login
sponsorshipsAsSponsor(first: 1) {
nodes {
isActive
isOneTimePayment
tier {
monthlyPriceInCents
}
tierSelectedAt
createdAt
}
totalRecurringMonthlyPriceInCents
}
}
... on Organization {
login
sponsorshipsAsSponsor(first: 1) {
nodes {
isActive
isOneTimePayment
tier {
monthlyPriceInCents
}
tierSelectedAt
createdAt
}
totalRecurringMonthlyPriceInCents
}
}
}
}
}
}
2 changes: 2 additions & 0 deletions src/main/graphql/graphql.config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: schema.json
documents: '**/*.graphql'
1 change: 1 addition & 0 deletions src/main/graphql/schema.json

Large diffs are not rendered by default.

24 changes: 21 additions & 3 deletions src/main/java/org/rtm516/discordbot/DiscordBot.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@

package org.rtm516.discordbot;

import com.apollographql.java.client.ApolloClient;
import com.jagrosh.jdautilities.command.Command;
import com.jagrosh.jdautilities.command.CommandClientBuilder;
import com.jagrosh.jdautilities.command.ContextMenu;
import com.jagrosh.jdautilities.command.SlashCommand;
import com.jagrosh.jdautilities.commons.waiter.EventWaiter;
import com.rtm516.discordbot.graphql.SponsorsQuery;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.OnlineStatus;
Expand All @@ -38,6 +40,7 @@
import net.dv8tion.jda.api.utils.MemberCachePolicy;
import net.dv8tion.jda.api.utils.cache.CacheFlag;
import net.dv8tion.jda.api.utils.messages.MessageRequest;
import org.rtm516.discordbot.http.Server;
import org.rtm516.discordbot.listeners.*;
import org.rtm516.discordbot.storage.AbstractStorageManager;
import org.rtm516.discordbot.storage.StorageType;
Expand All @@ -47,6 +50,8 @@
import org.kohsuke.github.GitHub;
import org.kohsuke.github.GitHubBuilder;
import org.reflections.Reflections;
import org.rtm516.discordbot.util.Sponsor;
import org.rtm516.discordbot.util.SponsorUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -73,6 +78,7 @@ public class DiscordBot {

private static JDA jda;
private static GitHub github;
private static Server httpServer;

static {
// Gathers all commands from "commands" package.
Expand Down Expand Up @@ -218,6 +224,16 @@ public static void main(String[] args) throws IOException {

// Register listeners
jda.addEventListener();

SponsorUtil.init();

try {
httpServer = new Server();
httpServer.start();
} catch (Exception e) {
// TODO
e.printStackTrace();
}
}

public static JDA getJDA() {
Expand All @@ -233,11 +249,13 @@ public static ScheduledExecutorService getGeneralThreadPool() {
}

public static void shutdown() {
DiscordBot.LOGGER.info("Shutting down storage...");
LOGGER.info("Shutting down storage...");
storageManager.closeStorage();
DiscordBot.LOGGER.info("Shutting down thread pool...");
LOGGER.info("Shutting down thread pool...");
generalThreadPool.shutdown();
DiscordBot.LOGGER.info("Finished shutdown, exiting!");
LOGGER.info("Shutting http server...");
httpServer.stop();
LOGGER.info("Finished shutdown, exiting!");
System.exit(0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/GeyserDiscordBot
*/

package org.rtm516.discordbot.commands;

import com.jagrosh.jdautilities.command.SlashCommand;
import com.jagrosh.jdautilities.command.SlashCommandEvent;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.UserSnowflake;
import net.dv8tion.jda.api.interactions.InteractionHook;
import net.dv8tion.jda.api.utils.TimeFormat;
import org.rtm516.discordbot.util.BotColors;
import org.rtm516.discordbot.util.Sponsor;
import org.rtm516.discordbot.util.SponsorUtil;

import java.util.Optional;

public class CheckDonateCommand extends SlashCommand {
public CheckDonateCommand() {
this.name = "checkdonate";
this.help = "Checks if your linked github account has an active sponsorship";
this.guildOnly = true;
}

@Override
protected void execute(SlashCommandEvent event) {
InteractionHook interactionHook = event.deferReply(true).complete();

// Check if the user has linked their github account
String ghUsername = SponsorUtil.getGithub(event.getUser());
if (ghUsername == null) {
interactionHook.editOriginalEmbeds(new EmbedBuilder()
.setTitle("No linked github account found")
.setDescription("Please link your github account on " + SponsorUtil.getGithubLink(event.getUser()))
.setColor(BotColors.FAILURE.getColor())
.build()).queue();
return;
}

// Check if the user has an active sponsorship
SponsorUtil.getSponsors().thenAccept(sponsors -> {
Optional<Sponsor> foundSponsor = sponsors.stream().filter(sponsor -> sponsor.username().equals(ghUsername)).findFirst();

if (foundSponsor.isPresent() && foundSponsor.get().active()) {
interactionHook.editOriginalEmbeds(new EmbedBuilder()
.setTitle("Active Sponsorship Found!")
.addField("Github Username", foundSponsor.get().username(), true)
.addField("Amount", "$" + String.format("%.02f", foundSponsor.get().amount()), true)
.addField("Re-occuring", String.valueOf(!foundSponsor.get().oneTime()), true)
.addField("Started", TimeFormat.DATE_TIME_SHORT.format(foundSponsor.get().started()), true)
.setColor(BotColors.SUCCESS.getColor())
.build()).queue();

SponsorUtil.checkAdd(event.getGuild(), foundSponsor.get());
} else {
interactionHook.editOriginalEmbeds(new EmbedBuilder()
.setTitle("No active sponsorship found")
.addField("Github Username", ghUsername, true)
.setColor(BotColors.FAILURE.getColor())
.build()).queue();
}
});
}
}
107 changes: 107 additions & 0 deletions src/main/java/org/rtm516/discordbot/http/Server.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Copyright (c) 2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/GeyserDiscordBot
*/

package org.rtm516.discordbot.http;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpServer;
import org.rtm516.discordbot.util.SponsorUtil;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class Server {
private final HttpServer server;

public Server() throws Exception {
server = HttpServer.create(new InetSocketAddress("0.0.0.0", 3000), 0);
server.createContext("/", exchange -> {
if (exchange.getRequestURI().getQuery() == null) {
respond("Invalid request", exchange);
return;
}

Map<String, String> queryParams = queryToMap(exchange.getRequestURI().getQuery());

String code = queryParams.getOrDefault("code", null);
String state = queryParams.getOrDefault("state", null);

if (code == null || state == null) {
respond("Invalid request", exchange);
} else {
respond(SponsorUtil.linkGithub(UUID.fromString(state), code), exchange);
}
});
server.setExecutor(null); // creates a default executor
}

public void start() {
server.start();
}

public void stop() {
server.stop(0);
}

private void respond(String message, HttpExchange exchange) throws IOException {
String response = "<html><body><h1>" + message + "</h1></body></html>";

exchange.getResponseHeaders().set("Content-Type", "text/html; charset=UTF-8");
byte[] bytes = response.getBytes(StandardCharsets.UTF_8);
exchange.sendResponseHeaders(200, bytes.length);
OutputStream os = exchange.getResponseBody();
os.write(bytes);
os.close();
}

/**
* Take a raw query string and transforming it into a key value map
*
* @param query The raw query string
* @return The key value map of the query params
*/
public static Map<String, String> queryToMap(String query) {
if(query == null) {
return null;
}
Map<String, String> result = new HashMap<>();
for (String param : query.split("&")) {
param = URLDecoder.decode(param, StandardCharsets.UTF_8);
String[] entry = param.split("=");
if (entry.length > 1) {
result.put(entry[0], entry[1]);
} else {
result.put(entry[0], "");
}
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,9 @@ public abstract class AbstractStorageManager {
* @return List of the Guilds {@link Role} marked as persistent for the {@link Member}
*/
public abstract List<Role> getPersistentRoles(Member member);

public abstract String getGithubUsername(long user);
public abstract long getDiscordId(String username);

public abstract void setGithubUsername(long user, String username);
}
Loading

0 comments on commit 45dfa6c

Please sign in to comment.