Allow setting a default display role
Same command as for threads, !role, but used outside a thread.cshd
parent
405a19b918
commit
bbca6a873f
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -12,11 +12,18 @@ Please report any bugs you encounter by [creating a GitHub issue](https://github
|
|||
* The symbols used can be changed with the `inlineSnippetStart` and `inlineSnippetEnd` options
|
||||
* This feature can be disabled by setting `allowInlineSnippets = off` in your config
|
||||
* By default, the bot will refuse to send a reply with an unknown inline snippet. To disable this behavior, set `errorOnUnknownInlineSnippet = off`.
|
||||
* Moderators can now set the role they'd like to be displayed with their replies on a per-thread basis by using `!role`
|
||||
* Moderators can now set the role they'd like to be displayed with their replies ("display role") by default and on a per-thread basis by using `!role`
|
||||
* Moderators can only choose roles they currently have
|
||||
* You can view your currently displayed role by using `!role`
|
||||
* You can set the displayed role by using `!role <role name>`, e.g. `!role Interviewer`
|
||||
* This feature can be disabled by setting `allowChangingDisplayedRole = off`
|
||||
* You can view your current display role by using `!role`
|
||||
* If you're in a modmail thread, this will show your display role for that thread
|
||||
* If you're *not* in a modmail thread, this will show your *default* display role
|
||||
* You can set the display role by using `!role <role name>`, e.g. `!role Interviewer`
|
||||
* If you're in a modmail thread, this will set your display role for that thread
|
||||
* If you're *not* in a modmail thread, this will set your *default* display role
|
||||
* You can reset the display role by using `!role reset`
|
||||
* If you're in a modmail thread, this will reset your display role for that thread to the default
|
||||
* If you're *not* in a modmail thread, this will reset your *default* display role
|
||||
* This feature can be disabled by setting `allowChangingDisplayRole = off`
|
||||
* New option: `fallbackRoleName`
|
||||
* Sets the role name to display in moderator replies if the moderator doesn't have a hoisted role
|
||||
* Unless `fallbackRoleName` is set, anonymous replies without a role will no longer display "Moderator:" at the beginning of the message
|
||||
|
|
|
@ -71,10 +71,13 @@ Delete your own previous reply sent with `!reply`.
|
|||
`<number>` is the message number shown in front of staff replies in the thread channel.
|
||||
|
||||
### `!role`
|
||||
View the role that is sent with your replies
|
||||
View your display role for the thread - the role that is shown in front of your name in your replies
|
||||
|
||||
### `!role`
|
||||
Reset your display role for the thread to the default
|
||||
|
||||
### `!role <role name>`
|
||||
Change the role that is sent with your replies to any role you currently have
|
||||
Change your display role for the thread to any role you currently have
|
||||
|
||||
### `!loglink`
|
||||
Get a link to the open Modmail thread's log.
|
||||
|
@ -129,6 +132,15 @@ Check if the specified user is blocked.
|
|||
|
||||
**Example:** `!is_blocked 106391128718245888`
|
||||
|
||||
### `!role`
|
||||
(Outside a modmail thread) View your default display role - the role that is shown in front of your name in your replies
|
||||
|
||||
### `!role`
|
||||
(Outside a modmail thread) Reset your default display role
|
||||
|
||||
### `!role <role name>`
|
||||
(Outside a modmail thread) Change your default display role to any role you currently have
|
||||
|
||||
### `!version`
|
||||
Show the Modmail bot's version.
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ If enabled, staff members can edit their own replies in modmail threads with `!e
|
|||
If enabled, snippets can be included *within* replies by wrapping the snippet's name in {{ and }}.
|
||||
E.g. `!r Hello! {{rules}}`
|
||||
|
||||
#### allowChangingDisplayedRole
|
||||
#### allowChangingDisplayRole
|
||||
**Default:** `on`
|
||||
If enabled, moderators can change the role that's shown with their replies to any role they currently have using the `!role` command.
|
||||
|
||||
|
|
|
@ -11,6 +11,13 @@ const Thread = require("./data/Thread");
|
|||
* @param {object} args
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback InboxServerCommandHandler
|
||||
* @param {Eris.Message} msg
|
||||
* @param {object} args
|
||||
* @param {Thread} [thread]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback InboxThreadCommandHandler
|
||||
* @param {Eris.Message} msg
|
||||
|
@ -30,7 +37,7 @@ const Thread = require("./data/Thread");
|
|||
* @callback AddInboxServerCommandFn
|
||||
* @param {string} trigger
|
||||
* @param {string} parameters
|
||||
* @param {CommandFn} handler
|
||||
* @param {InboxServerCommandHandler} handler
|
||||
* @param {ICommandConfig} commandConfig
|
||||
*/
|
||||
|
||||
|
|
|
@ -9,13 +9,12 @@ const attachments = require("./attachments");
|
|||
const { formatters } = require("../formatters");
|
||||
const { callAfterThreadCloseHooks } = require("../hooks/afterThreadClose");
|
||||
const snippets = require("./snippets");
|
||||
const { getModeratorThreadDisplayRoleName } = require("./moderatorRoleOverrides");
|
||||
|
||||
const ThreadMessage = require("./ThreadMessage");
|
||||
|
||||
const {THREAD_MESSAGE_TYPE, THREAD_STATUS, DISCORD_MESSAGE_ACTIVITY_TYPES} = require("./constants");
|
||||
|
||||
const ROLE_OVERRIDES_METADATA_KEY = "moderatorRoleOverrides";
|
||||
|
||||
/**
|
||||
* @property {String} id
|
||||
* @property {Number} status
|
||||
|
@ -195,7 +194,7 @@ class Thread {
|
|||
*/
|
||||
async replyToUser(moderator, text, replyAttachments = [], isAnonymous = false) {
|
||||
const moderatorName = config.useNicknames && moderator.nick ? moderator.nick : moderator.user.username;
|
||||
const roleName = this.getModeratorDisplayRoleName(moderator);
|
||||
const roleName = await getModeratorThreadDisplayRoleName(moderator, this.id);
|
||||
|
||||
if (config.allowInlineSnippets) {
|
||||
// Replace {{snippet}} with the corresponding snippet
|
||||
|
@ -838,43 +837,6 @@ class Thread {
|
|||
});
|
||||
}
|
||||
|
||||
setModeratorRoleOverride(moderatorId, roleId) {
|
||||
const moderatorRoleOverrides = this.getMetadataValue(ROLE_OVERRIDES_METADATA_KEY) || {};
|
||||
moderatorRoleOverrides[moderatorId] = roleId;
|
||||
return this.setMetadataValue(ROLE_OVERRIDES_METADATA_KEY, moderatorRoleOverrides);
|
||||
}
|
||||
|
||||
resetModeratorRoleOverride(moderatorId) {
|
||||
const moderatorRoleOverrides = this.getMetadataValue(ROLE_OVERRIDES_METADATA_KEY) || {};
|
||||
delete moderatorRoleOverrides[moderatorId];
|
||||
return this.setMetadataValue(ROLE_OVERRIDES_METADATA_KEY, moderatorRoleOverrides)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the role that is shown in the replies of the specified moderator,
|
||||
* taking role overrides into account.
|
||||
* @param {Eris.Member} moderator
|
||||
* @return {Eris.Role|undefined}
|
||||
*/
|
||||
getModeratorDisplayRole(moderator) {
|
||||
const moderatorRoleOverrides = this.getMetadataValue(ROLE_OVERRIDES_METADATA_KEY) || {};
|
||||
const overrideRoleId = moderatorRoleOverrides[moderator.id];
|
||||
const overrideRole = overrideRoleId && moderator.roles.includes(overrideRoleId) && utils.getInboxGuild().roles.get(overrideRoleId);
|
||||
const finalRole = overrideRole || utils.getMainRole(moderator);
|
||||
return finalRole;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the role NAME that is shown in the replies of the specified moderator,
|
||||
* taking role overrides into account.
|
||||
* @param {Eris.Member} moderator
|
||||
* @return {Eris.Role|undefined}
|
||||
*/
|
||||
getModeratorDisplayRoleName(moderator) {
|
||||
const displayRole = this.getModeratorDisplayRole(moderator);
|
||||
return displayRole ? displayRole.name : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {*} value
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
* @property {string} [inlineSnippetStart="{{"]
|
||||
* @property {string} [inlineSnippetEnd="}}"]
|
||||
* @property {boolean} [errorOnUnknownInlineSnippet=true]
|
||||
* @property {boolean} [allowChangingDisplayedRole=true]
|
||||
* @property {boolean} [allowChangingDisplayRole=true]
|
||||
* @property {string} [fallbackRoleName=null]
|
||||
* @property {string} [logStorage="local"]
|
||||
* @property {object} [logOptions]
|
||||
|
|
|
@ -336,7 +336,7 @@
|
|||
"default": true
|
||||
},
|
||||
|
||||
"allowChangingDisplayedRole": {
|
||||
"allowChangingDisplayRole": {
|
||||
"$ref": "#/definitions/customBoolean",
|
||||
"default": true
|
||||
},
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
exports.up = async function(knex, Promise) {
|
||||
if (! await knex.schema.hasTable("moderator_role_overrides")) {
|
||||
await knex.schema.createTable("moderator_role_overrides", table => {
|
||||
table.string("moderator_id", 20);
|
||||
table.string("thread_id", 36).nullable().defaultTo(null);
|
||||
table.string("role_id", 20);
|
||||
|
||||
table.primary(["moderator_id", "thread_id"]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.down = async function(knex, Promise) {
|
||||
if (await knex.schema.hasTable("moderator_role_overrides")) {
|
||||
await knex.schema.dropTable("moderator_role_overrides");
|
||||
}
|
||||
};
|
|
@ -0,0 +1,165 @@
|
|||
const knex = require("../knex");
|
||||
const Eris = require("eris");
|
||||
const utils = require("../utils");
|
||||
const config = require("../cfg");
|
||||
|
||||
/**
|
||||
* @param {string} moderatorId
|
||||
* @returns {Promise<string|null>}
|
||||
*/
|
||||
async function getModeratorDefaultRoleOverride(moderatorId) {
|
||||
const roleOverride = await knex("moderator_role_overrides")
|
||||
.where("moderator_id", moderatorId)
|
||||
.whereNull("thread_id")
|
||||
.first();
|
||||
|
||||
return roleOverride ? roleOverride.role_id : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} moderatorId
|
||||
* @param {string} roleId
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function setModeratorDefaultRoleOverride(moderatorId, roleId) {
|
||||
const existingGlobalOverride = await getModeratorDefaultRoleOverride(moderatorId);
|
||||
if (existingGlobalOverride) {
|
||||
await knex("moderator_role_overrides")
|
||||
.where("moderator_id", moderatorId)
|
||||
.whereNull("thread_id")
|
||||
.update({ role_id: roleId });
|
||||
} else {
|
||||
await knex("moderator_role_overrides")
|
||||
.insert({
|
||||
moderator_id: moderatorId,
|
||||
thread_id: null,
|
||||
role_id: roleId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} moderatorId
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function resetModeratorDefaultRoleOverride(moderatorId) {
|
||||
await knex("moderator_role_overrides")
|
||||
.where("moderator_id", moderatorId)
|
||||
.whereNull("thread_id")
|
||||
.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} moderatorId
|
||||
* @param {string} threadId
|
||||
* @returns {Promise<string|null>}
|
||||
*/
|
||||
async function getModeratorThreadRoleOverride(moderatorId, threadId) {
|
||||
const roleOverride = await knex("moderator_role_overrides")
|
||||
.where("moderator_id", moderatorId)
|
||||
.where("thread_id", threadId)
|
||||
.first();
|
||||
|
||||
return roleOverride ? roleOverride.role_id : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} moderatorId
|
||||
* @param {string} threadId
|
||||
* @param {string} roleId
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function setModeratorThreadRoleOverride(moderatorId, threadId, roleId) {
|
||||
const existingGlobalOverride = await getModeratorThreadRoleOverride(moderatorId, threadId);
|
||||
if (existingGlobalOverride) {
|
||||
await knex("moderator_role_overrides")
|
||||
.where("moderator_id", moderatorId)
|
||||
.where("thread_id", threadId)
|
||||
.update({ role_id: roleId });
|
||||
} else {
|
||||
await knex("moderator_role_overrides")
|
||||
.insert({
|
||||
moderator_id: moderatorId,
|
||||
thread_id: threadId,
|
||||
role_id: roleId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} moderatorId
|
||||
* @param {string} threadId
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function resetModeratorThreadRoleOverride(moderatorId, threadId) {
|
||||
await knex("moderator_role_overrides")
|
||||
.where("moderator_id", moderatorId)
|
||||
.where("thread_id", threadId)
|
||||
.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Eris.Member} moderator
|
||||
* @returns {Promise<Eris.Role|null>}
|
||||
*/
|
||||
async function getModeratorDefaultDisplayRole(moderator) {
|
||||
const globalOverrideRoleId = await getModeratorDefaultRoleOverride(moderator.id);
|
||||
if (globalOverrideRoleId && moderator.roles.includes(globalOverrideRoleId)) {
|
||||
return moderator.guild.roles.get(globalOverrideRoleId);
|
||||
}
|
||||
|
||||
return utils.getMainRole(moderator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Eris.Member} moderator
|
||||
* @returns {Promise<string|null>}
|
||||
*/
|
||||
async function getModeratorDefaultDisplayRoleName(moderator) {
|
||||
const defaultDisplayRole = await getModeratorDefaultDisplayRole(moderator);
|
||||
return defaultDisplayRole
|
||||
? defaultDisplayRole.name
|
||||
: (config.fallbackRoleName || null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Eris.Member} moderator
|
||||
* @param {string} threadId
|
||||
* @returns {Promise<Eris.Role|null>}
|
||||
*/
|
||||
async function getModeratorThreadDisplayRole(moderator, threadId) {
|
||||
const threadOverrideRoleId = await getModeratorThreadRoleOverride(moderator.id, threadId);
|
||||
if (threadOverrideRoleId && moderator.roles.includes(threadOverrideRoleId)) {
|
||||
return moderator.guild.roles.get(threadOverrideRoleId);
|
||||
}
|
||||
|
||||
return getModeratorDefaultDisplayRole(moderator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Eris.Member} moderator
|
||||
* @param {string} threadId
|
||||
* @returns {Promise<string|null>}
|
||||
*/
|
||||
async function getModeratorThreadDisplayRoleName(moderator, threadId) {
|
||||
const threadDisplayRole = await getModeratorThreadDisplayRole(moderator, threadId);
|
||||
return threadDisplayRole
|
||||
? threadDisplayRole.name
|
||||
: (config.fallbackRoleName || null);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getModeratorDefaultRoleOverride,
|
||||
setModeratorDefaultRoleOverride,
|
||||
resetModeratorDefaultRoleOverride,
|
||||
|
||||
getModeratorThreadRoleOverride,
|
||||
setModeratorThreadRoleOverride,
|
||||
resetModeratorThreadRoleOverride,
|
||||
|
||||
getModeratorDefaultDisplayRole,
|
||||
getModeratorDefaultDisplayRoleName,
|
||||
|
||||
getModeratorThreadDisplayRole,
|
||||
getModeratorThreadDisplayRoleName,
|
||||
};
|
|
@ -1,63 +1,99 @@
|
|||
const utils = require("../utils");
|
||||
const {
|
||||
setModeratorDefaultRoleOverride,
|
||||
resetModeratorDefaultRoleOverride,
|
||||
|
||||
setModeratorThreadRoleOverride,
|
||||
resetModeratorThreadRoleOverride,
|
||||
|
||||
getModeratorThreadDisplayRoleName,
|
||||
getModeratorDefaultDisplayRoleName,
|
||||
} = require("../data/moderatorRoleOverrides");
|
||||
|
||||
const ROLE_OVERRIDES_METADATA_KEY = "moderatorRoleOverrides";
|
||||
|
||||
module.exports = ({ bot, knex, config, commands }) => {
|
||||
if (! config.allowChangingDisplayedRole) {
|
||||
if (! config.allowChangingDisplayRole) {
|
||||
return;
|
||||
}
|
||||
|
||||
commands.addInboxThreadCommand("role", "[role:string$]", async (msg, args, thread) => {
|
||||
const moderatorRoleOverrides = thread.getMetadataValue(ROLE_OVERRIDES_METADATA_KEY);
|
||||
function resolveRoleInput(input) {
|
||||
if (utils.isSnowflake(input)) {
|
||||
return utils.getInboxGuild().roles.get(input);
|
||||
}
|
||||
|
||||
// Set display role
|
||||
if (args.role) {
|
||||
if (args.role === "reset") {
|
||||
await thread.resetModeratorRoleOverride(msg.member.id);
|
||||
return utils.getInboxGuild().roles.find(r => r.name.toLowerCase() === input.toLowerCase());
|
||||
}
|
||||
|
||||
const displayRole = thread.getModeratorDisplayRoleName(msg.member);
|
||||
if (displayRole) {
|
||||
thread.postSystemMessage(`Your display role has been reset. Your replies will now display the role **${displayRole}**.`);
|
||||
} else {
|
||||
thread.postSystemMessage("Your display role has been reset. Your replies will no longer display a role.");
|
||||
}
|
||||
// Get display role for a thread
|
||||
commands.addInboxThreadCommand("role", [], async (msg, args, thread) => {
|
||||
const displayRole = await getModeratorThreadDisplayRoleName(msg.member, thread.id);
|
||||
if (displayRole) {
|
||||
thread.postSystemMessage(`Your display role in this thread is currently **${displayRole}**`);
|
||||
} else {
|
||||
thread.postSystemMessage("Your replies in this thread do not currently display a role");
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
// Reset display role for a thread
|
||||
commands.addInboxThreadCommand("role reset", [], async (msg, args, thread) => {
|
||||
await resetModeratorThreadRoleOverride(msg.member.id, thread.id);
|
||||
|
||||
let role;
|
||||
if (utils.isSnowflake(args.role)) {
|
||||
if (! msg.member.roles.includes(args.role)) {
|
||||
thread.postSystemMessage("No matching role found. Make sure you have the role before trying to set it as your role.");
|
||||
return;
|
||||
}
|
||||
const displayRole = await getModeratorThreadDisplayRoleName(msg.member, thread.id);
|
||||
if (displayRole) {
|
||||
thread.postSystemMessage(`Your display role for this thread has been reset. Your replies will now display the default role **${displayRole}**.`);
|
||||
} else {
|
||||
thread.postSystemMessage("Your display role for this thread has been reset. Your replies will no longer display a role.");
|
||||
}
|
||||
}, {
|
||||
aliases: ["role_reset", "reset_role"],
|
||||
});
|
||||
|
||||
role = utils.getInboxGuild().roles.get(args.role);
|
||||
} else {
|
||||
const matchingMemberRole = utils.getInboxGuild().roles.find(r => {
|
||||
if (! msg.member.roles.includes(r.id)) return false;
|
||||
return r.name.toLowerCase() === args.role.toLowerCase();
|
||||
});
|
||||
|
||||
if (! matchingMemberRole) {
|
||||
thread.postSystemMessage("No matching role found. Make sure you have the role before trying to set it as your role.");
|
||||
return;
|
||||
}
|
||||
|
||||
role = matchingMemberRole;
|
||||
}
|
||||
|
||||
await thread.setModeratorRoleOverride(msg.member.id, role.id);
|
||||
thread.postSystemMessage(`Your display role has been set to **${role.name}**. You can reset it with \`${config.prefix}role reset\`.`);
|
||||
// Set display role for a thread
|
||||
commands.addInboxThreadCommand("role", "<role:string$>", async (msg, args, thread) => {
|
||||
const role = resolveRoleInput(args.role);
|
||||
if (! role || ! msg.member.roles.includes(role.id)) {
|
||||
thread.postSystemMessage("No matching role found. Make sure you have the role before trying to set it as your display role in this thread.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get display role
|
||||
const displayRole = thread.getModeratorDisplayRoleName(msg.member);
|
||||
await setModeratorThreadRoleOverride(msg.member.id, thread.id, role.id);
|
||||
thread.postSystemMessage(`Your display role for this thread has been set to **${role.name}**. You can reset it with \`${config.prefix}role reset\`.`);
|
||||
});
|
||||
|
||||
// Get default display role
|
||||
commands.addInboxServerCommand("role", [], async (msg, args, thread) => {
|
||||
const displayRole = await getModeratorDefaultDisplayRoleName(msg.member);
|
||||
if (displayRole) {
|
||||
thread.postSystemMessage(`Your displayed role is currently: **${displayRole}**`);
|
||||
msg.channel.createMessage(`Your default display role is currently **${displayRole}**`);
|
||||
} else {
|
||||
thread.postSystemMessage("Your replies do not currently display a role");
|
||||
msg.channel.createMessage("Your replies do not currently display a role by default");
|
||||
}
|
||||
});
|
||||
|
||||
// Reset default display role
|
||||
commands.addInboxServerCommand("role reset", [], async (msg, args, thread) => {
|
||||
await resetModeratorDefaultRoleOverride(msg.member.id);
|
||||
|
||||
const displayRole = await getModeratorDefaultDisplayRoleName(msg.member);
|
||||
if (displayRole) {
|
||||
msg.channel.createMessage(`Your default display role has been reset. Your replies will now display the role **${displayRole}** by default.`);
|
||||
} else {
|
||||
msg.channel.createMessage("Your default display role has been reset. Your replies will no longer display a role by default.");
|
||||
}
|
||||
}, {
|
||||
aliases: ["role_reset", "reset_role"],
|
||||
});
|
||||
|
||||
// Set default display role
|
||||
commands.addInboxServerCommand("role", "<role:string$>", async (msg, args, thread) => {
|
||||
const role = resolveRoleInput(args.role);
|
||||
if (! role || ! msg.member.roles.includes(role.id)) {
|
||||
msg.channel.createMessage("No matching role found. Make sure you have the role before trying to set it as your default display role.");
|
||||
return;
|
||||
}
|
||||
|
||||
await setModeratorDefaultRoleOverride(msg.member.id, role.id);
|
||||
msg.channel.createMessage(`Your default display role has been set to **${role.name}**. You can reset it with \`${config.prefix}role reset\`.`);
|
||||
});
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue