Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a8dd02d
Bump mockito-core from 4.7.0 to 4.8.0 (#564)
dependabot[bot] Sep 8, 2022
ac84310
Bump flyway-core from 9.2.0 to 9.3.0 (#568)
dependabot[bot] Sep 9, 2022
259521a
Bump log4j-core from 2.18.0 to 2.19.0 (#576)
dependabot[bot] Sep 19, 2022
3dd130b
Bump ascii-table from 1.6.0 to 1.7.0 (#575)
dependabot[bot] Sep 19, 2022
652cde7
Bump com.diffplug.spotless from 6.10.0 to 6.11.0 (#572)
dependabot[bot] Sep 20, 2022
051f803
Website based on Hyperspace (#552)
Zabuzard Sep 21, 2022
ca5df05
Website SEO (#577)
Zabuzard Sep 21, 2022
e4ba8ee
Google ownership verification (#578)
Zabuzard Sep 21, 2022
6c438a2
Rephrased auto-close message for UX (#581)
Zabuzard Sep 23, 2022
b8cbbcf
Changing auto archiving from 24 to 12h (#583)
Zabuzard Sep 23, 2022
7132ab6
Add comma for clarity inside TOS.md (#584)
Moki00 Sep 25, 2022
e4bb920
fixed bot positing advice on closed uncategorized help threads (#580)
Taz03 Sep 27, 2022
a5df7c5
Bump flyway-core from 9.3.0 to 9.4.0 (#590)
dependabot[bot] Sep 30, 2022
0d315c8
Command rework, attempt number 2 (#558)
Tais993 Sep 30, 2022
beba4b3
Added missing package-infos
Zabuzard Sep 30, 2022
72d4b3c
fixed context commands not working (#596)
Tais993 Sep 30, 2022
1b2de09
Bugfix command completion not working (#597)
Tais993 Oct 2, 2022
8fb5ebf
Bump ascii-table from 1.7.0 to 1.8.0 (#600)
dependabot[bot] Oct 3, 2022
c54df4a
Grouped help thread commands (#574)
Taz03 Oct 4, 2022
e7c216a
Fixed components not working (#601)
Tais993 Oct 4, 2022
802097f
Migrate to JDA alpha 20 (#587)
Zabuzard Oct 4, 2022
6d9f6c0
Ensure config is present and not null (#592)
Zabuzard Oct 4, 2022
8f60483
Forward logs to Discord (#579)
Zabuzard Oct 4, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion TOS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ By inviting **TJ-Bot** and using its features (accessible via [Discord](https://

You acknowledge that you must only invite the **bot** to a Server owned by **Together Java**, and only with their explicit approval.

Further, you have the priviledge to build and host the **bot** based on the [source](https://github.com/Together-Java/TJ-Bot) yourself. You may use such a self-hosted **bot** freely on any Discord Server (Server) you share with it, you can invite it to any Server that you have "Manage Server" rights for and you acknowledge that this priviledge might get revoked for you, if you're subject of breaking the terms and/or policy of this **bot**, or the Terms of Service, Privacy Policy and/or Community Guidelines of Discord Inc.
Further, you have the priviledge to build and host the **bot** based on the [source](https://github.com/Together-Java/TJ-Bot) yourself. You may use such a self-hosted **bot** freely on any Discord Server (Server) you share with it, you can invite it to any Server that you have "Manage Server" rights for, and you acknowledge that this priviledge might get revoked for you, if you're subject of breaking the terms and/or policy of this **bot**, or the Terms of Service, Privacy Policy and/or Community Guidelines of Discord Inc.

Through Inviting, the **bot** may collect specific data as described in its [Privacy Policy](#your-privacy).
The intended usage of this data is for core functionalities of the **bot** such as command handling.
Expand Down
10 changes: 6 additions & 4 deletions application/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,13 @@ dependencies {
implementation project(':database')
implementation project(':utils')

implementation 'net.dv8tion:JDA:5.0.0-alpha.9'
implementation 'net.dv8tion:JDA:5.0.0-alpha.20'

implementation 'org.apache.logging.log4j:log4j-core:2.18.0'
implementation 'org.apache.logging.log4j:log4j-core:2.19.0'
runtimeOnly 'org.apache.logging.log4j:log4j-slf4j18-impl:2.18.0'

implementation 'club.minnced:discord-webhooks:0.8.2'

implementation 'org.jooq:jooq:3.17.2'

implementation 'io.mikael:urlbuilder:2.0.9'
Expand All @@ -63,11 +65,11 @@ dependencies {
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.13.0'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0'

implementation 'com.github.freva:ascii-table:1.6.0'
implementation 'com.github.freva:ascii-table:1.8.0'

implementation 'com.github.ben-manes.caffeine:caffeine:3.1.1'

testImplementation 'org.mockito:mockito-core:4.7.0'
testImplementation 'org.mockito:mockito-core:4.8.0'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
Expand Down
4 changes: 3 additions & 1 deletion application/config.json.template
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,7 @@
"wsc",
"wsf",
"wsh"
]
],
"logInfoChannelWebhook": "<put_your_webhook_here>",
"logErrorChannelWebhook": "<put_your_webhook_here>"
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.exceptions.InvalidTokenException;
import net.dv8tion.jda.api.requests.GatewayIntent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -11,8 +12,9 @@
import org.togetherjava.tjbot.commands.system.BotCore;
import org.togetherjava.tjbot.config.Config;
import org.togetherjava.tjbot.db.Database;
import org.togetherjava.tjbot.logging.LogMarkers;
import org.togetherjava.tjbot.logging.discord.DiscordLogging;

import javax.security.auth.login.LoginException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
Expand Down Expand Up @@ -57,6 +59,7 @@ public static void main(final String[] args) {

Thread.setDefaultUncaughtExceptionHandler(Application::onUncaughtException);
Runtime.getRuntime().addShutdownHook(new Thread(Application::onShutdown));
DiscordLogging.startDiscordLogging(config);

runBot(config);
}
Expand All @@ -79,19 +82,20 @@ public static void runBot(Config config) {
Database database = new Database("jdbc:sqlite:" + databasePath.toAbsolutePath());

JDA jda = JDABuilder.createDefault(config.getToken())
.enableIntents(GatewayIntent.GUILD_MEMBERS)
.enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.MESSAGE_CONTENT)
.build();

jda.awaitReady();

BotCore core = new BotCore(jda, database, config);
CommandReloading.reloadCommands(jda, core);
core.scheduleRoutines(jda);

jda.addEventListener(core);
jda.awaitReady();

// We fire the event manually, since the core might be added too late to receive the
// actual event fired from JDA
core.onReady(jda);
logger.info("Bot is ready");
} catch (LoginException e) {
logger.error("Failed to login", e);
} catch (InvalidTokenException e) {
logger.error(LogMarkers.SENSITIVE, "Failed to login", e);
} catch (InterruptedException e) {
logger.error("Interrupted while waiting for setup to complete", e);
Thread.currentThread().interrupt();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package org.togetherjava.tjbot;

import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction;
import org.jetbrains.annotations.Contract;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.togetherjava.tjbot.commands.BotCommand;
import org.togetherjava.tjbot.commands.CommandVisibility;
import org.togetherjava.tjbot.commands.system.CommandProvider;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;

/**
* Offers utility functions for reloading all commands.
*/
public class CommandReloading {
private static final Logger logger = LoggerFactory.getLogger(CommandReloading.class);

/**
* According to <a href=
* "https://discord.com/developers/docs/interactions/application-commands#registering-a-command">Discord
* docs</a>, there can be a maximum of 110 commands, 100 slash, and 5 context each.
* <p>
* Because this bot most of the time operates in only 1 server, chances of exceeding this limit
* is low.
*/
public static final int MAX_COMMAND_COUNT = 110;

private CommandReloading() {
throw new UnsupportedOperationException("Utility class");
}

/**
* Reloads all commands based on the given {@link CommandProvider}.
*
* @param jda the JDA to update commands on
* @param commandProvider the {@link CommandProvider} to grab commands from
*/
public static void reloadCommands(final JDA jda, final CommandProvider commandProvider) {
logger.info("Reloading commands...");
List<CommandListUpdateAction> actions =
Collections.synchronizedList(new ArrayList<>(MAX_COMMAND_COUNT));

// Reload global commands
actions.add(updateCommandsIf(command -> CommandVisibility.GLOBAL == command.getVisibility(),
getGlobalUpdateAction(jda), commandProvider));

// Reload guild commands (potentially many guilds)
// NOTE Storing the guild actions in a list is potentially dangerous since the
// bot might theoretically be part of so many guilds that it exceeds the max size of
// list. However, correctly reducing RestActions in a stream is not trivial.
getGuildUpdateActions(jda)
.map(updateAction -> updateCommandsIf(
command -> CommandVisibility.GUILD == command.getVisibility(), updateAction,
commandProvider))
.forEach(actions::add);
logger.debug("Reloading commands over {} action-upstreams", actions.size());

// Send message when all are done
RestAction.allOf(actions).queue(a -> logger.debug("Commands successfully reloaded!"));
}

/**
* Updates all commands given by the command provider which pass the given filter by pushing
* through the given action upstream.
*
* @param commandFilter filter that matches commands that should be uploaded
* @param updateAction the upstream to update commands
* @return the given upstream for chaining
*/
@Contract("_, _, _ -> param2")
private static CommandListUpdateAction updateCommandsIf(
final Predicate<? super BotCommand> commandFilter,
final CommandListUpdateAction updateAction, final CommandProvider commandProvider) {
commandProvider.getInteractors()
.stream()
.filter(BotCommand.class::isInstance)
.map(BotCommand.class::cast)
.filter(commandFilter)
.map(BotCommand::getData)
.forEach(updateAction::addCommands);

return updateAction;
}

private static CommandListUpdateAction getGlobalUpdateAction(final JDA jda) {
return jda.updateCommands();
}

private static Stream<CommandListUpdateAction> getGuildUpdateActions(final JDA jda) {
return jda.getGuildCache().stream().map(Guild::updateCommands);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package org.togetherjava.tjbot.commands;

import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.events.interaction.component.SelectMenuInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.Command;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;

import java.util.List;

/**
* Represents a Discord command.
* <p>
* All commands have to implement this interface. For convenience, there is a
* {@link BotCommandAdapter} available that implemented most methods already. A new command can then
* be registered by adding it to {@link Features}.
* <p>
* Commands can either be visible globally in Discord or just to specific guilds. Some
* configurations can be made via {@link CommandData}, which is then to be returned by
* {@link #getData()} where the system will then pick it up from.
* <p>
* After registration, the system will notify a command whenever one of its corresponding command
* method, buttons ({@link #onButtonClick(ButtonInteractionEvent, List)}) or menus
* ({@link #onSelectionMenu(SelectMenuInteractionEvent, List)}) have been triggered.
* <p>
* Some example commands are available in {@link org.togetherjava.tjbot.commands.basic}.
*/
public interface BotCommand extends UserInteractor {

/**
* Gets the type of this command.
* <p>
* After registration of the command, the type must not change anymore.
*
* @return the type of the command
*/
Command.Type getType();

/**
* Gets the visibility of this command.
* <p>
* After registration of the command, the visibility must not change anymore.
*
* @return the visibility of the command
*/
CommandVisibility getVisibility();

/**
* Gets the command data belonging to this command.
* <p>
* See {@link net.dv8tion.jda.api.interactions.commands.build.Commands Commands} for details on
* how to create and configure instances of it.
* <p>
* This method may be called multiple times, implementations must not create new data each time
* but instead configure it once beforehand. The core system will automatically call this method
* to register the command to Discord.
*
* @return the command data of this command
*/
CommandData getData();
}
Loading