Merge pull request #7 from Fretuks/make-admin-commands-configurable
Add guild-configurable moderation permissions
This commit is contained in:
@@ -70,3 +70,23 @@ Im going to make a To-do List for the features i want to implement for my Bot.
|
|||||||
2. **Monitoring**
|
2. **Monitoring**
|
||||||
- [ ] Add logging to track errors and usage statistics.
|
- [ ] Add logging to track errors and usage statistics.
|
||||||
- [ ] Implement uptime monitoring to ensure the bot stays online.
|
- [ ] Implement uptime monitoring to ensure the bot stays online.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Server-Specific Permission Configuration**
|
||||||
|
Moderation commands support per-server permission overrides stored in MongoDB. Each guild can define which users or roles are allowed to run specific commands, plus optional admin overrides that apply to all moderation commands. This is intended for future web-based configuration.
|
||||||
|
|
||||||
|
Example document stored in the `discord.guild_permissions` collection:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"guildId": "1234567890",
|
||||||
|
"adminUserIds": ["1111111111"],
|
||||||
|
"adminRoleIds": ["2222222222"],
|
||||||
|
"commandPermissions": {
|
||||||
|
"kick": {
|
||||||
|
"allowedUserIds": ["3333333333"],
|
||||||
|
"allowedRoleIds": ["4444444444"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const { SlashCommandBuilder, PermissionFlagsBits } = require("discord.js");
|
const { SlashCommandBuilder, PermissionFlagsBits } = require("discord.js");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
permissionGroup: 'moderation',
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
.setName("kick")
|
.setName("kick")
|
||||||
.setDescription("Kick misbehaving people")
|
.setDescription("Kick misbehaving people")
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const { SlashCommandBuilder, PermissionFlagsBits } = require("discord.js");
|
const { SlashCommandBuilder, PermissionFlagsBits } = require("discord.js");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
permissionGroup: 'moderation',
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
.setName("mute")
|
.setName("mute")
|
||||||
.setDescription("Temporarily mute a member with a timeout.")
|
.setDescription("Temporarily mute a member with a timeout.")
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const { connectToDatabase } = require('../../db.js');
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mod: true,
|
mod: true,
|
||||||
|
permissionGroup: 'moderation',
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
.setName("temp-ban")
|
.setName("temp-ban")
|
||||||
.setDescription("Temporarily ban a member.")
|
.setDescription("Temporarily ban a member.")
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const { Events, MessageFlags } = require('discord.js');
|
const { Events, MessageFlags } = require('discord.js');
|
||||||
|
const { isCommandAllowed } = require('../services/permissions');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: Events.InteractionCreate,
|
name: Events.InteractionCreate,
|
||||||
@@ -13,6 +14,24 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (command.permissionGroup) {
|
||||||
|
const allowed = await isCommandAllowed({
|
||||||
|
guildId: interaction.guildId,
|
||||||
|
userId: interaction.user.id,
|
||||||
|
member: interaction.member,
|
||||||
|
commandName: interaction.commandName,
|
||||||
|
permissionGroup: command.permissionGroup,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
await interaction.reply({
|
||||||
|
content: 'You do not have permission to use this command.',
|
||||||
|
flags: MessageFlags.Ephemeral,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await command.execute(interaction);
|
await command.execute(interaction);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@@ -23,4 +42,4 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
const { connectToDatabase } = require('../db');
|
||||||
|
|
||||||
|
const DEFAULT_GUILD_PERMISSIONS = {
|
||||||
|
adminRoleIds: [],
|
||||||
|
adminUserIds: [],
|
||||||
|
commandPermissions: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizePermissionConfig = (config = {}) => ({
|
||||||
|
...DEFAULT_GUILD_PERMISSIONS,
|
||||||
|
...config,
|
||||||
|
adminRoleIds: Array.isArray(config.adminRoleIds) ? config.adminRoleIds : [],
|
||||||
|
adminUserIds: Array.isArray(config.adminUserIds) ? config.adminUserIds : [],
|
||||||
|
commandPermissions: config.commandPermissions ?? {},
|
||||||
|
});
|
||||||
|
|
||||||
|
const memberHasRole = (member, roleIds) =>
|
||||||
|
roleIds.some((roleId) => member.roles?.cache?.has(roleId));
|
||||||
|
|
||||||
|
const getGuildPermissions = async (guildId) => {
|
||||||
|
const dbClient = await connectToDatabase();
|
||||||
|
const db = dbClient.db('discord');
|
||||||
|
const collection = db.collection('guild_permissions');
|
||||||
|
const config = await collection.findOne({ guildId });
|
||||||
|
|
||||||
|
return normalizePermissionConfig(config);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isCommandAllowed = async ({
|
||||||
|
guildId,
|
||||||
|
userId,
|
||||||
|
member,
|
||||||
|
commandName,
|
||||||
|
permissionGroup,
|
||||||
|
}) => {
|
||||||
|
if (!guildId) return true;
|
||||||
|
|
||||||
|
const permissions = await getGuildPermissions(guildId);
|
||||||
|
const isAdmin =
|
||||||
|
permissions.adminUserIds.includes(userId) ||
|
||||||
|
(member && memberHasRole(member, permissions.adminRoleIds));
|
||||||
|
|
||||||
|
if (permissionGroup && isAdmin) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const commandPermissions = permissions.commandPermissions?.[commandName];
|
||||||
|
if (!commandPermissions) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const allowedUserIds = Array.isArray(commandPermissions.allowedUserIds)
|
||||||
|
? commandPermissions.allowedUserIds
|
||||||
|
: [];
|
||||||
|
const allowedRoleIds = Array.isArray(commandPermissions.allowedRoleIds)
|
||||||
|
? commandPermissions.allowedRoleIds
|
||||||
|
: [];
|
||||||
|
|
||||||
|
if (allowedUserIds.length === 0 && allowedRoleIds.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowedUserIds.includes(userId)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return member ? memberHasRole(member, allowedRoleIds) : false;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getGuildPermissions,
|
||||||
|
isCommandAllowed,
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user