Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3ab9d9e
Audit rework (#472)
Taz03 Aug 3, 2022
d58506f
Updated map of VC activities (#473)
Korwai Aug 5, 2022
e7e98f0
Update stale action v3 -> v4 (#477)
Zabuzard Aug 5, 2022
6eb914c
Made active_question post more robust against hicups (#476)
Zabuzard Aug 13, 2022
ed8accc
Bump flyway-core from 8.0.0 to 9.0.4 (#475)
dependabot[bot] Aug 13, 2022
d21ae6f
Update dependabot.yml (#496)
Zabuzard Aug 14, 2022
64a32bd
Bump org.sonarqube from 3.3 to 3.4.0.2513 (#498)
dependabot[bot] Aug 14, 2022
e34f456
Bump sqlite-jdbc from 3.36.0.3 to 3.39.2.0 (#499)
dependabot[bot] Aug 14, 2022
2a07284
Bump junit-jupiter-params from 5.8.1 to 5.9.0 (#500)
dependabot[bot] Aug 14, 2022
e8d7d71
Bump log4j-slf4j18-impl from 2.16.0 to 2.18.0 (#502)
dependabot[bot] Aug 14, 2022
d86fc3b
Bump ascii-table from 1.2.0 to 1.3.0 (#503)
dependabot[bot] Aug 14, 2022
f47892f
Bump caffeine from 3.0.4 to 3.1.1 (#504)
dependabot[bot] Aug 14, 2022
782c655
Bump com.google.cloud.tools.jib from 3.1.4 to 3.2.1 (#505)
dependabot[bot] Aug 14, 2022
29749b9
Bump flyway-core from 9.0.4 to 9.1.3 (#507)
dependabot[bot] Aug 14, 2022
fa0d983
Bump junit-jupiter-engine from 5.8.1 to 5.9.0 (#501)
dependabot[bot] Aug 14, 2022
b7cf966
Bump com.diffplug.spotless from 6.0.0 to 6.9.1 (#506)
dependabot[bot] Aug 14, 2022
5658412
Bump mockito-core from 4.0.0 to 4.7.0 (#510)
dependabot[bot] Aug 14, 2022
5e71489
Bump jooq from 3.15.3 to 3.17.2 (#508)
dependabot[bot] Aug 14, 2022
f2f2ef5
Bump junit-jupiter-api from 5.8.1 to 5.9.0 (#509)
dependabot[bot] Aug 14, 2022
1edd585
Bump log4j-core from 2.16.0 to 2.18.0 (#511)
dependabot[bot] Aug 14, 2022
8a16edc
fixed unknown class referenced (#514)
Taz03 Aug 14, 2022
e579de6
Adding uncaught exception handling (#494)
Zabuzard Aug 15, 2022
7130b76
Added help thread activity detection (#492)
Zabuzard Aug 19, 2022
617eb81
Gist auto filesharing in help threads (#491)
SquidXTV Aug 19, 2022
09d914d
Auto-prune of full helper roles (#495)
Zabuzard Aug 20, 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
6 changes: 3 additions & 3 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ updates:
- package-ecosystem: "gradle"
directory: "/"
schedule:
interval: "monthly"
interval: "daily"
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-patch", "version-update:semver-minor"]
open-pull-requests-limit: 10
update-types: ["version-update:semver-patch"]
open-pull-requests-limit: 10
2 changes: 1 addition & 1 deletion .github/workflows/stale.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
pull-requests: write

steps:
- uses: actions/stale@v3
- uses: actions/stale@v4
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label, comment or add the valid label or this will be closed in 5 days.'
Expand Down
22 changes: 11 additions & 11 deletions application/build.gradle
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
buildscript {
dependencies {
classpath 'org.xerial:sqlite-jdbc:3.36.0.3'
classpath 'org.xerial:sqlite-jdbc:3.39.2.0'
}
}

plugins {
id 'application'
id 'com.google.cloud.tools.jib' version '3.1.4'
id 'com.google.cloud.tools.jib' version '3.2.1'
id 'com.github.johnrengelman.shadow' version '7.1.0'
id 'database-settings'
}
Expand Down Expand Up @@ -45,10 +45,10 @@ dependencies {

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

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

implementation 'org.jooq:jooq:3.15.3'
implementation 'org.jooq:jooq:3.17.2'

implementation 'io.mikael:urlbuilder:2.0.9'

Expand All @@ -61,14 +61,14 @@ 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.2.0'
implementation 'com.github.freva:ascii-table:1.3.0'

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

testImplementation 'org.mockito:mockito-core:4.0.0'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
testImplementation 'org.mockito:mockito-core:4.7.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'
}

application {
Expand Down
1 change: 1 addition & 0 deletions application/config.json.template
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"token": "<put_your_token_here>",
"gistApiKey": "<your_gist_personal_access_token>",
"databasePath": "local-database.db",
"projectWebsite": "https://github.com/Together-Java/TJ-Bot",
"discordGuildInvite": "https://discord.com/invite/XXFUXzK",
Expand Down
35 changes: 23 additions & 12 deletions application/src/main/java/org/togetherjava/tjbot/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.requests.GatewayIntent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.togetherjava.tjbot.commands.Features;
import org.togetherjava.tjbot.commands.system.BotCore;
import org.togetherjava.tjbot.config.Config;
import org.togetherjava.tjbot.db.Database;
import org.togetherjava.tjbot.commands.SlashCommandAdapter;

import javax.security.auth.login.LoginException;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -19,10 +24,8 @@
/**
* Main class of the application. Use {@link #main(String[])} to start an instance of it.
* <p>
* New commands can be created by implementing
* {@link net.dv8tion.jda.api.events.interaction.SlashCommandInteractionEvent} or extending
* {@link org.togetherjava.tjbot.commands.SlashCommandAdapter}. They can then be registered in
* {@link Features}.
* New commands can be created by implementing {@link SlashCommandInteractionEvent} or extending
* {@link SlashCommandAdapter}. They can then be registered in {@link Features}.
*/
public enum Application {
;
Expand Down Expand Up @@ -53,11 +56,10 @@ public static void main(final String[] args) {
return;
}

try {
runBot(config);
} catch (Exception t) {
logger.error("Unknown error", t);
}
Thread.setDefaultUncaughtExceptionHandler(Application::onUncaughtException);
Runtime.getRuntime().addShutdownHook(new Thread(Application::onShutdown));

runBot(config);
}

/**
Expand All @@ -80,11 +82,15 @@ public static void runBot(Config config) {
JDA jda = JDABuilder.createDefault(config.getToken())
.enableIntents(GatewayIntent.GUILD_MEMBERS)
.build();
jda.addEventListener(new BotCore(jda, database, config));

BotCore core = new BotCore(jda, database, config);
jda.addEventListener(core);
jda.awaitReady();
logger.info("Bot is ready");

Runtime.getRuntime().addShutdownHook(new Thread(Application::onShutdown));
// 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 (InterruptedException e) {
Expand All @@ -106,4 +112,9 @@ private static void onShutdown() {
logger.info("Bot has been stopped");
}

private static void onUncaughtException(@NotNull Thread failingThread,
@NotNull Throwable failure) {
logger.error("Unknown error in thread {}.", failingThread.getName(), failure);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@

import net.dv8tion.jda.api.JDA;
import org.jetbrains.annotations.NotNull;
import org.togetherjava.tjbot.commands.basic.PingCommand;
import org.togetherjava.tjbot.commands.basic.RoleSelectCommand;
import org.togetherjava.tjbot.commands.basic.SuggestionsUpDownVoter;
import org.togetherjava.tjbot.commands.basic.VcActivityCommand;
import org.togetherjava.tjbot.commands.basic.*;
import org.togetherjava.tjbot.commands.filesharing.FileSharingMessageListener;
import org.togetherjava.tjbot.commands.help.*;
import org.togetherjava.tjbot.commands.mathcommands.TeXCommand;
import org.togetherjava.tjbot.commands.mathcommands.wolframalpha.WolframAlphaCommand;
Expand Down Expand Up @@ -75,12 +73,16 @@ public enum Features {
features.add(new RemindRoutine(database));
features.add(new ScamHistoryPurgeRoutine(scamHistoryStore));
features.add(new BotMessageCleanup(config));
features.add(new HelpThreadActivityUpdater(helpSystemHelper));
features
.add(new AutoPruneHelperRoutine(config, helpSystemHelper, modAuditLogWriter, database));

// Message receivers
features.add(new TopHelpersMessageListener(database, config));
features.add(new SuggestionsUpDownVoter(config));
features.add(new ScamBlocker(actionsStore, scamHistoryStore, config));
features.add(new ImplicitAskListener(config, helpSystemHelper));
features.add(new FileSharingMessageListener(config));

// Event receivers
features.add(new RejoinModerationRoleListener(actionsStore, config));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,34 +50,60 @@ public final class VcActivityCommand extends SlashCommandAdapter {
private static final long MAX_AGE_DAYS_LIMIT = 7;
private static final long MAX_USES_LIMIT = 100;

public static final String POKER_NAME = "Poker";
public static final String BETRAYAL_IO_NAME = "Betrayal.io";
public static final String FISHINGTON_IO_NAME = "Fishington.io";
public static final String SPELLCAST_NAME = "Spellcast";
public static final String DOODLECREW_NAME = "Doodlecrew";
public static final String WORDSNACK_NAME = "Wordsnack";
public static final String LETTERTILE_NAME = "Lettertile";


private static final List<Command.Choice> VC_APPLICATIONS =
List.of(new Command.Choice(POKER_NAME, POKER_NAME),
new Command.Choice(BETRAYAL_IO_NAME, BETRAYAL_IO_NAME),
new Command.Choice(FISHINGTON_IO_NAME, FISHINGTON_IO_NAME),
new Command.Choice(SPELLCAST_NAME, SPELLCAST_NAME),
new Command.Choice(DOODLECREW_NAME, DOODLECREW_NAME),
new Command.Choice(WORDSNACK_NAME, WORDSNACK_NAME),
new Command.Choice(LETTERTILE_NAME, LETTERTILE_NAME));
public static final String WATCH_TOGETHER_NAME = "Watch Together";
public static final String POKER_NAME = "Poker Night";
public static final String CHESS_NAME = "Chess In The Park";
public static final String SPELLCAST_NAME = "SpellCast";
public static final String DOODLE_CREW_NAME = "Doodle Crew";
public static final String WORD_SNACKS_NAME = "Word Snacks";
public static final String LETTER_LEAGUE_NAME = "Letter League";
public static final String CHECKERS_NAME = "Checkers In The Park";
public static final String BLAZING_EIGHTS_NAME = "Blazing 8s";
public static final String SKETCH_HEADS_NAME = "Sketch Heads";
public static final String PUTT_PARTY_NAME = "Putt Party";
public static final String LAND_IO_NAME = "Land-io";
public static final String BOBBLE_LEAGUE_NAME = "Bobble League";
public static final String ASK_AWAY_NAME = "Ask Away";
public static final String KNOW_WHAT_I_MEME_NAME = "Know What I Meme";

private static final List<Command.Choice> VC_APPLICATIONS = List.of(
new Command.Choice(WATCH_TOGETHER_NAME, WATCH_TOGETHER_NAME),
new Command.Choice(POKER_NAME, POKER_NAME), new Command.Choice(CHESS_NAME, CHESS_NAME),
new Command.Choice(SPELLCAST_NAME, SPELLCAST_NAME),
new Command.Choice(DOODLE_CREW_NAME, DOODLE_CREW_NAME),
new Command.Choice(WORD_SNACKS_NAME, WORD_SNACKS_NAME),
new Command.Choice(LETTER_LEAGUE_NAME, LETTER_LEAGUE_NAME),
new Command.Choice(CHECKERS_NAME, CHECKERS_NAME),
new Command.Choice(BLAZING_EIGHTS_NAME, BLAZING_EIGHTS_NAME),
new Command.Choice(SKETCH_HEADS_NAME, SKETCH_HEADS_NAME),
new Command.Choice(PUTT_PARTY_NAME, PUTT_PARTY_NAME),
new Command.Choice(LAND_IO_NAME, LAND_IO_NAME),
new Command.Choice(BOBBLE_LEAGUE_NAME, BOBBLE_LEAGUE_NAME),
new Command.Choice(ASK_AWAY_NAME, ASK_AWAY_NAME),
new Command.Choice(KNOW_WHAT_I_MEME_NAME, KNOW_WHAT_I_MEME_NAME));

/**
* List comes from <a href="https://github.com/DV8FromTheWorld/JDA/pull/1628">the "Implement
* invite targets" PR on JDA</a>. There is no official list from Discord themselves, so this is
* our best bet.
* List comes from
* <a href="https://gist.github.com/GeneralSadaf/42d91a2b6a93a7db7a39208f2d8b53ad">this public
* list obtained by GeneralSadaf.</a>. There is no official list from Discord themselves, so
* this is our best bet.
*/
private static final Map<String, String> VC_APPLICATION_TO_ID =
Map.of(POKER_NAME, "755827207812677713", BETRAYAL_IO_NAME, "773336526917861400",
FISHINGTON_IO_NAME, "814288819477020702", SPELLCAST_NAME, "852509694341283871",
DOODLECREW_NAME, "878067389634314250", WORDSNACK_NAME, "879863976006127627",
LETTERTILE_NAME, "879863686565621790");
Map.ofEntries(Map.entry(WATCH_TOGETHER_NAME, "880218394199220334"),
Map.entry(POKER_NAME, "755827207812677713"),
Map.entry(CHESS_NAME, "832012586023256104"),
Map.entry(SPELLCAST_NAME, "852509694341283871"),
Map.entry(DOODLE_CREW_NAME, "878067389634314250"),
Map.entry(WORD_SNACKS_NAME, "879863976006127627"),
Map.entry(LETTER_LEAGUE_NAME, "879863686565621790"),
Map.entry(CHECKERS_NAME, "832013003968348200"),
Map.entry(BLAZING_EIGHTS_NAME, "832025144389533716"),
Map.entry(SKETCH_HEADS_NAME, "902271654783242291"),
Map.entry(PUTT_PARTY_NAME, "945737671223947305"),
Map.entry(LAND_IO_NAME, "903769130790969345"),
Map.entry(BOBBLE_LEAGUE_NAME, "947957217959759964"),
Map.entry(ASK_AWAY_NAME, "976052223358406656"),
Map.entry(KNOW_WHAT_I_MEME_NAME, "950505761862189096"));

private static final List<OptionData> inviteOptions = List.of(new OptionData(OptionType.INTEGER,
MAX_USES_OPTION,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.togetherjava.tjbot.commands.componentids;

import org.jetbrains.annotations.NotNull;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;

import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
import net.dv8tion.jda.api.entities.Emoji;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.components.ComponentInteraction;
import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
import net.dv8tion.jda.api.interactions.components.buttons.Button;

import org.togetherjava.tjbot.commands.SlashCommand;

import org.jetbrains.annotations.NotNull;

/**
Expand All @@ -11,9 +16,8 @@
* Component IDs are used during button or selection menu events. They can carry arbitrary data and
* are persisted by the system.
* <p>
* See
* {@link org.togetherjava.tjbot.commands.SlashCommand#onSlashCommand(SlashCommandInteractionEvent)}
* for more context on how to use this.
* See {@link SlashCommand#onSlashCommand(SlashCommandInteractionEvent)} for more context on how to
* use this.
* <p>
* The interface {@link ComponentIdParser} is the counterpart to this, offering parsing back the
* payload from the ID.
Expand All @@ -25,8 +29,8 @@ public interface ComponentIdGenerator {
* interactions, such as button or selection menus.
* <p>
* See {@link ComponentInteraction#getComponentId()} and
* {@link net.dv8tion.jda.api.interactions.components.Button#of(ButtonStyle, String, Emoji)} for
* details on where the generated ID can be used.
* {@link Button#of(ButtonStyle, String, Emoji)} for details on where the generated ID can be
* used.
*
* @param componentId the component ID payload to persist and generate a valid ID for
* @param lifespan the lifespan of the generated and persisted component ID
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

import net.dv8tion.jda.api.entities.Emoji;
import net.dv8tion.jda.api.interactions.components.ComponentInteraction;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
import net.dv8tion.jda.api.interactions.components.buttons.Button;

import org.jetbrains.annotations.NotNull;

import java.util.Optional;
Expand All @@ -26,8 +30,8 @@ public interface ComponentIdParser {
* interactions, such as button or selection menus.
* <p>
* See {@link ComponentInteraction#getComponentId()} and
* {@link net.dv8tion.jda.api.interactions.components.Button#of(ButtonStyle, String, Emoji)} for
* details on where the ID was originally transported with.
* {@link Button#of(ButtonStyle, String, Emoji)} for details on where the ID was originally
* transported with.
*
* @param uuid the UUID to parse which represents the component ID
* @return the payload associated to the given UUID, if empty the component ID either never
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.togetherjava.tjbot.commands.SlashCommand;
import org.jetbrains.annotations.NotNull;
import org.jooq.Result;
import org.slf4j.Logger;
Expand All @@ -26,8 +28,7 @@
/**
* Thread-safe storage for component IDs. Can put, persist and get back component IDs based on
* UUIDs. Component IDs are used for button and selection menu commands, see
* {@link org.togetherjava.tjbot.commands.SlashCommand#onSlashCommand(SlashCommandInteractionEvent)}
* for details.
* {@link SlashCommand#onSlashCommand(SlashCommandInteractionEvent)} for details.
* <p>
* Use {@link #putOrThrow(UUID, ComponentId, Lifespan)} to put and persist a component ID; and
* {@link #get(UUID)} to get it back. Component IDs are persisted during application runs and can
Expand Down Expand Up @@ -113,8 +114,16 @@ public ComponentIdStore(@NotNull Database database, long evictEveryInitialDelay,
.maximumSize(CACHE_SIZE)
.expireAfterAccess(EVICT_CACHE_OLDER_THAN, TimeUnit.of(EVICT_CACHE_OLDER_THAN_UNIT))
.build();
evictionTask = evictionService.scheduleWithFixedDelay(this::evictDatabase,
evictEveryInitialDelay, evictEveryDelay, TimeUnit.of(evictEveryUnit));

Runnable evictCommand = () -> {
try {
evictDatabase();
} catch (Exception e) {
logger.error("Unknown error while evicting the component ID store database.", e);
}
};
evictionTask = evictionService.scheduleWithFixedDelay(evictCommand, evictEveryInitialDelay,
evictEveryDelay, TimeUnit.of(evictEveryUnit));

logDebugSizeStatistics();
}
Expand Down
Loading