diff --git a/backend/src/plugins/Roles.ts b/backend/src/plugins/Roles.ts index 08734dc0..1355333e 100644 --- a/backend/src/plugins/Roles.ts +++ b/backend/src/plugins/Roles.ts @@ -50,7 +50,7 @@ export class RolesPlugin extends ZeppelinPlugin { } - @d.command("role", " ",{ + @d.command("role", " [role:string$]",{ extra: { info: { description: "Assign a permitted role to a user", @@ -60,20 +60,20 @@ export class RolesPlugin extends ZeppelinPlugin { @d.permission("can_assign") async assignRole(msg: Message, args: {action: string; user: string; role: string}){ const user = await this.resolveUser(args.user); - console.log(user); + const roleId = await this.resolveRoleId(args.role); if (user.discriminator == "0000") { return this.sendErrorMessage(msg.channel, `User not found`); } //if the role doesnt exist, we can exit let roleIds = (msg.channel as TextChannel).guild.roles.map(x => x.id) - if(!(roleIds.includes(args.role))){ + if(!(roleIds.includes(roleId))){ return this.sendErrorMessage(msg.channel, `Role not found`); } // If the user exists as a guild member, make sure we can act on them first - const member = await this.getMember(user.id); - if (member && !this.canActOn(msg.member, member)) { + const targetMember = await this.getMember(user.id); + if (targetMember && !this.canActOn(msg.member, targetMember)) { this.sendErrorMessage(msg.channel, "Cannot add or remove roles on this user: insufficient permissions"); return; } @@ -86,14 +86,31 @@ export class RolesPlugin extends ZeppelinPlugin { //check if the role is allowed to be applied let config = this.getConfigForMsg(msg) - if(!config.assignable_roles || !config.assignable_roles.includes(args.role)){ + if(!config.assignable_roles || !config.assignable_roles.includes(roleId)){ this.sendErrorMessage(msg.channel, "You do not have access to the specified role"); return; } - //at this point, everything has been verified, so apply the role - await this.bot.addGuildMemberRole(this.guildId, user.id, args.role); - - console.log("exited at the end"); + //at this point, everything has been verified, so it's ACTION TIME + switch(RoleActions[action]){ + case RoleActions.Add: + if(targetMember.roles.includes(roleId)){ + this.sendErrorMessage(msg.channel, "Role already applied to user"); + return; + } + await this.bot.addGuildMemberRole(this.guildId, user.id, roleId); + this.sendSuccessMessage(msg.channel, `Role added to user!`); + break; + case RoleActions.Remove: + if(!targetMember.roles.includes(roleId)){ + this.sendErrorMessage(msg.channel, "User does not have role"); + return; + } + await this.bot.removeGuildMemberRole(this.guildId, user.id, roleId); + this.sendSuccessMessage(msg.channel, `Role removed from user!`); + break; + default: + break; + } } } \ No newline at end of file diff --git a/backend/src/plugins/ZeppelinPlugin.ts b/backend/src/plugins/ZeppelinPlugin.ts index ce593a0b..65eecbaa 100644 --- a/backend/src/plugins/ZeppelinPlugin.ts +++ b/backend/src/plugins/ZeppelinPlugin.ts @@ -16,6 +16,7 @@ import { trimEmptyStartEndLines, trimIndents, UnknownUser, + resolveRoleId, } from "../utils"; import { Invite, Member, User } from "eris"; import DiscordRESTError from "eris/lib/errors/DiscordRESTError"; // tslint:disable-line @@ -237,6 +238,16 @@ export class ZeppelinPlugin extends Plug return user; } + /** + * Resolves a role from the passed string. The passed string can be a role ID, a role mention or a role name. + * In the event of duplicate role names, this function will return the first one it comes across. + * @param roleResolvable + */ + async resolveRoleId(roleResolvable: string): Promise { + const roleId = await resolveRoleId(this.bot, this.guildId, roleResolvable); + return roleId; + } + /** * Resolves a member from the passed string. The passed string can be a user id, a user mention, a full username (with discrim), etc. * If the member is not found in the cache, it's fetched from the API. diff --git a/backend/src/utils.ts b/backend/src/utils.ts index 9542c48b..f12a04e1 100644 --- a/backend/src/utils.ts +++ b/backend/src/utils.ts @@ -956,6 +956,32 @@ export async function resolveMember(bot: Client, guild: Guild, value: string): P return null; } +export async function resolveRoleId(bot: Client, guildId: string, value: string){ + if(value == null){ + return null; + } + + //role mention + const mentionMatch = value.match(/^<@&?(\d+)>$/); + if(mentionMatch){ + return mentionMatch[1]; + } + + //role name + let roleList = await bot.getRESTGuildRoles(guildId); + let role = roleList.filter(x => x.name.toLocaleLowerCase() == value.toLocaleLowerCase()); + if(role[0]){ + return role[0].id; + } + + //role ID + const idMatch = value.match(/^\d+$/); + if (idMatch) { + return value; + } + return null; +} + export type StrictMessageContent = { content?: string; tts?: boolean; disableEveryone?: boolean; embed?: EmbedOptions }; export async function confirm(bot: Client, channel: TextableChannel, userId: string, content: MessageContent) {