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
8cdc646
build(deps): bump com.openai:openai-java from 4.18.0 to 4.19.0 (#1412)
dependabot[bot] Feb 10, 2026
7f63240
build(deps): bump com.openai:openai-java from 4.19.0 to 4.20.0 (#1413)
dependabot[bot] Feb 11, 2026
e6a2657
fix: Handle UNKNOWN_MESSAGE exception in SuggestionsUpDownVoter (#1415)
Bryce72 Feb 17, 2026
bf23930
build(deps): bump org.jetbrains:annotations from 26.0.1 to 26.1.0 (#1…
dependabot[bot] Feb 19, 2026
3292631
build(deps): bump com.openai:openai-java from 4.20.0 to 4.22.0 (#1418)
dependabot[bot] Feb 20, 2026
1b44779
build(deps): bump com.openai:openai-java from 4.22.0 to 4.23.0 (#1421)
dependabot[bot] Feb 24, 2026
1070f23
fix: allow forwarded messages with media in media-only channels (#1419)
VlaM5 Feb 26, 2026
e7c8c3f
build(deps): bump org.mockito:mockito-core from 5.21.0 to 5.22.0 (#1424)
dependabot[bot] Mar 2, 2026
4367c2d
build(deps): bump com.diffplug.spotless from 8.2.0 to 8.3.0 (#1426)
dependabot[bot] Mar 3, 2026
6ebffd9
Add utilities to detect and replace broken links. (#1366)
barsh404error Mar 3, 2026
9015870
Added "Mark Active" button to help-thread "inactivity-closed" message…
SleepyStack Mar 3, 2026
0af5cd0
build(deps): bump com.openai:openai-java from 4.23.0 to 4.24.1 (#1429)
dependabot[bot] Mar 5, 2026
9383845
build(deps): bump gradle-wrapper from 9.2.0 to 9.4.0 (#1428)
dependabot[bot] Mar 5, 2026
692453c
removed slash command educator (#1427)
Zabuzard Mar 5, 2026
afd9424
build(deps): bump com.openai:openai-java from 4.24.1 to 4.26.0 (#1430)
dependabot[bot] Mar 6, 2026
f27f66a
Reduced log-level of RSS-Feed Circuit Breaker (#1431)
Zabuzard Mar 6, 2026
c686756
build(deps): bump org.flywaydb:flyway-core from 12.0.0 to 12.1.0 (#1432)
dependabot[bot] Mar 10, 2026
bb7164a
Basic Bot Analytics System (#1425)
firasrg Mar 11, 2026
7990089
build(deps): bump org.mockito:mockito-core from 5.22.0 to 5.23.0 (#1436)
dependabot[bot] Mar 12, 2026
5d819b3
Fixed Slashcommand-Metrics missing subcommands (#1434)
Zabuzard Mar 12, 2026
ddabd5e
Fixed /github-search command failing in some cases (#1435)
Zabuzard Mar 12, 2026
e64fd0b
Added metric events (#1433)
Zabuzard Mar 12, 2026
70b5297
docs: add pipeline badge to README.md
surajkumar Mar 12, 2026
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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=Together-Java_TJ-Bot&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=Together-Java_TJ-Bot)
[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=Together-Java_TJ-Bot&metric=security_rating)](https://sonarcloud.io/dashboard?id=Together-Java_TJ-Bot)

[![Pipeline](https://woodpecker.togetherjava.org/api/badges/1/status.svg)](https://woodpecker.togetherjava.org/repos/1)


TJ-Bot is a Discord Bot used on the [Together Java](https://discord.com/invite/XXFUXzK) server. It is maintained by the community, anyone can contribute!

![bot says hello](https://i.imgur.com/FE1MJTV.png)
Expand Down
4 changes: 2 additions & 2 deletions application/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ shadowJar {

dependencies {
implementation 'com.google.code.findbugs:jsr305:3.0.2'
implementation 'org.jetbrains:annotations:26.0.1'
implementation 'org.jetbrains:annotations:26.1.0'

implementation project(':database')
implementation project(':utils')
Expand Down Expand Up @@ -80,7 +80,7 @@ dependencies {
implementation 'org.apache.commons:commons-text:1.15.0'
implementation 'com.apptasticsoftware:rssreader:3.12.0'

testImplementation 'org.mockito:mockito-core:5.21.0'
testImplementation 'org.mockito:mockito-core:5.23.0'
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion"
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.togetherjava.tjbot.db.Database;
import org.togetherjava.tjbot.features.Features;
import org.togetherjava.tjbot.features.SlashCommandAdapter;
import org.togetherjava.tjbot.features.analytics.Metrics;
import org.togetherjava.tjbot.features.system.BotCore;
import org.togetherjava.tjbot.logging.LogMarkers;
import org.togetherjava.tjbot.logging.discord.DiscordLogging;
Expand Down Expand Up @@ -82,13 +83,15 @@ public static void runBot(Config config) {
}
Database database = new Database("jdbc:sqlite:" + databasePath.toAbsolutePath());

Metrics metrics = new Metrics(database);

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

jda.awaitReady();

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
import org.togetherjava.tjbot.config.FeatureBlacklist;
import org.togetherjava.tjbot.config.FeatureBlacklistConfig;
import org.togetherjava.tjbot.db.Database;
import org.togetherjava.tjbot.features.analytics.Metrics;
import org.togetherjava.tjbot.features.basic.MemberCountDisplayRoutine;
import org.togetherjava.tjbot.features.basic.PingCommand;
import org.togetherjava.tjbot.features.basic.QuoteBoardForwarder;
import org.togetherjava.tjbot.features.basic.RoleSelectCommand;
import org.togetherjava.tjbot.features.basic.SlashCommandEducator;
import org.togetherjava.tjbot.features.basic.SuggestionsUpDownVoter;
import org.togetherjava.tjbot.features.bookmarks.BookmarksCommand;
import org.togetherjava.tjbot.features.bookmarks.BookmarksSystem;
Expand Down Expand Up @@ -91,7 +91,7 @@
* it with the system.
* <p>
* To add a new slash command, extend the commands returned by
* {@link #createFeatures(JDA, Database, Config)}.
* {@link #createFeatures(JDA, Database, Config, Metrics)}.
*/
public class Features {
private Features() {
Expand All @@ -107,9 +107,12 @@ private Features() {
* @param jda the JDA instance commands will be registered at
* @param database the database of the application, which features can use to persist data
* @param config the configuration features should use
* @param metrics the metrics service for tracking analytics
* @return a collection of all features
*/
public static Collection<Feature> createFeatures(JDA jda, Database database, Config config) {
@SuppressWarnings("unused")
public static Collection<Feature> createFeatures(JDA jda, Database database, Config config,
Metrics metrics) {
FeatureBlacklistConfig blacklistConfig = config.getFeatureBlacklistConfig();
JShellEval jshellEval = new JShellEval(config.getJshell(), config.getGitHubApiKey());

Expand All @@ -118,16 +121,18 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
ModerationActionsStore actionsStore = new ModerationActionsStore(database);
ModAuditLogWriter modAuditLogWriter = new ModAuditLogWriter(config);
ScamHistoryStore scamHistoryStore = new ScamHistoryStore(database);
GitHubReference githubReference = new GitHubReference(config);
GitHubReference githubReference = new GitHubReference(config, metrics);
CodeMessageHandler codeMessageHandler =
new CodeMessageHandler(blacklistConfig.special(), jshellEval);
ChatGptService chatGptService = new ChatGptService(config);
new CodeMessageHandler(blacklistConfig.special(), jshellEval, metrics);
ChatGptService chatGptService = new ChatGptService(config, metrics);
HelpSystemHelper helpSystemHelper = new HelpSystemHelper(config, database, chatGptService);
HelpThreadLifecycleListener helpThreadLifecycleListener =
new HelpThreadLifecycleListener(helpSystemHelper, database);
HelpThreadCreatedListener helpThreadCreatedListener =
new HelpThreadCreatedListener(helpSystemHelper, metrics);
TopHelpersService topHelpersService = new TopHelpersService(database);
TopHelpersAssignmentRoutine topHelpersAssignmentRoutine =
new TopHelpersAssignmentRoutine(config, topHelpersService);
new TopHelpersAssignmentRoutine(config, topHelpersService, metrics);

// NOTE The system can add special system relevant commands also by itself,
// hence this list may not necessarily represent the full list of all commands actually
Expand All @@ -142,38 +147,37 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
features.add(new ScamHistoryPurgeRoutine(scamHistoryStore));
features.add(new HelpThreadMetadataPurger(database));
features.add(new HelpThreadActivityUpdater(helpSystemHelper));
features
.add(new AutoPruneHelperRoutine(config, helpSystemHelper, modAuditLogWriter, database));
features.add(new AutoPruneHelperRoutine(config, helpSystemHelper, modAuditLogWriter,
database, metrics));
features.add(new HelpThreadAutoArchiver(helpSystemHelper));
features.add(new LeftoverBookmarksCleanupRoutine(bookmarksSystem));
features.add(new MarkHelpThreadCloseInDBRoutine(database, helpThreadLifecycleListener));
features.add(new MemberCountDisplayRoutine(config));
features.add(new RSSHandlerRoutine(config, database));
features.add(new RSSHandlerRoutine(config, database, metrics));
features.add(topHelpersAssignmentRoutine);

// Message receivers
features.add(new TopHelpersMessageListener(database, config));
features.add(new SuggestionsUpDownVoter(config));
features.add(new ScamBlocker(actionsStore, scamHistoryStore, config));
features.add(new MediaOnlyChannelListener(config));
features.add(new FileSharingMessageListener(config));
features.add(new BlacklistedAttachmentListener(config, modAuditLogWriter));
features.add(new SuggestionsUpDownVoter(config, metrics));
features.add(new ScamBlocker(actionsStore, scamHistoryStore, config, metrics));
features.add(new MediaOnlyChannelListener(config, metrics));
features.add(new FileSharingMessageListener(config, metrics));
features.add(new BlacklistedAttachmentListener(config, modAuditLogWriter, metrics));
features.add(githubReference);
features.add(codeMessageHandler);
features.add(new CodeMessageAutoDetection(config, codeMessageHandler));
features.add(new CodeMessageManualDetection(codeMessageHandler));
features.add(new SlashCommandEducator());
features.add(new PinnedNotificationRemover(config));
features.add(new QuoteBoardForwarder(config));

// Voice receivers
features.add(new DynamicVoiceChat(config));
features.add(new DynamicVoiceChat(config, metrics));

// Event receivers
features.add(new RejoinModerationRoleListener(actionsStore, config));
features.add(new GuildLeaveCloseThreadListener(config));
features.add(new RejoinModerationRoleListener(actionsStore, config, metrics));
features.add(new GuildLeaveCloseThreadListener(config, metrics));
features.add(new LeftoverBookmarksListener(bookmarksSystem));
features.add(new HelpThreadCreatedListener(helpSystemHelper));
features.add(helpThreadCreatedListener);
features.add(new HelpThreadLifecycleListener(helpSystemHelper, database));
features.add(new ProjectsThreadCreatedListener(config));

Expand All @@ -186,7 +190,7 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
features.add(new LogLevelCommand());
features.add(new PingCommand());
features.add(new TeXCommand());
features.add(new TagCommand(tagSystem));
features.add(new TagCommand(tagSystem, metrics));
features.add(new TagManageCommand(tagSystem, modAuditLogWriter));
features.add(new TagsCommand(tagSystem));
features.add(new WarnCommand(actionsStore));
Expand All @@ -206,7 +210,7 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
features.add(new WolframAlphaCommand(config));
features.add(new GitHubCommand(githubReference));
features.add(new ModMailCommand(jda, config));
features.add(new HelpThreadCommand(config, helpSystemHelper));
features.add(new HelpThreadCommand(config, helpSystemHelper, metrics));
features.add(new ReportCommand(config));
features.add(new BookmarksCommand(bookmarksSystem));
features.add(new ChatGptCommand(chatGptService, helpSystemHelper));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.togetherjava.tjbot.features.analytics;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.togetherjava.tjbot.db.Database;
import org.togetherjava.tjbot.db.generated.tables.MetricEvents;

import java.time.Instant;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* Service for tracking and recording events for analytics purposes.
*/
public final class Metrics {
private static final Logger logger = LoggerFactory.getLogger(Metrics.class);

private final Database database;

private final ExecutorService service = Executors.newSingleThreadExecutor();

/**
* Creates a new instance.
*
* @param database the database to use for storing and retrieving analytics data
*/
public Metrics(Database database) {
this.database = database;
}

/**
* Track an event execution.
*
* @param event the event to save
*/
public void count(String event) {
logger.debug("Counting new record for event: {}", event);
Instant moment = Instant.now();
service.submit(() -> processEvent(event, moment));

}

/**
*
* @param event the event to save
* @param happenedAt the moment when the event is dispatched
*/
private void processEvent(String event, Instant happenedAt) {
database.write(context -> context.newRecord(MetricEvents.METRIC_EVENTS)
.setEvent(event)
.setHappenedAt(happenedAt)
.insert());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Analytics system for collecting and persisting bot activity metrics.
* <p>
* This package provides services and components that record events for later analysis and reporting
* across multiple feature areas.
*/
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
package org.togetherjava.tjbot.features.analytics;

import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault;

import javax.annotation.ParametersAreNonnullByDefault;

This file was deleted.

Loading
Loading