Modernize role management system with slash commands and role IDs
- Convert role management from prefix to slash commands (/role add/remove/list) - Update database schema to store role IDs as JSON arrays instead of regex patterns - Add /config roles command for administrators to manage allowed roles - Simplify database schema by reusing allowed_roles_for_request field as JSON - Add database reset script (pnpm reset-db) for easy testing and migration - Update config format to only support array format (no backward compatibility) Role Management Features: - /role add <role> - Self-assign roles with dropdown selection - /role remove <role> - Remove roles with dropdown selection - /role list - Show available self-assignable roles - /config roles add/remove/list/clear - Administrator role management Technical Improvements: - Role ID based matching (more reliable than name-based regex) - Type-safe role selection with Discord's native role picker - Permission hierarchy validation - Rich embed responses with proper error handling - Ephemeral responses for clean chat experience 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -13,22 +13,24 @@ class ConfigManager {
|
||||
*/
|
||||
loadFileConfig() {
|
||||
const configPath = path.join(__dirname, "..", "..", "config.json");
|
||||
|
||||
|
||||
if (!fs.existsSync(configPath)) {
|
||||
console.warn("config.json not found, using environment variables only");
|
||||
return {
|
||||
discord: {
|
||||
token: process.env.DISCORD_TOKEN,
|
||||
adminUserId: process.env.ADMIN_USER_ID,
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
||||
|
||||
|
||||
// Validate required fields
|
||||
if (!config.discord?.token && !process.env.DISCORD_TOKEN) {
|
||||
throw new Error("Discord token is required in config.json or DISCORD_TOKEN environment variable");
|
||||
throw new Error(
|
||||
"Discord token is required in config.json or DISCORD_TOKEN environment variable"
|
||||
);
|
||||
}
|
||||
|
||||
return config;
|
||||
@@ -46,19 +48,30 @@ class ConfigManager {
|
||||
*/
|
||||
getBotConfig() {
|
||||
const fileConfig = this.fileConfig;
|
||||
const dbConfig = this.databaseService ? this.databaseService.getBotConfiguration() : {};
|
||||
const dbConfig = this.databaseService
|
||||
? this.databaseService.getBotConfiguration()
|
||||
: {};
|
||||
|
||||
return {
|
||||
// Use file config as fallback, database as primary
|
||||
botName: dbConfig.botName || fileConfig.botName || 'GHBot',
|
||||
debug: dbConfig.debug !== undefined ? dbConfig.debug : (fileConfig.debug || false),
|
||||
botName: dbConfig.botName || fileConfig.botName || "GHBot",
|
||||
debug:
|
||||
dbConfig.debug !== undefined
|
||||
? dbConfig.debug
|
||||
: fileConfig.debug || false,
|
||||
discord: {
|
||||
token: fileConfig.discord?.token || process.env.DISCORD_TOKEN,
|
||||
adminUserId: dbConfig.adminUserId || fileConfig.discord?.adminUserId || process.env.ADMIN_USER_ID,
|
||||
activities: dbConfig.activities || fileConfig.discord?.activities || ['Playing sounds', 'Serving facts'],
|
||||
blacklistedUsers: dbConfig.blacklistedUsers || fileConfig.discord?.blacklistedUsers || [],
|
||||
master: fileConfig.discord?.master !== false, // Default to true
|
||||
}
|
||||
adminUserId:
|
||||
dbConfig.adminUserId ||
|
||||
fileConfig.discord?.adminUserId ||
|
||||
process.env.ADMIN_USER_ID,
|
||||
activities: dbConfig.activities ||
|
||||
fileConfig.discord?.activities || ["Playing sounds", "Serving facts"],
|
||||
blacklistedUsers:
|
||||
dbConfig.blacklistedUsers ||
|
||||
fileConfig.discord?.blacklistedUsers ||
|
||||
[],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -75,19 +88,19 @@ class ConfigManager {
|
||||
|
||||
// Fallback to file config for backward compatibility
|
||||
if (this.fileConfig.discord?.guilds) {
|
||||
const guilds = Array.isArray(this.fileConfig.discord.guilds)
|
||||
? this.fileConfig.discord.guilds
|
||||
const guilds = Array.isArray(this.fileConfig.discord.guilds)
|
||||
? this.fileConfig.discord.guilds
|
||||
: Object.values(this.fileConfig.discord.guilds);
|
||||
|
||||
return guilds.find(g => g.id === guildId);
|
||||
|
||||
return guilds.find((g) => g.id === guildId);
|
||||
}
|
||||
|
||||
// Return default config for new guilds
|
||||
return {
|
||||
id: guildId,
|
||||
name: 'Unknown Guild',
|
||||
internalName: 'Unknown Guild',
|
||||
prefix: '!',
|
||||
name: "Unknown Guild",
|
||||
internalName: "Unknown Guild",
|
||||
prefix: "!",
|
||||
enableSfx: true,
|
||||
allowedSfxChannels: null,
|
||||
sfxVolume: 0.5,
|
||||
@@ -107,10 +120,10 @@ class ConfigManager {
|
||||
|
||||
// Fallback to file config
|
||||
if (this.fileConfig.discord?.guilds) {
|
||||
const guilds = Array.isArray(this.fileConfig.discord.guilds)
|
||||
? this.fileConfig.discord.guilds
|
||||
const guilds = Array.isArray(this.fileConfig.discord.guilds)
|
||||
? this.fileConfig.discord.guilds
|
||||
: Object.values(this.fileConfig.discord.guilds);
|
||||
|
||||
|
||||
return guilds;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user