Advertisement
Guest User

Untitled

a guest
May 27th, 2022
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. 'use strict';
  2.  
  3. const { Collection } = require('@discordjs/collection');
  4. const BaseManager = require('./BaseManager');
  5. const { Error, TypeError } = require('../errors');
  6. const { ApplicationCommandPermissionTypes, APIErrors } = require('../util/Constants');
  7.  
  8. /**
  9.  * Manages API methods for permissions of Application Commands.
  10.  * @extends {BaseManager}
  11.  */
  12. class ApplicationCommandPermissionsManager extends BaseManager {
  13.   constructor(manager) {
  14.     super(manager.client);
  15.  
  16.     /**
  17.      * The manager or command that this manager belongs to
  18.      * @type {ApplicationCommandManager|ApplicationCommand}
  19.      * @private
  20.      */
  21.     this.manager = manager;
  22.  
  23.     /**
  24.      * The guild that this manager acts on
  25.      * @type {?Guild}
  26.      */
  27.     this.guild = manager.guild ?? null;
  28.  
  29.     /**
  30.      * The id of the guild that this manager acts on
  31.      * @type {?Snowflake}
  32.      */
  33.     this.guildId = manager.guildId ?? manager.guild?.id ?? null;
  34.  
  35.     /**
  36.      * The id of the command this manager acts on
  37.      * @type {?Snowflake}
  38.      */
  39.     this.commandId = manager.id ?? null;
  40.   }
  41.  
  42.   /**
  43.    * The APIRouter path to the commands
  44.    * @param {Snowflake} guildId The guild's id to use in the path,
  45.    * @param {Snowflake} [commandId] The application command's id
  46.    * @returns {Object}
  47.    * @private
  48.    */
  49.   permissionsPath(guildId, commandId) {
  50.     return this.client.api.applications(this.client.application.id).guilds(guildId).commands(commandId).permissions;
  51.   }
  52.  
  53.   /**
  54.    * Data for setting the permissions of an application command.
  55.    * @typedef {Object} ApplicationCommandPermissionData
  56.    * @property {Snowflake} id The role or user's id
  57.    * @property {ApplicationCommandPermissionType|number} type Whether this permission is for a role or a user
  58.    * @property {boolean} permission Whether the role or user has the permission to use this command
  59.    */
  60.  
  61.   /**
  62.    * The object returned when fetching permissions for an application command.
  63.    * @typedef {Object} ApplicationCommandPermissions
  64.    * @property {Snowflake} id The role or user's id
  65.    * @property {ApplicationCommandPermissionType} type Whether this permission is for a role or a user
  66.    * @property {boolean} permission Whether the role or user has the permission to use this command
  67.    */
  68.  
  69.   /**
  70.    * Options for managing permissions for one or more Application Commands
  71.    * <warn>When passing these options to a manager where `guildId` is `null`,
  72.    * `guild` is a required parameter</warn>
  73.    * @typedef {Object} BaseApplicationCommandPermissionsOptions
  74.    * @property {GuildResolvable} [guild] The guild to modify / check permissions for
  75.    * <warn>Ignored when the manager has a non-null `guildId` property</warn>
  76.    * @property {ApplicationCommandResolvable} [command] The command to modify / check permissions for
  77.    * <warn>Ignored when the manager has a non-null `commandId` property</warn>
  78.    */
  79.  
  80.   /**
  81.    * Fetches the permissions for one or multiple commands.
  82.    * @param {BaseApplicationCommandPermissionsOptions} [options] Options used to fetch permissions
  83.    * @returns {Promise<ApplicationCommandPermissions[]|Collection<Snowflake, ApplicationCommandPermissions[]>>}
  84.    * @example
  85.    * // Fetch permissions for one command
  86.    * guild.commands.permissions.fetch({ command: '123456789012345678' })
  87.    *   .then(perms => console.log(`Fetched permissions for ${perms.length} users`))
  88.    *   .catch(console.error);
  89.    * @example
  90.    * // Fetch permissions for all commands in a guild
  91.    * client.application.commands.permissions.fetch({ guild: '123456789012345678' })
  92.    *   .then(perms => console.log(`Fetched permissions for ${perms.size} commands`))
  93.    *   .catch(console.error);
  94.    */
  95.   async fetch({ guild, command } = {}) {
  96.     const { guildId, commandId } = this._validateOptions(guild, command);
  97.     if (commandId) {
  98.       const data = await this.permissionsPath(guildId, commandId).get();
  99.       return data.permissions.map(perm => this.constructor.transformPermissions(perm, true));
  100.     }
  101.  
  102.     const data = await this.permissionsPath(guildId).get();
  103.     return data.reduce(
  104.       (coll, perm) =>
  105.         coll.set(
  106.           perm.id,
  107.           perm.permissions.map(p => this.constructor.transformPermissions(p, true)),
  108.         ),
  109.       new Collection(),
  110.     );
  111.   }
  112.  
  113.   /**
  114.    * Data used for overwriting the permissions for all application commands in a guild.
  115.    * @typedef {Object} GuildApplicationCommandPermissionData
  116.    * @property {Snowflake} id The command's id
  117.    * @property {ApplicationCommandPermissionData[]} permissions The permissions for this command
  118.    */
  119.  
  120.   /**
  121.    * Options used to set permissions for one or more Application Commands in a guild
  122.    * <warn>One of `command` AND `permissions`, OR `fullPermissions` is required.
  123.    * `fullPermissions` is not a valid option when passing to a manager where `commandId` is non-null</warn>
  124.    * @typedef {BaseApplicationCommandPermissionsOptions} SetApplicationCommandPermissionsOptions
  125.    * @property {ApplicationCommandPermissionData[]} [permissions] The new permissions for the command
  126.    * @property {GuildApplicationCommandPermissionData[]} [fullPermissions] The new permissions for all commands
  127.    * in a guild <warn>When this parameter is set, `permissions` and `command` are ignored</warn>
  128.    */
  129.  
  130.   /**
  131.    * Sets the permissions for one or more commands.
  132.    * @param {SetApplicationCommandPermissionsOptions} options Options used to set permissions
  133.    * @returns {Promise<ApplicationCommandPermissions[]|Collection<Snowflake, ApplicationCommandPermissions[]>>}
  134.    * @example
  135.    * // Set the permissions for one command
  136.    * client.application.commands.permissions.set({ guild: '892455839386304532', command: '123456789012345678',
  137.    *  permissions: [
  138.    *    {
  139.    *      id: '876543210987654321',
  140.    *      type: 'USER',
  141.    *      permission: false,
  142.    *    },
  143.    * ]})
  144.    *   .then(console.log)
  145.    *   .catch(console.error);
  146.    * @example
  147.    * // Set the permissions for all commands
  148.    * guild.commands.permissions.set({ fullPermissions: [
  149.    *   {
  150.    *     id: '123456789012345678',
  151.    *     permissions: [{
  152.    *       id: '876543210987654321',
  153.    *       type: 'USER',
  154.    *       permission: false,
  155.    *     }],
  156.    *   },
  157.    * ]})
  158.    *   .then(console.log)
  159.    *   .catch(console.error);
  160.    */
  161.   async set({ guild, command, permissions, fullPermissions } = {}) {
  162.     const { guildId, commandId } = this._validateOptions(guild, command);
  163.  
  164.     if (commandId) {
  165.       if (!Array.isArray(permissions)) {
  166.         throw new TypeError('INVALID_TYPE', 'permissions', 'Array of ApplicationCommandPermissionData', true);
  167.       }
  168.       const data = await this.permissionsPath(guildId, commandId).put({
  169.         data: { permissions: permissions.map(perm => this.constructor.transformPermissions(perm)) },
  170.       });
  171.       return data.permissions.map(perm => this.constructor.transformPermissions(perm, true));
  172.     }
  173.  
  174.     if (!Array.isArray(fullPermissions)) {
  175.       throw new TypeError('INVALID_TYPE', 'fullPermissions', 'Array of GuildApplicationCommandPermissionData', true);
  176.     }
  177.  
  178.     const APIPermissions = [];
  179.     for (const perm of fullPermissions) {
  180.       if (!Array.isArray(perm.permissions)) throw new TypeError('INVALID_ELEMENT', 'Array', 'fullPermissions', perm);
  181.       APIPermissions.push({
  182.         id: perm.id,
  183.         permissions: perm.permissions.map(p => this.constructor.transformPermissions(p)),
  184.       });
  185.     }
  186.     const data = await this.permissionsPath(guildId).put({
  187.       data: APIPermissions,
  188.     });
  189.     return data.reduce(
  190.       (coll, perm) =>
  191.         coll.set(
  192.           perm.id,
  193.           perm.permissions.map(p => this.constructor.transformPermissions(p, true)),
  194.         ),
  195.       new Collection(),
  196.     );
  197.   }
  198.  
  199.   /**
  200.    * Options used to add permissions to a command
  201.    * <warn>The `command` parameter is not optional when the managers `commandId` is `null`</warn>
  202.    * @typedef {BaseApplicationCommandPermissionsOptions} AddApplicationCommandPermissionsOptions
  203.    * @property {ApplicationCommandPermissionData[]} permissions The permissions to add to the command
  204.    */
  205.  
  206.   /**
  207.    * Add permissions to a command.
  208.    * @param {AddApplicationCommandPermissionsOptions} options Options used to add permissions
  209.    * @returns {Promise<ApplicationCommandPermissions[]>}
  210.    * @example
  211.    * // Block a role from the command permissions
  212.    * guild.commands.permissions.add({ command: '123456789012345678', permissions: [
  213.    *   {
  214.    *     id: '876543211234567890',
  215.    *     type: 'ROLE',
  216.    *     permission: false
  217.    *   },
  218.    * ]})
  219.    *   .then(console.log)
  220.    *   .catch(console.error);
  221.    */
  222.   async add({ guild, command, permissions }) {
  223.     const { guildId, commandId } = this._validateOptions(guild, command);
  224.     if (!commandId) throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable');
  225.     if (!Array.isArray(permissions)) {
  226.       throw new TypeError('INVALID_TYPE', 'permissions', 'Array of ApplicationCommandPermissionData', true);
  227.     }
  228.  
  229.     let existing = [];
  230.     try {
  231.       existing = await this.fetch({ guild: guildId, command: commandId });
  232.     } catch (error) {
  233.       if (error.code !== APIErrors.UNKNOWN_APPLICATION_COMMAND_PERMISSIONS) throw error;
  234.     }
  235.  
  236.     const newPermissions = permissions.slice();
  237.     for (const perm of existing) {
  238.       if (!newPermissions.some(x => x.id === perm.id)) {
  239.         newPermissions.push(perm);
  240.       }
  241.     }
  242.  
  243.     return this.set({ guild: guildId, command: commandId, permissions: newPermissions });
  244.   }
  245.  
  246.   /**
  247.    * Options used to remove permissions from a command
  248.    * <warn>The `command` parameter is not optional when the managers `commandId` is `null`</warn>
  249.    * @typedef {BaseApplicationCommandPermissionsOptions} RemoveApplicationCommandPermissionsOptions
  250.    * @property {UserResolvable|UserResolvable[]} [users] The user(s) to remove from the command permissions
  251.    * <warn>One of `users` or `roles` is required</warn>
  252.    * @property {RoleResolvable|RoleResolvable[]} [roles] The role(s) to remove from the command permissions
  253.    * <warn>One of `users` or `roles` is required</warn>
  254.    */
  255.  
  256.   /**
  257.    * Remove permissions from a command.
  258.    * @param {RemoveApplicationCommandPermissionsOptions} options Options used to remove permissions
  259.    * @returns {Promise<ApplicationCommandPermissions[]>}
  260.    * @example
  261.    * // Remove a user permission from this command
  262.    * guild.commands.permissions.remove({ command: '123456789012345678', users: '876543210123456789' })
  263.    *   .then(console.log)
  264.    *   .catch(console.error);
  265.    * @example
  266.    * // Remove multiple roles from this command
  267.    * guild.commands.permissions.remove({
  268.    *   command: '123456789012345678', roles: ['876543210123456789', '765432101234567890']
  269.    * })
  270.    *    .then(console.log)
  271.    *    .catch(console.error);
  272.    */
  273.   async remove({ guild, command, users, roles }) {
  274.     const { guildId, commandId } = this._validateOptions(guild, command);
  275.     if (!commandId) throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable');
  276.  
  277.     if (!users && !roles) throw new TypeError('INVALID_TYPE', 'users OR roles', 'Array or Resolvable', true);
  278.  
  279.     let resolvedIds = [];
  280.     if (Array.isArray(users)) {
  281.       users.forEach(user => {
  282.         const userId = this.client.users.resolveId(user);
  283.         if (!userId) throw new TypeError('INVALID_ELEMENT', 'Array', 'users', user);
  284.         resolvedIds.push(userId);
  285.       });
  286.     } else if (users) {
  287.       const userId = this.client.users.resolveId(users);
  288.       if (!userId) {
  289.         throw new TypeError('INVALID_TYPE', 'users', 'Array or UserResolvable');
  290.       }
  291.       resolvedIds.push(userId);
  292.     }
  293.  
  294.     if (Array.isArray(roles)) {
  295.       roles.forEach(role => {
  296.         if (typeof role === 'string') {
  297.           resolvedIds.push(role);
  298.           return;
  299.         }
  300.         if (!this.guild) throw new Error('GUILD_UNCACHED_ROLE_RESOLVE');
  301.         const roleId = this.guild.roles.resolveId(role);
  302.         if (!roleId) throw new TypeError('INVALID_ELEMENT', 'Array', 'users', role);
  303.         resolvedIds.push(roleId);
  304.       });
  305.     } else if (roles) {
  306.       if (typeof roles === 'string') {
  307.         resolvedIds.push(roles);
  308.       } else {
  309.         if (!this.guild) throw new Error('GUILD_UNCACHED_ROLE_RESOLVE');
  310.         const roleId = this.guild.roles.resolveId(roles);
  311.         if (!roleId) {
  312.           throw new TypeError('INVALID_TYPE', 'users', 'Array or RoleResolvable');
  313.         }
  314.         resolvedIds.push(roleId);
  315.       }
  316.     }
  317.  
  318.     let existing = [];
  319.     try {
  320.       existing = await this.fetch({ guild: guildId, command: commandId });
  321.     } catch (error) {
  322.       if (error.code !== APIErrors.UNKNOWN_APPLICATION_COMMAND_PERMISSIONS) throw error;
  323.     }
  324.  
  325.     const permissions = existing.filter(perm => !resolvedIds.includes(perm.id));
  326.  
  327.     return this.set({ guild: guildId, command: commandId, permissions });
  328.   }
  329.  
  330.   /**
  331.    * Options used to check the existence of permissions on a command
  332.    * <warn>The `command` parameter is not optional when the managers `commandId` is `null`</warn>
  333.    * @typedef {BaseApplicationCommandPermissionsOptions} HasApplicationCommandPermissionsOptions
  334.    * @property {UserResolvable|RoleResolvable} permissionId The user or role to check if a permission exists for
  335.    * on this command.
  336.    */
  337.  
  338.   /**
  339.    * Check whether a permission exists for a user or role
  340.    * @param {AddApplicationCommandPermissionsOptions} options Options used to check permissions
  341.    * @returns {Promise<boolean>}
  342.    * @example
  343.    * // Check whether a user has permission to use a command
  344.    * guild.commands.permissions.has({ command: '123456789012345678', permissionId: '876543210123456789' })
  345.    *  .then(console.log)
  346.    *  .catch(console.error);
  347.    */
  348.   async has({ guild, command, permissionId }) {
  349.     const { guildId, commandId } = this._validateOptions(guild, command);
  350.     if (!commandId) throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable');
  351.  
  352.     if (!permissionId) throw new TypeError('INVALID_TYPE', 'permissionId', 'UserResolvable or RoleResolvable');
  353.     let resolvedId = permissionId;
  354.     if (typeof permissionId !== 'string') {
  355.       resolvedId = this.client.users.resolveId(permissionId);
  356.       if (!resolvedId) {
  357.         if (!this.guild) throw new Error('GUILD_UNCACHED_ROLE_RESOLVE');
  358.         resolvedId = this.guild.roles.resolveId(permissionId);
  359.       }
  360.       if (!resolvedId) {
  361.         throw new TypeError('INVALID_TYPE', 'permissionId', 'UserResolvable or RoleResolvable');
  362.       }
  363.     }
  364.  
  365.     let existing = [];
  366.     try {
  367.       existing = await this.fetch({ guild: guildId, command: commandId });
  368.     } catch (error) {
  369.       if (error.code !== APIErrors.UNKNOWN_APPLICATION_COMMAND_PERMISSIONS) throw error;
  370.     }
  371.  
  372.     return existing.some(perm => perm.id === resolvedId);
  373.   }
  374.  
  375.   _validateOptions(guild, command) {
  376.     const guildId = this.guildId ?? this.client.guilds.resolveId(guild);
  377.     if (!guildId) throw new Error('GLOBAL_COMMAND_PERMISSIONS');
  378.     let commandId = this.commandId;
  379.     if (command && !commandId) {
  380.       commandId = this.manager.resolveId?.(command);
  381.       if (!commandId && this.guild) {
  382.         commandId = this.guild.commands.resolveId(command);
  383.       }
  384.       commandId ??= this.client.application?.commands.resolveId(command);
  385.       if (!commandId) {
  386.         throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable', true);
  387.       }
  388.     }
  389.     return { guildId, commandId };
  390.   }
  391.  
  392.   /**
  393.    * Transforms an {@link ApplicationCommandPermissionData} object into something that can be used with the API.
  394.    * @param {ApplicationCommandPermissionData} permissions The permissions to transform
  395.    * @param {boolean} [received] Whether these permissions have been received from Discord
  396.    * @returns {APIApplicationCommandPermissions}
  397.    * @private
  398.    */
  399.   static transformPermissions(permissions, received) {
  400.     return {
  401.       id: permissions.id,
  402.       permission: permissions.permission,
  403.       type:
  404.         typeof permissions.type === 'number' && !received
  405.           ? permissions.type
  406.           : ApplicationCommandPermissionTypes[permissions.type],
  407.     };
  408.   }
  409. }
  410.  
  411. module.exports = ApplicationCommandPermissionsManager;
  412.  
  413. /* eslint-disable max-len */
  414. /**
  415.  * @external APIApplicationCommandPermissions
  416.  * @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permissions-structure}
  417.  */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement