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

fix(ApplicationCommandManager): limit permission methods to guilds #5613

Merged
merged 5 commits into from May 22, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/errors/Messages.js
Expand Up @@ -112,6 +112,8 @@ const Messages = {

MEMBER_FETCH_NONCE_LENGTH: 'Nonce length must not exceed 32 characters.',

GLOBAL_COMMAND: 'This method cannot be used on global application commands.',
vaporoxx marked this conversation as resolved.
Show resolved Hide resolved

INTERACTION_ALREADY_REPLIED: 'This interaction has already been deferred or replied to.',
};

Expand Down
119 changes: 0 additions & 119 deletions src/managers/ApplicationCommandManager.js
Expand Up @@ -4,7 +4,6 @@ const BaseManager = require('./BaseManager');
const { TypeError } = require('../errors');
const ApplicationCommand = require('../structures/ApplicationCommand');
const Collection = require('../util/Collection');
const { ApplicationCommandPermissionTypes } = require('../util/Constants');

/**
* Manages API methods for application commands and stores their cache.
Expand Down Expand Up @@ -164,106 +163,6 @@ class ApplicationCommandManager extends BaseManager {
return cached ?? null;
}

/**
* Fetches the permissions for one or multiple commands.
* @param {ApplicationCommandResolvable} [command] The command to get the permissions from
* @returns {Promise<ApplicationCommandPermissions[]|Collection<Snowflake, ApplicationCommandPermissions[]>>}
* @example
* // Fetch permissions for one command
* guild.commands.fetchPermissions('123456789012345678')
* .then(perms => console.log(`Fetched permissions for ${perms.length} users`))
* .catch(console.error);
* @example
* // Fetch permissions for all commands
* client.application.commands.fetchPermissions()
* .then(perms => console.log(`Fetched permissions for ${perms.size} commands`))
* .catch(console.error);
*/
async fetchPermissions(command) {
if (command) {
const id = this.resolveID(command);
if (!id) throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable');

const data = await this.commandPath(id).permissions.get();
return data.permissions.map(perm => this.constructor.transformPermissions(perm, true));
}

const data = await this.commandPath.permissions.get();
return data.reduce(
(coll, perm) =>
coll.set(
perm.id,
perm.permissions.map(p => this.constructor.transformPermissions(p, true)),
),
new Collection(),
);
}

/**
* Data used for overwriting the permissions for all application commands in a guild.
* @typedef {object} GuildApplicationCommandPermissionData
* @prop {Snowflake} command The ID of the command
* @prop {ApplicationCommandPermissionData[]} permissions The permissions for this command
*/

/**
* Sets the permissions for a command.
* @param {ApplicationCommandResolvable|GuildApplicationCommandPermissionData[]} command The command to edit the
* permissions for, or an array of guild application command permissions to set the permissions of all commands
* @param {ApplicationCommandPermissionData[]} permissions The new permissions for the command
* @returns {Promise<ApplicationCommandPermissions[]|Collection<Snowflake, ApplicationCommandPermissions[]>>}
* @example
* // Set the permissions for one command
* client.application.commands.setPermissions('123456789012345678', [
* {
* id: '876543210987654321',
* type: 'USER',
* permission: false,
* },
* ])
* .then(console.log)
* .catch(console.error);
* @example
* // Set the permissions for all commands
* guild.commands.setPermissions([
* {
* id: '123456789012345678',
* permissions: [{
* id: '876543210987654321',
* type: 'USER',
* permission: false,
* }],
* },
* ])
* .then(console.log)
* .catch(console.error);
*/
async setPermissions(command, permissions) {
const id = this.resolveID(command);

if (id) {
const data = await this.commandPath(id).permissions.put({
data: { permissions: permissions.map(perm => this.constructor.transformPermissions(perm)) },
});
return data.permissions.map(perm => this.constructor.transformPermissions(perm, true));
}

const data = await this.commandPath.permissions.put({
data: command.map(perm => ({
id: perm.id,
permissions: perm.permissions.map(p => this.constructor.transformPermissions(p)),
})),
});
return data.reduce(
(coll, perm) =>
coll.set(
perm.id,
perm.permissions.map(p => this.constructor.transformPermissions(p, true)),
),
new Collection(),
);
}

