Migrate Roles to new Plugin structure

This commit is contained in:
Dark 2020-07-23 00:55:12 +02:00
parent ebcb28261b
commit 3685cc4df8
7 changed files with 388 additions and 0 deletions

View 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);
},
});

View 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)}!`,
);
},
});

View 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));
},
});

View 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));
},
});

View 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)}!`,
);
},
});

View 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>();

View file

@ -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";
// prettier-ignore
export const guildPlugins: Array<ZeppelinPluginBlueprint<any>> = [
@ -23,6 +24,7 @@ export const guildPlugins: Array<ZeppelinPluginBlueprint<any>> = [
MessageSaverPlugin,
NameHistoryPlugin,
RemindersPlugin,
RolesPlugin,
TagsPlugin,
UsernameSaverPlugin,
UtilityPlugin,