feat: add discord analytics
Node.js CI / Lint and Test (push) Failing after 29s

This commit is contained in:
2025-10-09 19:56:00 -07:00
parent 91d7a1ef28
commit e38d1057f4
16 changed files with 55 additions and 41 deletions
-34
View File
@@ -1,34 +0,0 @@
name: Code Analysis
on:
push:
branches:
- main
jobs:
sonar:
name: SonarQube
steps:
- name: Checkout Source Files
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: SonarCube Scan
uses: SonarSource/sonarqube-scan-action@v4
timeout-minutes: 10
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: "https://quality.nhcarrigan.com"
with:
args: >
-Dsonar.sources=.
-Dsonar.projectKey=mod-bot
- name: SonarQube Quality Gate check
uses: sonarsource/sonarqube-quality-gate-action@v1
with:
pollingTimeoutSec: 600
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: "https://quality.nhcarrigan.com"
+2 -1
View File
@@ -34,7 +34,8 @@
"typescript": "5.4.5"
},
"dependencies": {
"@nhcarrigan/logger": "1.0.0",
"@nhcarrigan/discord-analytics": "0.0.6",
"@nhcarrigan/logger": "1.1.1",
"@octokit/rest": "20.1.1",
"@prisma/client": "5.13.0",
"diff": "8.0.2",
+20 -5
View File
@@ -8,9 +8,12 @@ importers:
.:
dependencies:
'@nhcarrigan/discord-analytics':
specifier: 0.0.6
version: 0.0.6(@nhcarrigan/logger@1.1.1)(discord.js@14.15.2)
'@nhcarrigan/logger':
specifier: 1.0.0
version: 1.0.0
specifier: 1.1.1
version: 1.1.1
'@octokit/rest':
specifier: 20.1.1
version: 20.1.1
@@ -167,14 +170,20 @@ packages:
'@humanwhocodes/object-schema@2.0.3':
resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
'@nhcarrigan/discord-analytics@0.0.6':
resolution: {integrity: sha512-Mci/zSY2nE24BM2cZx5EiYqwpRTTCBznFfs2BphejzDAaWPt1P12V5ln7OSUbFLGhvTD/Qwi0za3yPv6shQLoA==}
peerDependencies:
'@nhcarrigan/logger': '>=1.1.0-hotfix'
discord.js: ^14.0.0
'@nhcarrigan/eslint-config@3.2.0':
resolution: {integrity: sha512-DlB0T5o0BcRlqJ9ktejs+jtufrxwyWnzWXsCM8GrWMph+19dCBOf8w3aDQpuIu9hM16d79mDTvSwwDx5ekOVvw==}
engines: {node: '20', pnpm: '8'}
peerDependencies:
eslint: '>=8'
'@nhcarrigan/logger@1.0.0':
resolution: {integrity: sha512-2e19Bie+ZKb6yKPKjhawqsENkhHatYkvBAmFZx9eToOXdOca+CYi51tldRMtejg6e0+4hOOf2bo5zdBQKmH0dw==}
'@nhcarrigan/logger@1.1.1':
resolution: {integrity: sha512-P6OEQFHDtf6psybYGljuCxkSW6DLQCsx1aZZ3w4YKBXHBFjDbhuvpM9K1kPhVN48hakitx2WPLEoIFr6YZELYw==}
'@nhcarrigan/prettier-config@3.2.0':
resolution: {integrity: sha512-AZOzwDTZfRiEinjUmqRj4gqZLYpLANhN1iMIsESxeuln+/BjGI06pINQsePIZ/I2HoPd+HGjNqu0S+Os9nHzuw==}
@@ -2393,6 +2402,12 @@ snapshots:
'@humanwhocodes/object-schema@2.0.3': {}
'@nhcarrigan/discord-analytics@0.0.6(@nhcarrigan/logger@1.1.1)(discord.js@14.15.2)':
dependencies:
'@nhcarrigan/logger': 1.1.1
discord.js: 14.15.2
node-schedule: 2.1.1
'@nhcarrigan/eslint-config@3.2.0(eslint@8.57.0)(prettier@3.2.5)(typescript@5.4.5)':
dependencies:
'@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
@@ -2411,7 +2426,7 @@ snapshots:
- supports-color
- typescript
'@nhcarrigan/logger@1.0.0': {}
'@nhcarrigan/logger@1.1.1': {}
'@nhcarrigan/prettier-config@3.2.0(prettier@3.2.5)':
dependencies:
+8 -1
View File
@@ -1,3 +1,4 @@
import { DiscordAnalytics } from "@nhcarrigan/discord-analytics";
import { ExtendedClient } from "../interfaces/ExtendedClient";
import { checkEntitledGuild } from "../utils/checkEntitledGuild";
@@ -17,6 +18,7 @@ import { onThreadCreate } from "./thread/onThreadCreate";
import { onThreadDelete } from "./thread/onThreadDelete";
import { onThreadUpdate } from "./thread/onThreadUpdate";
import { onVoiceUpdate } from "./voice/onVoiceUpdate";
import { logHandler } from "../utils/logHandler.js";
/**
* Module to mount the Discord event listeners.
@@ -24,8 +26,13 @@ import { onVoiceUpdate } from "./voice/onVoiceUpdate";
* @param {ExtendedClient} bot The bot's Discord instance.
*/
export const handleEvents = (bot: ExtendedClient) => {
const analytics = new DiscordAnalytics(bot, logHandler);
/* Client Events */
bot.on("ready", async () => await onReady(bot));
bot.once("ready", async () => {
await onReady(bot);
analytics.startCron();
});
bot.on("disconnect", () => onDisconnect());
/* Message Events */
+2
View File
@@ -5,6 +5,7 @@ import { getModActionFromAuditLog } from "../../modules/events/getModActionFromA
import { addCase } from "../../utils/addCase";
import { errorHandler } from "../../utils/errorHandler";
import { sendLogMessage } from "../../utils/sendLogMessage";
import { logHandler } from "../../utils/logHandler.js";
/**
* Handles properly logging a manual mod action based on audit logs.
@@ -72,6 +73,7 @@ export const onAuditLogEntry = async (
false,
caseNum
);
await logHandler.metric("audit_log_action", 1, { modAction, guildId: guild.id, targetId: target.id });
} catch (err) {
await errorHandler(bot, "on audit log entry", err);
}
+2
View File
@@ -9,6 +9,7 @@ import { handleMassBanModal } from "../../modules/modals/handleMassBanModal";
import { handleMessageReportModal } from "../../modules/modals/handleMessageReportModal";
import { checkEntitledGuild } from "../../utils/checkEntitledGuild";
import { errorHandler } from "../../utils/errorHandler";
import { logHandler } from "../../utils/logHandler.js";
/**
* Handles interactions.
@@ -60,6 +61,7 @@ export const onInteraction = async (
await handleMessageReportModal(bot, interaction);
}
}
await logHandler.metric("interaction_create", 1, { userId: interaction.user.id, guildId: interaction.guild.id, command: interaction.isCommand() ? interaction.commandName : interaction.customId });
} catch (err) {
const id = await errorHandler(bot, "on interaction", err);
if (!interaction.isAutocomplete()) {
+2
View File
@@ -3,6 +3,7 @@ import { GuildMember } from "discord.js";
import { ExtendedClient } from "../../interfaces/ExtendedClient";
import { getConfig } from "../../modules/data/getConfig";
import { errorHandler } from "../../utils/errorHandler";
import { logHandler } from "../../utils/logHandler.js";
/**
* Sends a log message to the configured log channel when a member
@@ -36,6 +37,7 @@ export const onMemberAdd = async (bot: ExtendedClient, member: GuildMember) => {
await channel.send({
content: `${user.tag} (${user.id}) has joined the server. Total Members: ${guild.memberCount}`
});
await logHandler.metric("member_join", 1, { userId: user.id, guildId: guild.id });
} catch (err) {
await errorHandler(bot, "on member add", err);
}
+2
View File
@@ -3,6 +3,7 @@ import { GuildMember, PartialGuildMember } from "discord.js";
import { ExtendedClient } from "../../interfaces/ExtendedClient";
import { getConfig } from "../../modules/data/getConfig";
import { errorHandler } from "../../utils/errorHandler";
import { logHandler } from "../../utils/logHandler.js";
/**
* Sends a log message to the configured log channel when a member
@@ -54,6 +55,7 @@ export const onMemberRemove = async (
await channel.send({
content: `${user.tag} (${user.id}) has left the server (joined at ${joinStamp}). Total Members: ${guild.memberCount}`
});
await logHandler.metric("member_leave", 1, { userId: user.id, guildId: guild.id });
} catch (err) {
await errorHandler(bot, "on member remove", err);
}
+2
View File
@@ -3,6 +3,7 @@ import { GuildMember, PartialGuildMember } from "discord.js";
import { ExtendedClient } from "../../interfaces/ExtendedClient";
import { getConfig } from "../../modules/data/getConfig";
import { errorHandler } from "../../utils/errorHandler";
import { logHandler } from "../../utils/logHandler.js";
/**
* Sends a log message to the configured log channel when a member's
@@ -74,6 +75,7 @@ export const onMemberUpdate = async (
)}`
});
}
await logHandler.metric("member_update", 1, { userId: user.id, guildId: guild.id });
} catch (err) {
await errorHandler(bot, "on member update", err);
}
+3
View File
@@ -9,6 +9,7 @@ import { errorHandler } from "../../utils/errorHandler";
import { sendLogMessage } from "../../utils/sendLogMessage";
import { sendModDm } from "../../utils/sendModDm";
import { triggerModRequest } from "../../utils/triggerModRequest";
import { logHandler } from "../../utils/logHandler.js";
const linkRegex = /https?:\/\/([a-zA-Z0-9_.-]{2,256}\.\w{2,24}\b)/g;
@@ -67,6 +68,7 @@ export const onMessage = async (bot: ExtendedClient, message: Message) => {
duration: calculateMuteDuration(24, "hours"),
pruneDays: 0
});
await logHandler.metric("automod_trigger", 1, { userId: author.id, guildId: guild.id });
return;
}
}
@@ -135,6 +137,7 @@ export const onMessage = async (bot: ExtendedClient, message: Message) => {
for (const record of levelRoles) {
await member.roles.add(record.roleId).catch(() => null);
}
await logHandler.metric("message_create", 1, { userId: author.id, guildId: guild.id });
} catch (err) {
await errorHandler(bot, "on message", err);
}
+2
View File
@@ -5,6 +5,7 @@ import { ExtendedClient } from "../../interfaces/ExtendedClient";
import { getConfig } from "../../modules/data/getConfig";
import { customSubstring } from "../../utils/customSubstring";
import { errorHandler } from "../../utils/errorHandler";
import { logHandler } from "../../utils/logHandler.js";
/**
* Handles a message delete event.
@@ -67,6 +68,7 @@ export const onMessageDelete = async (
parse: []
}
});
await logHandler.metric("message_delete", 1, { userId: author?.id ?? "unknown", guildId: guild.id });
} catch (err) {
await errorHandler(bot, "on message delete", err);
}
+2
View File
@@ -5,6 +5,7 @@ import { getConfig } from "../../modules/data/getConfig";
import { customSubstring } from "../../utils/customSubstring";
import { errorHandler } from "../../utils/errorHandler";
import { generateDiff } from "../../modules/events/generateDiff";
import { logHandler } from "../../utils/logHandler.js";
/**
* Handles a message edit event.
@@ -58,6 +59,7 @@ export const onMessageEdit = async (
}>:\`\`\`diff\n${customSubstring(diffContent, 4000)}\n\`\`\``,
allowedMentions: { parse: [] }
});
await logHandler.metric("message_edit", 1, { userId: author?.id ?? "unknown", guildId: guild.id });
} catch (err) {
await errorHandler(bot, "on message edit", err);
}
+2
View File
@@ -3,6 +3,7 @@ import { ThreadChannel } from "discord.js";
import { ExtendedClient } from "../../interfaces/ExtendedClient";
import { getConfig } from "../../modules/data/getConfig";
import { errorHandler } from "../../utils/errorHandler";
import { logHandler } from "../../utils/logHandler.js";
/**
* Handles the creation of a new thread.
@@ -36,6 +37,7 @@ export const onThreadCreate = async (
await channel.send({
content: `${thread.name} has been created in <#${thread.parentId}>`
});
await logHandler.metric("thread_create", 1, { userId: thread.ownerId ?? "unknown", guildId: thread.guild.id });
} catch (err) {
await errorHandler(bot, "on thread create", err);
}
+2
View File
@@ -3,6 +3,7 @@ import { ThreadChannel } from "discord.js";
import { ExtendedClient } from "../../interfaces/ExtendedClient";
import { getConfig } from "../../modules/data/getConfig";
import { errorHandler } from "../../utils/errorHandler";
import { logHandler } from "../../utils/logHandler.js";
/**
* Handles the deletion of a thread.
@@ -32,6 +33,7 @@ export const onThreadDelete = async (
await channel.send({
content: `${thread.name} has been deleted from <#${thread.parentId}>`
});
await logHandler.metric("thread_delete", 1, { userId: thread.ownerId ?? "unknown", guildId: thread.guild.id });
} catch (err) {
await errorHandler(bot, "on thread create", err);
}
+2
View File
@@ -3,6 +3,7 @@ import { ThreadChannel } from "discord.js";
import { ExtendedClient } from "../../interfaces/ExtendedClient";
import { getConfig } from "../../modules/data/getConfig";
import { errorHandler } from "../../utils/errorHandler";
import { logHandler } from "../../utils/logHandler.js";
/**
* Handles a thread update.
@@ -48,6 +49,7 @@ export const onThreadUpdate = async (
content: `${oldThread.name} has been renamed to ${newThread.name} in <#${newThread.parentId}>`
});
}
await logHandler.metric("thread_update", 1, { userId: newThread.ownerId ?? "unknown", guildId: newThread.guild.id });
} catch (err) {
await errorHandler(bot, "on thread update", err);
}
+2
View File
@@ -3,6 +3,7 @@ import { VoiceState } from "discord.js";
import { ExtendedClient } from "../../interfaces/ExtendedClient";
import { getConfig } from "../../modules/data/getConfig";
import { errorHandler } from "../../utils/errorHandler";
import { logHandler } from "../../utils/logHandler.js";
/**
* Handles voice state updates.
@@ -76,6 +77,7 @@ export const onVoiceUpdate = async (
content: `${newVoice.member.user.tag} (${newVoice.member.id}) has been deafened.`
});
}
await logHandler.metric("voice_update", 1, { userId: newVoice.member?.id ?? "unknown", guildId: newVoice.guild.id });
} catch (err) {
await errorHandler(bot, "on voice update", err);
}