/**
* Transforms an {@link ApplicationCommandData} object into something that can be used with the API.
* @param {ApplicationCommandData} command The command to transform
Expand All @@ -278,24 +177,6 @@ class ApplicationCommandManager extends BaseManager {
default_permission: command.defaultPermission,
};
}

/**
* Transforms an {@link ApplicationCommandPermissionData} object into something that can be used with the API.
* @param {ApplicationCommandPermissionData} permissions The permissions to transform
* @param {boolean} [received] Whether these permissions have been received from Discord
* @returns {Object}
* @private
*/
static transformPermissions(permissions, received) {
return {
id: permissions.id,
permission: permissions.permission,
type:
typeof permissions.type === 'number' && !received
? permissions.type
: ApplicationCommandPermissionTypes[permissions.type],
};
}
}

module.exports = ApplicationCommandManager;
120 changes: 120 additions & 0 deletions src/managers/GuildApplicationCommandManager.js
@@ -1,6 +1,8 @@
'use strict';

const ApplicationCommandManager = require('./ApplicationCommandManager');
const Collection = require('../util/Collection');
const { ApplicationCommandPermissionTypes } = require('../util/Constants');

/**
* An extension for guild-specific application commands.
Expand All @@ -16,6 +18,124 @@ class GuildApplicationCommandManager extends ApplicationCommandManager {
*/
this.guild = guild;
}

/**
* Fetches the permissions for one or multiple commands.
* @param {ApplicationCommandResolvable} [command] The command to get the permissions from
* @returns {Promise<ApplicationCommandPermissions[]|Collection<Snowflake, ApplicationCommandPermissions[]>>}
* @example
* // Fetch permissions for one command
* guild.commands.fetchPermissions('123456789012345678')
* .then(perms => console.log(`Fetched permissions for ${perms.length} users`))
* .catch(console.error);
* @example
* // Fetch permissions for all commands
* client.application.commands.fetchPermissions()
* .then(perms => console.log(`Fetched permissions for ${perms.size} commands`))
* .catch(console.error);
*/
async fetchPermissions(command) {
if (command) {
const id = this.resolveID(command);
if (!id) throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable');

const data = await this.commandPath(id).permissions.get();
return data.permissions.map(perm => this.constructor.transformPermissions(perm, true));
}

const data = await this.commandPath.permissions.get();
return data.reduce(
(coll, perm) =>
coll.set(
perm.id,
perm.permissions.map(p => this.constructor.transformPermissions(p, true)),
),
new Collection(),
);
}

/**
* Data used for overwriting the permissions for all application commands in a guild.
* @typedef {object} GuildApplicationCommandPermissionData
* @prop {Snowflake} command The ID of the command
* @prop {ApplicationCommandPermissionData[]} permissions The permissions for this command
*/

/**
* Sets the permissions for a command.
* @param {ApplicationCommandResolvable|GuildApplicationCommandPermissionData[]} command The command to edit the
* permissions for, or an array of guild application command permissions to set the permissions of all commands
* @param {ApplicationCommandPermissionData[]} permissions The new permissions for the command
* @returns {Promise<ApplicationCommandPermissions[]|Collection<Snowflake, ApplicationCommandPermissions[]>>}
* @example
* // Set the permissions for one command
* client.application.commands.setPermissions('123456789012345678', [
* {
* id: '876543210987654321',
* type: 'USER',
* permission: false,
* },
* ])
* .then(console.log)
* .catch(console.error);
* @example
* // Set the permissions for all commands
* guild.commands.setPermissions([
* {
* id: '123456789012345678',
* permissions: [{
* id: '876543210987654321',
* type: 'USER',
* permission: false,
* }],
* },
* ])
* .then(console.log)
* .catch(console.error);
*/
async setPermissions(command, permissions) {
const id = this.resolveID(command);

if (id) {
const data = await this.commandPath(id).permissions.put({
data: { permissions: permissions.map(perm => this.constructor.transformPermissions(perm)) },
});
return data.permissions.map(perm => this.constructor.transformPermissions(perm, true));
}

const data = await this.commandPath.permissions.put({
data: command.map(perm => ({
id: perm.id,
permissions: perm.permissions.map(p => this.constructor.transformPermissions(p)),
})),
});
return data.reduce(
(coll, perm) =>
coll.set(
perm.id,
perm.permissions.map(p => this.constructor.transformPermissions(p, true)),
),
new Collection(),
);
}

