commit
482886a012
7 changed files with 388 additions and 0 deletions
49
backend/src/plugins/Roles/RolesPlugin.ts
Normal file
49
backend/src/plugins/Roles/RolesPlugin.ts
Normal file
|
@ -0,0 +1,49 @@
|
|||
import { zeppelinPlugin } from "../ZeppelinPluginBlueprint";
|
||||
import { PluginOptions } from "knub";
|
||||
import { ConfigSchema, RolesPluginType } from "./types";
|
||||
import { GuildLogs } from "src/data/GuildLogs";
|
||||
import { AddRoleCmd } from "./commands/AddRoleCmd";
|
||||
import { RemoveRoleCmd } from "./commands/RemoveRoleCmd";
|
||||
import { MassAddRoleCmd } from "./commands/MassAddRoleCmd";
|
||||
import { MassRemoveRoleCmd } from "./commands/MassRemoveRoleCmd";
|
||||
|
||||
const defaultOptions: PluginOptions<RolesPluginType> = {
|
||||
config: {
|
||||
can_assign: false,
|
||||
can_mass_assign: false,
|
||||
assignable_roles: ["558037973581430785"],
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
level: ">=50",
|
||||
config: {
|
||||
can_assign: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
level: ">=100",
|
||||
config: {
|
||||
can_mass_assign: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const RolesPlugin = zeppelinPlugin<RolesPluginType>()("roles", {
|
||||
configSchema: ConfigSchema,
|
||||
defaultOptions,
|
||||
|
||||
// prettier-ignore
|
||||
commands: [
|
||||
AddRoleCmd,
|
||||
RemoveRoleCmd,
|
||||
MassAddRoleCmd,
|
||||
MassRemoveRoleCmd,
|
||||
],
|
||||
|
||||
onLoad(pluginData) {
|
||||
const { state, guild } = pluginData;
|
||||
|
||||
state.logs = new GuildLogs(guild.id);
|
||||
},
|
||||
});
|
61
backend/src/plugins/Roles/commands/AddRoleCmd.ts
Normal file
61
backend/src/plugins/Roles/commands/AddRoleCmd.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||
import { sendErrorMessage, sendSuccessMessage, canActOn } from "src/pluginUtils";
|
||||
import { rolesCmd } from "../types";
|
||||
import { resolveRoleId, stripObjectToScalars, verboseUserMention } from "src/utils";
|
||||
import { LogType } from "src/data/LogType";
|
||||
import { GuildChannel } from "eris";
|
||||
|
||||
export const AddRoleCmd = rolesCmd({
|
||||
trigger: "addrole",
|
||||
permission: "can_assign",
|
||||
|
||||
signature: {
|
||||
member: ct.resolvedMember(),
|
||||
role: ct.string({ catchAll: true }),
|
||||
},
|
||||
|
||||
async run({ message: msg, args, pluginData }) {
|
||||
if (!canActOn(pluginData, msg.member, args.member, true)) {
|
||||
return sendErrorMessage(pluginData, msg.channel, "Cannot add roles to this user: insufficient permissions");
|
||||
}
|
||||
|
||||
const roleId = await resolveRoleId(pluginData.client, pluginData.guild.id, args.role);
|
||||
if (!roleId) {
|
||||
return sendErrorMessage(pluginData, msg.channel, "Invalid role id");
|
||||
}
|
||||
|
||||
const config = pluginData.config.getForMessage(msg);
|
||||
if (!config.assignable_roles.includes(roleId)) {
|
||||
return sendErrorMessage(pluginData, msg.channel, "You cannot assign that role");
|
||||
}
|
||||
|
||||
// Sanity check: make sure the role is configured properly
|
||||
const role = (msg.channel as GuildChannel).guild.roles.get(roleId);
|
||||
if (!role) {
|
||||
pluginData.state.logs.log(LogType.BOT_ALERT, {
|
||||
body: `Unknown role configured for 'roles' plugin: ${roleId}`,
|
||||
});
|
||||
return sendErrorMessage(pluginData, msg.channel, "You cannot assign that role");
|
||||
}
|
||||
|
||||
if (args.member.roles.includes(roleId)) {
|
||||
return sendErrorMessage(pluginData, msg.channel, "Member already has that role");
|
||||
}
|
||||
|
||||
pluginData.state.logs.ignoreLog(LogType.MEMBER_ROLE_ADD, args.member.id);
|
||||
|
||||
await args.member.addRole(roleId);
|
||||
|
||||
pluginData.state.logs.log(LogType.MEMBER_ROLE_ADD, {
|
||||
member: stripObjectToScalars(args.member, ["user", "roles"]),
|
||||
roles: role.name,
|
||||
mod: stripObjectToScalars(msg.author),
|
||||
});
|
||||
|
||||
sendSuccessMessage(
|
||||
pluginData,
|
||||
msg.channel,
|
||||
`Added role **${role.name}** to ${verboseUserMention(args.member.user)}!`,
|
||||
);
|
||||
},
|
||||
});
|
98
backend/src/plugins/Roles/commands/MassAddRoleCmd.ts
Normal file
98
backend/src/plugins/Roles/commands/MassAddRoleCmd.ts
Normal file
|
@ -0,0 +1,98 @@
|
|||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||
import { sendErrorMessage, canActOn } from "src/pluginUtils";
|
||||
import { rolesCmd } from "../types";
|
||||
import { resolveMember, resolveRoleId, stripObjectToScalars, successMessage } from "src/utils";
|
||||
import { LogType } from "src/data/LogType";
|
||||
import { logger } from "src/logger";
|
||||
|
||||
export const MassAddRoleCmd = rolesCmd({
|
||||
trigger: "massaddrole",
|
||||
permission: "can_mass_assign",
|
||||
|
||||
signature: {
|
||||
role: ct.string(),
|
||||
members: ct.string({ rest: true }),
|
||||
},
|
||||
|
||||
async run({ message: msg, args, pluginData }) {
|
||||
msg.channel.createMessage(`Resolving members...`);
|
||||
|
||||
const members = [];
|
||||
const unknownMembers = [];
|
||||
for (const memberId of args.members) {
|
||||
const member = await resolveMember(pluginData.client, pluginData.guild, memberId);
|
||||
if (member) members.push(member);
|
||||
else unknownMembers.push(memberId);
|
||||
}
|
||||
|
||||
for (const member of members) {
|
||||
if (!canActOn(pluginData, msg.member, member, true)) {
|
||||
return sendErrorMessage(
|
||||
pluginData,
|
||||
msg.channel,
|
||||
"Cannot add roles to 1 or more specified members: insufficient permissions",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const roleId = await resolveRoleId(pluginData.client, pluginData.guild.id, args.role);
|
||||
if (!roleId) {
|
||||
return sendErrorMessage(pluginData, msg.channel, "Invalid role id");
|
||||
}
|
||||
|
||||
const config = pluginData.config.getForMessage(msg);
|
||||
if (!config.assignable_roles.includes(roleId)) {
|
||||
return sendErrorMessage(pluginData, msg.channel, "You cannot assign that role");
|
||||
}
|
||||
|
||||
const role = pluginData.guild.roles.get(roleId);
|
||||
if (!role) {
|
||||
pluginData.state.logs.log(LogType.BOT_ALERT, {
|
||||
body: `Unknown role configured for 'roles' plugin: ${roleId}`,
|
||||
});
|
||||
return sendErrorMessage(pluginData, msg.channel, "You cannot assign that role");
|
||||
}
|
||||
|
||||
const membersWithoutTheRole = members.filter(m => !m.roles.includes(roleId));
|
||||
let assigned = 0;
|
||||
const failed = [];
|
||||
const alreadyHadRole = members.length - membersWithoutTheRole.length;
|
||||
|
||||
msg.channel.createMessage(
|
||||
`Adding role **${role.name}** to ${membersWithoutTheRole.length} ${
|
||||
membersWithoutTheRole.length === 1 ? "member" : "members"
|
||||
}...`,
|
||||
);
|
||||
|
||||
for (const member of membersWithoutTheRole) {
|
||||
try {
|
||||
pluginData.state.logs.ignoreLog(LogType.MEMBER_ROLE_ADD, member.id);
|
||||
await member.addRole(roleId);
|
||||
pluginData.state.logs.log(LogType.MEMBER_ROLE_ADD, {
|
||||
member: stripObjectToScalars(member, ["user", "roles"]),
|
||||
roles: role.name,
|
||||
mod: stripObjectToScalars(msg.author),
|
||||
});
|
||||
assigned++;
|
||||
} catch (e) {
|
||||
logger.warn(`Error when adding role via !massaddrole: ${e.message}`);
|
||||
failed.push(member.id);
|
||||
}
|
||||
}
|
||||
|
||||
let resultMessage = `Added role **${role.name}** to ${assigned} ${assigned === 1 ? "member" : "members"}!`;
|
||||
if (alreadyHadRole) {
|
||||
resultMessage += ` ${alreadyHadRole} ${alreadyHadRole === 1 ? "member" : "members"} already had the role.`;
|
||||
}
|
||||
|
||||
if (failed.length) {
|
||||
resultMessage += `\nFailed to add the role to the following members: ${failed.join(", ")}`;
|
||||
}
|
||||
|
||||
if (unknownMembers.length) {
|
||||
resultMessage += `\nUnknown members: ${unknownMembers.join(", ")}`;
|
||||
}
|
||||
|
||||
msg.channel.createMessage(successMessage(resultMessage));
|
||||
},
|
||||
});
|
98
backend/src/plugins/Roles/commands/MassRemoveRoleCmd.ts
Normal file
98
backend/src/plugins/Roles/commands/MassRemoveRoleCmd.ts
Normal file
|
@ -0,0 +1,98 @@
|
|||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||
import { sendErrorMessage, canActOn } from "src/pluginUtils";
|
||||
import { rolesCmd } from "../types";
|
||||
import { resolveMember, stripObjectToScalars, successMessage, resolveRoleId } from "src/utils";
|
||||
import { LogType } from "src/data/LogType";
|
||||
import { logger } from "src/logger";
|
||||
|
||||
export const MassRemoveRoleCmd = rolesCmd({
|
||||
trigger: "massremoverole",
|
||||
permission: "can_mass_assign",
|
||||
|
||||
signature: {
|
||||
role: ct.string(),
|
||||
members: ct.string({ rest: true }),
|
||||
},
|
||||
|
||||
async run({ message: msg, args, pluginData }) {
|
||||
msg.channel.createMessage(`Resolving members...`);
|
||||
|
||||
const members = [];
|
||||
const unknownMembers = [];
|
||||
for (const memberId of args.members) {
|
||||
const member = await resolveMember(pluginData.client, pluginData.guild, memberId);
|
||||
if (member) members.push(member);
|
||||
else unknownMembers.push(memberId);
|
||||
}
|
||||
|
||||
for (const member of members) {
|
||||
if (!canActOn(pluginData, msg.member, member, true)) {
|
||||
return sendErrorMessage(
|
||||
pluginData,
|
||||
msg.channel,
|
||||
"Cannot add roles to 1 or more specified members: insufficient permissions",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const roleId = await resolveRoleId(pluginData.client, pluginData.guild.id, args.role);
|
||||
if (!roleId) {
|
||||
return sendErrorMessage(pluginData, msg.channel, "Invalid role id");
|
||||
}
|
||||
|
||||
const config = pluginData.config.getForMessage(msg);
|
||||
if (!config.assignable_roles.includes(roleId)) {
|
||||
return sendErrorMessage(pluginData, msg.channel, "You cannot remove that role");
|
||||
}
|
||||
|
||||
const role = pluginData.guild.roles.get(roleId);
|
||||
if (!role) {
|
||||
pluginData.state.logs.log(LogType.BOT_ALERT, {
|
||||
body: `Unknown role configured for 'roles' plugin: ${roleId}`,
|
||||
});
|
||||
return sendErrorMessage(pluginData, msg.channel, "You cannot remove that role");
|
||||
}
|
||||
|
||||
const membersWithTheRole = members.filter(m => m.roles.includes(roleId));
|
||||
let assigned = 0;
|
||||
const failed = [];
|
||||
const didNotHaveRole = members.length - membersWithTheRole.length;
|
||||
|
||||
msg.channel.createMessage(
|
||||
`Removing role **${role.name}** from ${membersWithTheRole.length} ${
|
||||
membersWithTheRole.length === 1 ? "member" : "members"
|
||||
}...`,
|
||||
);
|
||||
|
||||
for (const member of membersWithTheRole) {
|
||||
try {
|
||||
pluginData.state.logs.ignoreLog(LogType.MEMBER_ROLE_REMOVE, member.id);
|
||||
await member.removeRole(roleId);
|
||||
pluginData.state.logs.log(LogType.MEMBER_ROLE_REMOVE, {
|
||||
member: stripObjectToScalars(member, ["user", "roles"]),
|
||||
roles: role.name,
|
||||
mod: stripObjectToScalars(msg.author),
|
||||
});
|
||||
assigned++;
|
||||
} catch (e) {
|
||||
logger.warn(`Error when removing role via !massremoverole: ${e.message}`);
|
||||
failed.push(member.id);
|
||||
}
|
||||
}
|
||||
|
||||
let resultMessage = `Removed role **${role.name}** from ${assigned} ${assigned === 1 ? "member" : "members"}!`;
|
||||
if (didNotHaveRole) {
|
||||
resultMessage += ` ${didNotHaveRole} ${didNotHaveRole === 1 ? "member" : "members"} didn't have the role.`;
|
||||
}
|
||||
|
||||
if (failed.length) {
|
||||
resultMessage += `\nFailed to remove the role from the following members: ${failed.join(", ")}`;
|
||||
}
|
||||
|
||||
if (unknownMembers.length) {
|
||||
resultMessage += `\nUnknown members: ${unknownMembers.join(", ")}`;
|
||||
}
|
||||
|
||||
msg.channel.createMessage(successMessage(resultMessage));
|
||||
},
|
||||
});
|
61
backend/src/plugins/Roles/commands/RemoveRoleCmd.ts
Normal file
61
backend/src/plugins/Roles/commands/RemoveRoleCmd.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||
import { sendErrorMessage, sendSuccessMessage, canActOn } from "src/pluginUtils";
|
||||
import { rolesCmd } from "../types";
|
||||
import { GuildChannel } from "eris";
|
||||
import { LogType } from "src/data/LogType";
|
||||
import { stripObjectToScalars, verboseUserMention, resolveRoleId } from "src/utils";
|
||||
|
||||
export const RemoveRoleCmd = rolesCmd({
|
||||
trigger: "removerole",
|
||||
permission: "can_assign",
|
||||
|
||||
signature: {
|
||||
member: ct.resolvedMember(),
|
||||
role: ct.string({ catchAll: true }),
|
||||
},
|
||||
|
||||
async run({ message: msg, args, pluginData }) {
|
||||
if (!canActOn(pluginData, msg.member, args.member, true)) {
|
||||
return sendErrorMessage(pluginData, msg.channel, "Cannot remove roles from this user: insufficient permissions");
|
||||
}
|
||||
|
||||
const roleId = await resolveRoleId(pluginData.client, pluginData.guild.id, args.role);
|
||||
if (!roleId) {
|
||||
return sendErrorMessage(pluginData, msg.channel, "Invalid role id");
|
||||
}
|
||||
|
||||
const config = pluginData.config.getForMessage(msg);
|
||||
if (!config.assignable_roles.includes(roleId)) {
|
||||
return sendErrorMessage(pluginData, msg.channel, "You cannot remove that role");
|
||||
}
|
||||
|
||||
// Sanity check: make sure the role is configured properly
|
||||
const role = (msg.channel as GuildChannel).guild.roles.get(roleId);
|
||||
if (!role) {
|
||||
pluginData.state.logs.log(LogType.BOT_ALERT, {
|
||||
body: `Unknown role configured for 'roles' plugin: ${roleId}`,
|
||||
});
|
||||
return sendErrorMessage(pluginData, msg.channel, "You cannot remove that role");
|
||||
}
|
||||
|
||||
if (!args.member.roles.includes(roleId)) {
|
||||
return sendErrorMessage(pluginData, msg.channel, "Member doesn't have that role");
|
||||
}
|
||||
|
||||
pluginData.state.logs.ignoreLog(LogType.MEMBER_ROLE_REMOVE, args.member.id);
|
||||
|
||||
await args.member.removeRole(roleId);
|
||||
|
||||
pluginData.state.logs.log(LogType.MEMBER_ROLE_REMOVE, {
|
||||
member: stripObjectToScalars(args.member, ["user", "roles"]),
|
||||
roles: role.name,
|
||||
mod: stripObjectToScalars(msg.author),
|
||||
});
|
||||
|
||||
sendSuccessMessage(
|
||||
pluginData,
|
||||
msg.channel,
|
||||
`Removed role **${role.name}** removed from ${verboseUserMention(args.member.user)}!`,
|
||||
);
|
||||
},
|
||||
});
|
19
backend/src/plugins/Roles/types.ts
Normal file
19
backend/src/plugins/Roles/types.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import * as t from "io-ts";
|
||||
import { BasePluginType, eventListener, command } from "knub";
|
||||
import { GuildLogs } from "src/data/GuildLogs";
|
||||
|
||||
export const ConfigSchema = t.type({
|
||||
can_assign: t.boolean,
|
||||
can_mass_assign: t.boolean,
|
||||
assignable_roles: t.array(t.string),
|
||||
});
|
||||
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
|
||||
|
||||
export interface RolesPluginType extends BasePluginType {
|
||||
config: TConfigSchema;
|
||||
state: {
|
||||
logs: GuildLogs;
|
||||
};
|
||||
}
|
||||
|
||||
export const rolesCmd = command<RolesPluginType>();
|
|
@ -13,6 +13,7 @@ import { GuildConfigReloaderPlugin } from "./GuildConfigReloader/GuildConfigRelo
|
|||
import { CasesPlugin } from "./Cases/CasesPlugin";
|
||||
import { MutesPlugin } from "./Mutes/MutesPlugin";
|
||||
import { TagsPlugin } from "./Tags/TagsPlugin";
|
||||
import { RolesPlugin } from "./Roles/RolesPlugin";
|
||||
import { SlowmodePlugin } from "./Slowmode/SlowmodePlugin";
|
||||
import { StarboardPlugin } from "./Starboard/StarboardPlugin";
|
||||
import { ChannelArchiverPlugin } from "./ChannelArchiver/ChannelArchiverPlugin";
|
||||
|
@ -27,6 +28,7 @@ export const guildPlugins: Array<ZeppelinPluginBlueprint<any>> = [
|
|||
MessageSaverPlugin,
|
||||
NameHistoryPlugin,
|
||||
RemindersPlugin,
|
||||
RolesPlugin,
|
||||
SlowmodePlugin,
|
||||
StarboardPlugin,
|
||||
TagsPlugin,
|
||||
|
|
Loading…
Add table
Reference in a new issue