Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ID permission handlers #7

Merged
merged 5 commits into from
Jul 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"@typescript-eslint/eslint-plugin": "^4.28.2",
"@typescript-eslint/parser": "^4.28.2",
"babel-jest": "^27.0.6",
"discord.js": "^13.0.0-dev.5ca97c9.1626480265",
"discord.js": "^13.0.0-dev.4d53d0f.1626566655",
"eslint": "^7.30.0",
"jest": "^27.0.6",
"nodemon": "^2.0.12",
Expand Down
147 changes: 129 additions & 18 deletions src/utils/permissions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { GuildMember, TextChannel, ThreadChannel } from 'discord.js';
import { GuildMember, Snowflake, TextChannel, ThreadChannel } from 'discord.js';
import { PermissionHandler } from '../Command';
import { resolveRoleID } from './role';

Expand All @@ -22,12 +22,14 @@ export function checkAll(...handlers: PermissionHandler[]): PermissionHandler {
};
}

const hasID = (member: GuildMember, id: Snowflake) => member.roles.cache.has(id);

/**
* A helper function to check if the given roles are present from an interaction.
* @param roles The roles to check for.
* @param roles The roles names to check for.
* @returns A permission handler function.
*/
export function allRoles(...roles: string[]): PermissionHandler {
export function allRoleNames(...roles: string[]): PermissionHandler {
return async (interaction) => {
let allowed = true;
// FIXME is this cast safe?
Expand All @@ -50,9 +52,9 @@ export function allRoles(...roles: string[]): PermissionHandler {
}
const roleIDs = roles.map((role) => resolveRoleID(guild, role));
const errMsg =
'You must have the following roles to run this command:\n'.concat(
...roleIDs.map((role) => `- <@&${role}>\n`)
);
'You must have the following roles to run this command:\n'.concat(
...roleIDs.map((role) => `- <@&${role}>\n`)
);
await interaction.reply({ content: errMsg, ephemeral: true });
}

Expand All @@ -62,10 +64,10 @@ export function allRoles(...roles: string[]): PermissionHandler {

/**
* A helper function to check if the sender has one of the given roles.
* @param roles The roles to check for.
* @param roles The roles names to check for.
* @returns A permission handler function.
*/
export function oneOfRoles(...roles: string[]): PermissionHandler {
export function inRoleNames(...roles: string[]): PermissionHandler {
return async (interaction) => {
// FIXME is this cast safe?
const member = interaction.member as GuildMember;
Expand All @@ -81,9 +83,63 @@ export function oneOfRoles(...roles: string[]): PermissionHandler {
}
const roleIDs = roles.map((role) => resolveRoleID(guild, role));
const errMsg =
'You must have one of the following roles to run this command:\n'.concat(
...roleIDs.map((role) => `- <@&${role}>\n`)
);
'You must have one of the following roles to run this command:\n'.concat(
...roleIDs.map((role) => `- <@&${role}>\n`)
);
await interaction.reply({ content: errMsg, ephemeral: true });
}

return allowed;
};
}

/**
* A helper function to check if the given roles are present from an interaction.
* @param roles The roles IDs to check for.
* @returns A permission handler function.
*/
export function allRoles(...roleIDs: Snowflake[]): PermissionHandler {
return async (interaction) => {
const member = interaction.member as GuildMember;
let allowed = true;
if (!member) {
return false;
}

roleIDs.forEach(roleID => allowed &&= hasID(member, roleID));

if (!allowed) {
const errMsg =
'You must have the following roles to run this command:\n'.concat(
...roleIDs.map((role) => `- <@&${role}>\n`)
);
await interaction.reply({ content: errMsg, ephemeral: true });
}

return allowed;
};
}

/**
* A helper function to check if the sender has one of the given roles.
* @param roles The roles IDs to check for.
* @returns A permission handler function.
*/
export function inRoles(...roleIDs: Snowflake[]): PermissionHandler {
return async (interaction) => {
const member = interaction.member as GuildMember;
if (!member) {
return false;
}

const allowed = member.roles.cache.some(role => roleIDs.includes(role.id));

if (!allowed) {
const errMsg =
'You must have one of the following roles to run this command:\n'.concat(
...roleIDs.map((role) => `- <@&${role}>\n`)
);

await interaction.reply({ content: errMsg, ephemeral: true });
}

Expand All @@ -93,10 +149,10 @@ export function oneOfRoles(...roles: string[]): PermissionHandler {

/**
* A helper function to check if the interaction was sent in the given channel(s).
* @param channels The channels to check for.
* @param channels The channels names to check for.
* @returns A permission handler function.
*/
export function inChannels(...channels: string[]): PermissionHandler {
export function inChannelNames(...channels: string[]): PermissionHandler {
return async (interaction) => {
// Resolve each of the channel names
const channelIDs = channels.map(
Expand Down Expand Up @@ -126,12 +182,39 @@ export function inChannels(...channels: string[]): PermissionHandler {
};
}

/**
* A helper function to check if the interaction was sent in the given channel(s).
* @param channels The channels IDs to check for.
* @returns A permission handler function.
*/
export function inChannels(...channelIDs: Snowflake[]): PermissionHandler {
return async (interaction) => {

if (!interaction.channel) {
console.log('No channels found');
}

const allowed = channelIDs.includes(interaction.channelId);

if (!allowed) {
const errMsg = 'Please use this command in an allowed channel:\n'.concat(
...channelIDs.map((channel) => `- <#${channel}>\n`)
);

// Send error message.
await interaction.reply({ content: errMsg, ephemeral: true });
}

return allowed;
};
}

/**
* Checks if a given interaction is created in an allowed category.
* @param categories The categories to check for
* @param categories The categories names to check for
* @returns A permission handler.
*/
export function inCategories(...categories: string[]): PermissionHandler {
export function inCategoryNames(...categories: string[]): PermissionHandler {
return async (interaction) => {
if (!(interaction.channel instanceof TextChannel)) {
return false;
Expand All @@ -146,9 +229,37 @@ export function inCategories(...categories: string[]): PermissionHandler {

if (!allowed) {
const content =
'Please use the command in the following categories:\n'.concat(
...categories.map((cur) => `- ${cur}\n`)
);
'Please use the command in the following categories:\n'.concat(
...categories.map((cur) => `- ${cur}\n`)
);
await interaction.reply({ content, ephemeral: true });
}

return allowed;
};
}

/**
* Checks if a given interaction is created in an allowed category.
* @param categories The categories IDs to check for
* @returns A permission handler.
*/
export function inCategories(...categoryIDs: Snowflake[]): PermissionHandler {
return async (interaction) => {
if (!(interaction.channel instanceof TextChannel)) {
return false;
}

const category = interaction.channel.parent;

if (!category) {
return false;
}

const allowed = categoryIDs.includes(category.id);

if (!allowed) {
const content = 'This command is not allowed in this category';
await interaction.reply({ content, ephemeral: true });
}

Expand Down