/**
* Transforms an {@link ApplicationCommandPermissionData} object into something that can be used with the API.
* @param {ApplicationCommandPermissionData} permissions The permissions to transform
* @param {boolean} [received] Whether these permissions have been received from Discord
* @returns {Object}
* @private
*/
static transformPermissions(permissions, received) {
return {
id: permissions.id,
permission: permissions.permission,
type:
typeof permissions.type === 'number' && !received
? permissions.type
: ApplicationCommandPermissionTypes[permissions.type],
};
}
}

module.exports = GuildApplicationCommandManager;
5 changes: 4 additions & 1 deletion src/structures/ApplicationCommand.js
@@ -1,6 +1,7 @@
'use strict';

const Base = require('./Base');
const { Error } = require('../errors');
const { ApplicationCommandOptionTypes } = require('../util/Constants');
const SnowflakeUtil = require('../util/SnowflakeUtil');

Expand Down Expand Up @@ -130,7 +131,7 @@ class ApplicationCommand extends Base {
}

/**
* The object returned when fetching permissions for an application command.
* Data for setting the permissions of an application command.
* @typedef {object} ApplicationCommandPermissionData
* @property {Snowflake} id The ID of the role or user
* @property {ApplicationCommandPermissionType|number} type Whether this permission if for a role or a user
Expand All @@ -155,6 +156,7 @@ class ApplicationCommand extends Base {
* .catch(console.error);
*/
fetchPermissions() {
if (!this.guild) throw new Error('GLOBAL_COMMAND');
return this.manager.fetchPermissions(this);
}

Expand All @@ -175,6 +177,7 @@ class ApplicationCommand extends Base {
* .catch(console.error);
*/
setPermissions(permissions) {
if (!this.guild) throw new Error('GLOBAL_COMMAND');
return this.manager.setPermissions(this, permissions);
}

Expand Down
20 changes: 10 additions & 10 deletions typings/index.d.ts
Expand Up @@ -2065,18 +2065,8 @@ declare module 'discord.js' {
public edit(command: ApplicationCommandResolvable, data: ApplicationCommandData): Promise<ApplicationCommand>;
public fetch(id: Snowflake, cache?: boolean, force?: boolean): Promise<ApplicationCommand>;
public fetch(id?: Snowflake, cache?: boolean, force?: boolean): Promise<Collection<Snowflake, ApplicationCommand>>;
public fetchPermissions(): Promise<Collection<Snowflake, ApplicationCommandPermissions[]>>;
public fetchPermissions(command: ApplicationCommandResolvable): Promise<ApplicationCommandPermissions[]>;
public set(commands: ApplicationCommandData[]): Promise<Collection<Snowflake, ApplicationCommand>>;
public setPermissions(
command: ApplicationCommandResolvable,
permissions: ApplicationCommandPermissionData[],
): Promise<ApplicationCommandPermissions[]>;
public setPermissions(
permissions: GuildApplicationCommandPermissionData[],
): Promise<Collection<Snowflake, ApplicationCommandPermissions[]>>;
private static transformCommand(command: ApplicationCommandData): object;
private static transformPermissions(permissions: ApplicationCommandPermissionData, received?: boolean): object;
}

export class BaseGuildEmojiManager extends BaseManager<Snowflake, GuildEmoji, EmojiResolvable> {
Expand All @@ -2092,6 +2082,16 @@ declare module 'discord.js' {
export class GuildApplicationCommandManager extends ApplicationCommandManager {
constructor(guild: Guild, iterable?: Iterable<any>);
public guild: Guild;
public fetchPermissions(): Promise<Collection<Snowflake, ApplicationCommandPermissions[]>>;
public fetchPermissions(command: ApplicationCommandResolvable): Promise<ApplicationCommandPermissions[]>;
public setPermissions(
command: ApplicationCommandResolvable,
permissions: ApplicationCommandPermissionData[],
): Promise<ApplicationCommandPermissions[]>;
public setPermissions(
permissions: GuildApplicationCommandPermissionData[],
): Promise<Collection<Snowflake, ApplicationCommandPermissions[]>>;
private static transformPermissions(permissions: ApplicationCommandPermissionData, received?: boolean): object;
}

export class GuildChannelManager extends BaseManager<Snowflake, GuildChannel, GuildChannelResolvable> {
Expand Down