Add auto-role and role replacement rules
Adds slash commands, services, migrations, and member event handlers for configuring per-guild auto-roles and role replacement rules. Also updates shared error/permission messaging to support the new role management flows.
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import { getDatabase } from '../database/database.js';
|
||||
import logger from '../utilities/logger.js';
|
||||
|
||||
/**
|
||||
* @typedef {object} AutoRoleRow
|
||||
* @property {string} guild_id
|
||||
* @property {string} role_id
|
||||
* @property {string} updated_by
|
||||
* @property {string} updated_at
|
||||
*/
|
||||
|
||||
/**
|
||||
* Data-access helpers for per-guild auto-roles assigned on join.
|
||||
*/
|
||||
export const autoRoleService = {
|
||||
/**
|
||||
* @param {string} guildId
|
||||
* @returns {AutoRoleRow | undefined}
|
||||
*/
|
||||
get(guildId) {
|
||||
return getDatabase()
|
||||
.prepare('SELECT * FROM guild_autoroles WHERE guild_id = ?')
|
||||
.get(guildId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates or updates the auto-role for a guild.
|
||||
* @param {{ guildId: string, roleId: string, updatedBy: string }} input
|
||||
* @returns {AutoRoleRow}
|
||||
*/
|
||||
set(input) {
|
||||
const db = getDatabase();
|
||||
|
||||
try {
|
||||
db.prepare(
|
||||
`INSERT INTO guild_autoroles (guild_id, role_id, updated_by, updated_at)
|
||||
VALUES (@guildId, @roleId, @updatedBy, datetime('now'))
|
||||
ON CONFLICT(guild_id) DO UPDATE SET
|
||||
role_id = excluded.role_id,
|
||||
updated_by = excluded.updated_by,
|
||||
updated_at = datetime('now')`,
|
||||
).run({
|
||||
guildId: input.guildId,
|
||||
roleId: input.roleId,
|
||||
updatedBy: input.updatedBy,
|
||||
});
|
||||
|
||||
const row = this.get(input.guildId);
|
||||
if (!row) {
|
||||
throw new Error('Failed to load auto-role after save.');
|
||||
}
|
||||
|
||||
logger.info('Auto-role configured', {
|
||||
guildId: row.guild_id,
|
||||
roleId: row.role_id,
|
||||
updatedBy: row.updated_by,
|
||||
});
|
||||
|
||||
return row;
|
||||
} catch (error) {
|
||||
logger.error('Database error while saving auto-role', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears the auto-role for a guild.
|
||||
* @param {string} guildId
|
||||
* @returns {AutoRoleRow | undefined} The previous row, if any
|
||||
*/
|
||||
clear(guildId) {
|
||||
const existing = this.get(guildId);
|
||||
if (!existing) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
getDatabase()
|
||||
.prepare('DELETE FROM guild_autoroles WHERE guild_id = ?')
|
||||
.run(guildId);
|
||||
|
||||
logger.info('Auto-role cleared', {
|
||||
guildId,
|
||||
roleId: existing.role_id,
|
||||
});
|
||||
|
||||
return existing;
|
||||
} catch (error) {
|
||||
logger.error('Database error while clearing auto-role', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default autoRoleService;
|
||||
Reference in New Issue
Block a user