-
Notifications
You must be signed in to change notification settings - Fork 2
feat: add moderation command suite (v2.0.0) #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1b3a8ba
6deb0b1
491afb7
25b68e3
684e8c6
9c641e9
fcb17dc
17b6f74
b249f5b
d9ec7c7
475d379
2b4475e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,14 +1,7 @@ | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| "$schema": "https://biomejs.dev/schemas/2.3.14/schema.json", | ||||||||||||||||||||||||||||||
| "files": { | ||||||||||||||||||||||||||||||
| "includes": [ | ||||||||||||||||||||||||||||||
| "src/**/*.js", | ||||||||||||||||||||||||||||||
| "tests/**/*.js", | ||||||||||||||||||||||||||||||
| "!node_modules/**", | ||||||||||||||||||||||||||||||
| "!coverage/**", | ||||||||||||||||||||||||||||||
| "!logs/**", | ||||||||||||||||||||||||||||||
| "!data/**" | ||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||
| "includes": ["src/**/*.js", "tests/**/*.js", "!node_modules", "!coverage", "!logs", "!data"] | ||||||||||||||||||||||||||||||
|
Comment on lines
2
to
+4
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: Biome 2.3.14 configuration schema (biome.json / biome.jsonc)Schema version to use (matches Biome 2.3.14): {
"$schema": "https://biomejs.dev/schemas/2.3.14/schema.json"
}This is shown in Biome’s “Getting started” guide (example config) for v2.3.14. [1] Alternative (recommended to avoid hardcoding the URL version): {
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json"
}Biome documents this local schema file option in the configuration reference. [2] Biome 2.3.14 release documentation (what changed)Biome publishes the 2.3.14 changelog entry here (“All versions since 2.3.14” → section 2.3.14). It lists the patch changes included in 2.3.14. [3] Sources: [1] (biomejs.dev) [2] (biomejs.dev) [3] (main--biomejs.netlify.app) Citations:
🌐 Web query:
💡 Result: In Biome,
Citations:
Remove redundant exclusion patterns from The schema version "files": {
- "includes": ["src/**/*.js", "tests/**/*.js", "!node_modules", "!coverage", "!logs", "!data"]
+ "includes": ["src/**/*.js", "tests/**/*.js"]
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| "linter": { | ||||||||||||||||||||||||||||||
| "enabled": true, | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,7 +32,31 @@ | |
| "moderation": { | ||
| "enabled": true, | ||
| "alertChannelId": "1438665401243275284", | ||
| "autoDelete": false | ||
| "autoDelete": false, | ||
| "dmNotifications": { | ||
| "warn": true, | ||
| "timeout": true, | ||
| "kick": true, | ||
| "ban": true | ||
| }, | ||
|
Comment on lines
+36
to
+41
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The 🐛 Proposed fix "dmNotifications": {
"warn": true,
"timeout": true,
"kick": true,
- "ban": true
+ "ban": true,
+ "softban": true
},🤖 Prompt for AI Agents |
||
| "escalation": { | ||
| "enabled": false, | ||
| "thresholds": [ | ||
| { "warns": 3, "withinDays": 7, "action": "timeout", "duration": "1h" }, | ||
| { "warns": 5, "withinDays": 30, "action": "ban" } | ||
| ] | ||
| }, | ||
| "logging": { | ||
| "channels": { | ||
| "default": null, | ||
| "warns": null, | ||
| "bans": null, | ||
| "kicks": null, | ||
| "timeouts": null, | ||
| "purges": null, | ||
| "locks": null | ||
| } | ||
| } | ||
| }, | ||
| "logging": { | ||
| "level": "info", | ||
|
|
@@ -44,7 +68,22 @@ | |
| "usePermissions": true, | ||
| "allowedCommands": { | ||
| "ping": "everyone", | ||
| "config": "admin" | ||
| "config": "admin", | ||
| "warn": "admin", | ||
| "kick": "admin", | ||
| "timeout": "admin", | ||
| "untimeout": "admin", | ||
| "ban": "admin", | ||
| "tempban": "admin", | ||
| "unban": "admin", | ||
| "softban": "admin", | ||
| "purge": "admin", | ||
| "case": "admin", | ||
| "history": "admin", | ||
| "lock": "admin", | ||
| "unlock": "admin", | ||
| "slowmode": "admin", | ||
| "modlog": "admin" | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| /** | ||
| * Ban Command | ||
| * Bans a user from the server and records a moderation case. | ||
| */ | ||
|
|
||
| import { SlashCommandBuilder } from 'discord.js'; | ||
| import { info, error as logError } from '../logger.js'; | ||
| import { getConfig } from '../modules/config.js'; | ||
| import { | ||
| checkHierarchy, | ||
| createCase, | ||
| sendDmNotification, | ||
| sendModLogEmbed, | ||
| shouldSendDm, | ||
| } from '../modules/moderation.js'; | ||
|
|
||
| export const data = new SlashCommandBuilder() | ||
| .setName('ban') | ||
| .setDescription('Ban a user from the server') | ||
| .addUserOption((opt) => opt.setName('user').setDescription('Target user').setRequired(true)) | ||
| .addStringOption((opt) => | ||
| opt.setName('reason').setDescription('Reason for ban').setRequired(false), | ||
| ) | ||
| .addIntegerOption((opt) => | ||
| opt | ||
| .setName('delete_messages') | ||
| .setDescription('Days of messages to delete (0-7)') | ||
| .setMinValue(0) | ||
| .setMaxValue(7) | ||
| .setRequired(false), | ||
| ); | ||
|
|
||
| export const adminOnly = true; | ||
|
|
||
| /** | ||
| * Execute the ban command | ||
| * @param {import('discord.js').ChatInputCommandInteraction} interaction | ||
| */ | ||
| export async function execute(interaction) { | ||
| try { | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| await interaction.deferReply({ ephemeral: true }); | ||
|
|
||
| const config = getConfig(); | ||
| const user = interaction.options.getUser('user'); | ||
| const reason = interaction.options.getString('reason'); | ||
| const deleteMessageDays = interaction.options.getInteger('delete_messages') || 0; | ||
|
|
||
| let member = null; | ||
| try { | ||
| member = await interaction.guild.members.fetch(user.id); | ||
| } catch { | ||
| // User not in guild — skip hierarchy check | ||
| } | ||
|
|
||
| if (member) { | ||
| const hierarchyError = checkHierarchy( | ||
| interaction.member, | ||
| member, | ||
| interaction.guild.members.me, | ||
| ); | ||
| if (hierarchyError) { | ||
| return await interaction.editReply(hierarchyError); | ||
| } | ||
|
|
||
| if (shouldSendDm(config, 'ban')) { | ||
| await sendDmNotification(member, 'ban', reason, interaction.guild.name); | ||
| } | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| await interaction.guild.members.ban(user.id, { | ||
| deleteMessageSeconds: deleteMessageDays * 86400, | ||
| reason: reason || undefined, | ||
| }); | ||
|
|
||
| const caseData = await createCase(interaction.guild.id, { | ||
| action: 'ban', | ||
| targetId: user.id, | ||
| targetTag: user.tag, | ||
| moderatorId: interaction.user.id, | ||
| moderatorTag: interaction.user.tag, | ||
| reason, | ||
| }); | ||
|
|
||
| await sendModLogEmbed(interaction.client, config, caseData); | ||
|
|
||
| info('User banned', { target: user.tag, moderator: interaction.user.tag }); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Structured log missing For log-filtering parity with other commands (e.g., purge includes ♻️ Suggested fix- info('User banned', { target: user.tag, moderator: interaction.user.tag });
+ info('User banned', { guildId: interaction.guild.id, target: user.tag, moderator: interaction.user.tag });🤖 Prompt for AI Agents |
||
| await interaction.editReply( | ||
| `✅ **${user.tag}** has been banned. (Case #${caseData.case_number})`, | ||
| ); | ||
| } catch (err) { | ||
| logError('Command error', { error: err.message, command: 'ban' }); | ||
| await interaction | ||
| .editReply('❌ An error occurred. Please try again or contact an administrator.') | ||
| .catch(() => {}); | ||
| } | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.