mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-16 11:33:30 +01:00
Merge branch 'master' into voice-rewrite
This commit is contained in:
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
@@ -14,4 +14,4 @@ To get ready to work on the codebase, please do the following:
|
|||||||
3. If you're working on voice, also run `npm install node-opus` or `npm install opusscript`
|
3. If you're working on voice, also run `npm install node-opus` or `npm install opusscript`
|
||||||
4. Code your heart out!
|
4. Code your heart out!
|
||||||
5. Run `npm test` to run ESLint and ensure any JSDoc changes are valid
|
5. Run `npm test` to run ESLint and ensure any JSDoc changes are valid
|
||||||
6. [Submit a pull request](https://github.com/hydrabolt/discord.js/compare)
|
6. [Submit a pull request](https://github.com/discordjs/discord.js/compare)
|
||||||
|
|||||||
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
|||||||
[submodule "typings"]
|
[submodule "typings"]
|
||||||
path = typings
|
path = typings
|
||||||
url = https://github.com/zajrik/discord.js-typings
|
url = https://github.com/discordjs/discord.js-typings
|
||||||
|
|||||||
12
README.md
12
README.md
@@ -8,8 +8,8 @@
|
|||||||
<a href="https://discord.gg/bRCvFy9"><img src="https://discordapp.com/api/guilds/222078108977594368/embed.png" alt="Discord server" /></a>
|
<a href="https://discord.gg/bRCvFy9"><img src="https://discordapp.com/api/guilds/222078108977594368/embed.png" alt="Discord server" /></a>
|
||||||
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/v/discord.js.svg?maxAge=3600" alt="NPM version" /></a>
|
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/v/discord.js.svg?maxAge=3600" alt="NPM version" /></a>
|
||||||
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/dt/discord.js.svg?maxAge=3600" alt="NPM downloads" /></a>
|
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/dt/discord.js.svg?maxAge=3600" alt="NPM downloads" /></a>
|
||||||
<a href="https://travis-ci.org/hydrabolt/discord.js"><img src="https://travis-ci.org/hydrabolt/discord.js.svg" alt="Build status" /></a>
|
<a href="https://travis-ci.org/discordjs/discord.js"><img src="https://travis-ci.org/discordjs/discord.js.svg" alt="Build status" /></a>
|
||||||
<a href="https://david-dm.org/hydrabolt/discord.js"><img src="https://img.shields.io/david/hydrabolt/discord.js.svg?maxAge=3600" alt="Dependencies" /></a>
|
<a href="https://david-dm.org/discordjs/discord.js"><img src="https://img.shields.io/david/discordjs/discord.js.svg?maxAge=3600" alt="Dependencies" /></a>
|
||||||
<a href="https://www.patreon.com/discordjs"><img src="https://img.shields.io/badge/donate-patreon-F96854.svg" alt="Patreon" /></a>
|
<a href="https://www.patreon.com/discordjs"><img src="https://img.shields.io/badge/donate-patreon-F96854.svg" alt="Patreon" /></a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
@@ -67,21 +67,21 @@ client.login('your token');
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
* [Website](https://discord.js.org/) ([source](https://github.com/hydrabolt/discord.js-site))
|
* [Website](https://discord.js.org/) ([source](https://github.com/discordjs/website))
|
||||||
* [Documentation](https://discord.js.org/#/docs)
|
* [Documentation](https://discord.js.org/#/docs)
|
||||||
* [Discord.js Discord server](https://discord.gg/bRCvFy9)
|
* [Discord.js Discord server](https://discord.gg/bRCvFy9)
|
||||||
* [Discord API Discord server](https://discord.gg/discord-api)
|
* [Discord API Discord server](https://discord.gg/discord-api)
|
||||||
* [GitHub](https://github.com/hydrabolt/discord.js)
|
* [GitHub](https://github.com/discordjs/discord.js)
|
||||||
* [NPM](https://www.npmjs.com/package/discord.js)
|
* [NPM](https://www.npmjs.com/package/discord.js)
|
||||||
* [Related libraries](https://discordapi.com/unofficial/libs.html)
|
* [Related libraries](https://discordapi.com/unofficial/libs.html)
|
||||||
|
|
||||||
### Extensions
|
### Extensions
|
||||||
* [discord-rpc](https://www.npmjs.com/package/discord-rpc) ([github](https://github.com/devsnek/discord-rpc))
|
* [discord-rpc](https://www.npmjs.com/package/discord-rpc) ([github](https://github.com/discordjs/RPC))
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
Before creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the
|
Before creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the
|
||||||
[documentation](https://discord.js.org/#/docs).
|
[documentation](https://discord.js.org/#/docs).
|
||||||
See [the contribution guide](https://github.com/hydrabolt/discord.js/blob/master/.github/CONTRIBUTING.md) if you'd like to submit a PR.
|
See [the contribution guide](https://github.com/discordjs/discord.js/blob/master/.github/CONTRIBUTING.md) if you'd like to submit a PR.
|
||||||
|
|
||||||
## Help
|
## Help
|
||||||
If you don't understand something in the documentation, you are experiencing problems, or you just need a gentle
|
If you don't understand something in the documentation, you are experiencing problems, or you just need a gentle
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# Version 11.1.0
|
# Version 11.1.0
|
||||||
v11.1.0 features improved voice and gateway stability, as well as support for new features such as audit logs and searching for messages.
|
v11.1.0 features improved voice and gateway stability, as well as support for new features such as audit logs and searching for messages.
|
||||||
See [the changelog](https://github.com/hydrabolt/discord.js/releases/tag/11.1.0) for a full list of changes, including
|
See [the changelog](https://github.com/discordjs/discord.js/releases/tag/11.1.0) for a full list of changes, including
|
||||||
information about deprecations.
|
information about deprecations.
|
||||||
|
|
||||||
# Version 11
|
# Version 11
|
||||||
Version 11 contains loads of new and improved features, optimisations, and bug fixes.
|
Version 11 contains loads of new and improved features, optimisations, and bug fixes.
|
||||||
See [the changelog](https://github.com/hydrabolt/discord.js/releases/tag/11.0.0) for a full list of changes.
|
See [the changelog](https://github.com/discordjs/discord.js/releases/tag/11.0.0) for a full list of changes.
|
||||||
|
|
||||||
## Significant additions
|
## Significant additions
|
||||||
* Message Reactions and Embeds (rich text)
|
* Message Reactions and Embeds (rich text)
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
<a href="https://discord.gg/bRCvFy9"><img src="https://discordapp.com/api/guilds/222078108977594368/embed.png" alt="Discord server" /></a>
|
<a href="https://discord.gg/bRCvFy9"><img src="https://discordapp.com/api/guilds/222078108977594368/embed.png" alt="Discord server" /></a>
|
||||||
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/v/discord.js.svg?maxAge=3600" alt="NPM version" /></a>
|
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/v/discord.js.svg?maxAge=3600" alt="NPM version" /></a>
|
||||||
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/dt/discord.js.svg?maxAge=3600" alt="NPM downloads" /></a>
|
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/dt/discord.js.svg?maxAge=3600" alt="NPM downloads" /></a>
|
||||||
<a href="https://travis-ci.org/hydrabolt/discord.js"><img src="https://travis-ci.org/hydrabolt/discord.js.svg" alt="Build status" /></a>
|
<a href="https://travis-ci.org/discordjs/discord.js"><img src="https://travis-ci.org/discordjs/discord.js.svg" alt="Build status" /></a>
|
||||||
<a href="https://david-dm.org/hydrabolt/discord.js"><img src="https://img.shields.io/david/hydrabolt/discord.js.svg?maxAge=3600" alt="Dependencies" /></a>
|
<a href="https://david-dm.org/discordjs/discord.js"><img src="https://img.shields.io/david/discordjs/discord.js.svg?maxAge=3600" alt="Dependencies" /></a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="https://nodei.co/npm/discord.js/"><img src="https://nodei.co/npm/discord.js.png?downloads=true&stars=true" alt="NPM info" /></a>
|
<a href="https://nodei.co/npm/discord.js/"><img src="https://nodei.co/npm/discord.js.png?downloads=true&stars=true" alt="NPM info" /></a>
|
||||||
@@ -68,18 +68,18 @@ client.login('your token');
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
* [Website](https://discord.js.org/) ([source](https://github.com/hydrabolt/discord.js-site))
|
* [Website](https://discord.js.org/) ([source](https://github.com/discordjs/website))
|
||||||
* [Documentation](https://discord.js.org/#/docs)
|
* [Documentation](https://discord.js.org/#/docs)
|
||||||
* [Discord.js server](https://discord.gg/bRCvFy9)
|
* [Discord.js server](https://discord.gg/bRCvFy9)
|
||||||
* [Discord API server](https://discord.gg/rV4BwdK)
|
* [Discord API server](https://discord.gg/rV4BwdK)
|
||||||
* [GitHub](https://github.com/hydrabolt/discord.js)
|
* [GitHub](https://github.com/discordjs/discord.js)
|
||||||
* [NPM](https://www.npmjs.com/package/discord.js)
|
* [NPM](https://www.npmjs.com/package/discord.js)
|
||||||
* [Related libraries](https://discordapi.com/unofficial/libs.html) (see also [discord-rpc](https://www.npmjs.com/package/discord-rpc))
|
* [Related libraries](https://discordapi.com/unofficial/libs.html) (see also [discord-rpc](https://www.npmjs.com/package/discord-rpc))
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
Before creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the
|
Before creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the
|
||||||
[documentation](https://discord.js.org/#/docs).
|
[documentation](https://discord.js.org/#/docs).
|
||||||
See [the contribution guide](https://github.com/hydrabolt/discord.js/blob/master/.github/CONTRIBUTING.md) if you'd like to submit a PR.
|
See [the contribution guide](https://github.com/discordjs/discord.js/blob/master/.github/CONTRIBUTING.md) if you'd like to submit a PR.
|
||||||
|
|
||||||
## Help
|
## Help
|
||||||
If you don't understand something in the documentation, you are experiencing problems, or you just need a gentle
|
If you don't understand something in the documentation, you are experiencing problems, or you just need a gentle
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const Discord = require('discord.js/browser');
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Webpack File
|
### Webpack File
|
||||||
You can obtain your desired version of discord.js' web build from the [webpack branch](https://github.com/hydrabolt/discord.js/tree/webpack) of the GitHub repository.
|
You can obtain your desired version of discord.js' web build from the [webpack branch](https://github.com/discordjs/discord.js/tree/webpack) of the GitHub repository.
|
||||||
There is a file for each branch and version of the library, and the ones ending in `.min.js` are minified to substantially reduce the size of the source code.
|
There is a file for each branch and version of the library, and the ones ending in `.min.js` are minified to substantially reduce the size of the source code.
|
||||||
|
|
||||||
Include the file on the page just as you would any other JS library, like so:
|
Include the file on the page just as you would any other JS library, like so:
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/hydrabolt/discord.js.git"
|
"url": "git+https://github.com/discordjs/discord.js.git"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"discord",
|
"discord",
|
||||||
@@ -27,9 +27,9 @@
|
|||||||
"author": "Amish Shah <amishshah.2k@gmail.com>",
|
"author": "Amish Shah <amishshah.2k@gmail.com>",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/hydrabolt/discord.js/issues"
|
"url": "https://github.com/discordjs/discord.js/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/hydrabolt/discord.js#readme",
|
"homepage": "https://github.com/discordjs/discord.js#readme",
|
||||||
"runkitExampleFilename": "./docs/examples/ping.js",
|
"runkitExampleFilename": "./docs/examples/ping.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pako": "^1.0.0",
|
"pako": "^1.0.0",
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^8.0.0",
|
"@types/node": "^8.0.0",
|
||||||
"discord.js-docgen": "hydrabolt/discord.js-docgen",
|
"discord.js-docgen": "discordjs/docgen",
|
||||||
"eslint": "^4.11.0",
|
"eslint": "^4.11.0",
|
||||||
"jsdoc-strip-async-await": "^0.1.0",
|
"jsdoc-strip-async-await": "^0.1.0",
|
||||||
"json-filter-loader": "^1.0.0",
|
"json-filter-loader": "^1.0.0",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const UserStore = require('../stores/UserStore');
|
|||||||
const ChannelStore = require('../stores/ChannelStore');
|
const ChannelStore = require('../stores/ChannelStore');
|
||||||
const GuildStore = require('../stores/GuildStore');
|
const GuildStore = require('../stores/GuildStore');
|
||||||
const ClientPresenceStore = require('../stores/ClientPresenceStore');
|
const ClientPresenceStore = require('../stores/ClientPresenceStore');
|
||||||
const EmojiStore = require('../stores/EmojiStore');
|
const GuildEmojiStore = require('../stores/GuildEmojiStore');
|
||||||
const { Events, browser } = require('../util/Constants');
|
const { Events, browser } = require('../util/Constants');
|
||||||
const DataResolver = require('../util/DataResolver');
|
const DataResolver = require('../util/DataResolver');
|
||||||
const { Error, TypeError, RangeError } = require('../errors');
|
const { Error, TypeError, RangeError } = require('../errors');
|
||||||
@@ -208,11 +208,11 @@ class Client extends BaseClient {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* All custom emojis that the client has access to, mapped by their IDs
|
* All custom emojis that the client has access to, mapped by their IDs
|
||||||
* @type {EmojiStore<Snowflake, Emoji>}
|
* @type {GuildEmojiStore<Snowflake, GuildEmoji>}
|
||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
get emojis() {
|
get emojis() {
|
||||||
const emojis = new EmojiStore({ client: this });
|
const emojis = new GuildEmojiStore({ client: this });
|
||||||
for (const guild of this.guilds.values()) {
|
for (const guild of this.guilds.values()) {
|
||||||
if (guild.available) for (const emoji of guild.emojis.values()) emojis.set(emoji.id, emoji);
|
if (guild.available) for (const emoji of guild.emojis.values()) emojis.set(emoji.id, emoji);
|
||||||
}
|
}
|
||||||
@@ -287,6 +287,11 @@ class Client extends BaseClient {
|
|||||||
* Obtains an invite from Discord.
|
* Obtains an invite from Discord.
|
||||||
* @param {InviteResolvable} invite Invite code or URL
|
* @param {InviteResolvable} invite Invite code or URL
|
||||||
* @returns {Promise<Invite>}
|
* @returns {Promise<Invite>}
|
||||||
|
* @example
|
||||||
|
* client.fetchInvite('https://discord.gg/bRCvFy9')
|
||||||
|
* .then(invite => {
|
||||||
|
* console.log(`Obtained invite with code: ${invite.code}`);
|
||||||
|
* }).catch(console.error);
|
||||||
*/
|
*/
|
||||||
fetchInvite(invite) {
|
fetchInvite(invite) {
|
||||||
const code = DataResolver.resolveInviteCode(invite);
|
const code = DataResolver.resolveInviteCode(invite);
|
||||||
@@ -299,6 +304,11 @@ class Client extends BaseClient {
|
|||||||
* @param {Snowflake} id ID of the webhook
|
* @param {Snowflake} id ID of the webhook
|
||||||
* @param {string} [token] Token for the webhook
|
* @param {string} [token] Token for the webhook
|
||||||
* @returns {Promise<Webhook>}
|
* @returns {Promise<Webhook>}
|
||||||
|
* @example
|
||||||
|
* client.fetchWebhook('id', 'token')
|
||||||
|
* .then(webhook => {
|
||||||
|
* console.log(`Obtained webhook with name: ${webhook.name}`);
|
||||||
|
* }).catch(console.error);
|
||||||
*/
|
*/
|
||||||
fetchWebhook(id, token) {
|
fetchWebhook(id, token) {
|
||||||
return this.api.webhooks(id, token).get().then(data => new Webhook(this, data));
|
return this.api.webhooks(id, token).get().then(data => new Webhook(this, data));
|
||||||
@@ -307,6 +317,11 @@ class Client extends BaseClient {
|
|||||||
/**
|
/**
|
||||||
* Obtains the available voice regions from Discord.
|
* Obtains the available voice regions from Discord.
|
||||||
* @returns {Collection<string, VoiceRegion>}
|
* @returns {Collection<string, VoiceRegion>}
|
||||||
|
* @example
|
||||||
|
* client.fetchVoiceRegions()
|
||||||
|
* .then(regions => {
|
||||||
|
* console.log(`Available regions are: ${regions.map(region => region.name).join(', ')}`);
|
||||||
|
* }).catch(console.error);
|
||||||
*/
|
*/
|
||||||
fetchVoiceRegions() {
|
fetchVoiceRegions() {
|
||||||
return this.api.voice.regions.get().then(res => {
|
return this.api.voice.regions.get().then(res => {
|
||||||
@@ -323,6 +338,10 @@ class Client extends BaseClient {
|
|||||||
* will be removed from the caches. The default is based on {@link ClientOptions#messageCacheLifetime}
|
* will be removed from the caches. The default is based on {@link ClientOptions#messageCacheLifetime}
|
||||||
* @returns {number} Amount of messages that were removed from the caches,
|
* @returns {number} Amount of messages that were removed from the caches,
|
||||||
* or -1 if the message cache lifetime is unlimited
|
* or -1 if the message cache lifetime is unlimited
|
||||||
|
* @example
|
||||||
|
* // Remove all messages older than 1800 seconds from the messages cache
|
||||||
|
* const amount = client.sweepMessages(1800);
|
||||||
|
* console.log(`Successfully removed ${amount} messages from the cache.`);
|
||||||
*/
|
*/
|
||||||
sweepMessages(lifetime = this.options.messageCacheLifetime) {
|
sweepMessages(lifetime = this.options.messageCacheLifetime) {
|
||||||
if (typeof lifetime !== 'number' || isNaN(lifetime)) {
|
if (typeof lifetime !== 'number' || isNaN(lifetime)) {
|
||||||
@@ -359,6 +378,11 @@ class Client extends BaseClient {
|
|||||||
* Obtains the OAuth Application of the bot from Discord.
|
* Obtains the OAuth Application of the bot from Discord.
|
||||||
* @param {Snowflake} [id='@me'] ID of application to fetch
|
* @param {Snowflake} [id='@me'] ID of application to fetch
|
||||||
* @returns {Promise<ClientApplication>}
|
* @returns {Promise<ClientApplication>}
|
||||||
|
* @example
|
||||||
|
* client.fetchApplication('id')
|
||||||
|
* .then(application => {
|
||||||
|
* console.log(`Obtained application with name: ${application.name}`);
|
||||||
|
* }).catch(console.error);
|
||||||
*/
|
*/
|
||||||
fetchApplication(id = '@me') {
|
fetchApplication(id = '@me') {
|
||||||
return this.api.oauth2.applications(id).get()
|
return this.api.oauth2.applications(id).get()
|
||||||
@@ -374,7 +398,7 @@ class Client extends BaseClient {
|
|||||||
* client.generateInvite(['SEND_MESSAGES', 'MANAGE_GUILD', 'MENTION_EVERYONE'])
|
* client.generateInvite(['SEND_MESSAGES', 'MANAGE_GUILD', 'MENTION_EVERYONE'])
|
||||||
* .then(link => {
|
* .then(link => {
|
||||||
* console.log(`Generated bot invite link: ${link}`);
|
* console.log(`Generated bot invite link: ${link}`);
|
||||||
* });
|
* }).catch(console.error);
|
||||||
*/
|
*/
|
||||||
generateInvite(permissions) {
|
generateInvite(permissions) {
|
||||||
if (permissions) {
|
if (permissions) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class GuildEmojiCreateAction extends Action {
|
|||||||
/**
|
/**
|
||||||
* Emitted whenever a custom emoji is created in a guild.
|
* Emitted whenever a custom emoji is created in a guild.
|
||||||
* @event Client#emojiCreate
|
* @event Client#emojiCreate
|
||||||
* @param {Emoji} emoji The emoji that was created
|
* @param {GuildEmoji} emoji The emoji that was created
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = GuildEmojiCreateAction;
|
module.exports = GuildEmojiCreateAction;
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ class GuildEmojiDeleteAction extends Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emitted whenever a custom guild emoji is deleted.
|
* Emitted whenever a custom emoji is deleted in a guild.
|
||||||
* @event Client#emojiDelete
|
* @event Client#emojiDelete
|
||||||
* @param {Emoji} emoji The emoji that was deleted
|
* @param {GuildEmoji} emoji The emoji that was deleted
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = GuildEmojiDeleteAction;
|
module.exports = GuildEmojiDeleteAction;
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ class GuildEmojiUpdateAction extends Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emitted whenever a custom guild emoji is updated.
|
* Emitted whenever a custom emoji is updated in a guild.
|
||||||
* @event Client#emojiUpdate
|
* @event Client#emojiUpdate
|
||||||
* @param {Emoji} oldEmoji The old emoji
|
* @param {GuildEmoji} oldEmoji The old emoji
|
||||||
* @param {Emoji} newEmoji The new emoji
|
* @param {GuildEmoji} newEmoji The new emoji
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = GuildEmojiUpdateAction;
|
module.exports = GuildEmojiUpdateAction;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class MessageReactionAdd extends Action {
|
|||||||
* Emitted whenever a reaction is added to a message.
|
* Emitted whenever a reaction is added to a message.
|
||||||
* @event Client#messageReactionAdd
|
* @event Client#messageReactionAdd
|
||||||
* @param {MessageReaction} messageReaction The reaction object
|
* @param {MessageReaction} messageReaction The reaction object
|
||||||
* @param {User} user The user that applied the emoji or reaction emoji
|
* @param {User} user The user that applied the guild or reaction emoji
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = MessageReactionAdd;
|
module.exports = MessageReactionAdd;
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ const Messages = {
|
|||||||
|
|
||||||
WEBHOOK_MESSAGE: 'The message was not sent by a webhook.',
|
WEBHOOK_MESSAGE: 'The message was not sent by a webhook.',
|
||||||
|
|
||||||
EMOJI_TYPE: 'Emoji must be a string or Emoji/ReactionEmoji',
|
EMOJI_TYPE: 'Emoji must be a string or GuildEmoji/ReactionEmoji',
|
||||||
|
|
||||||
REACTION_RESOLVE_USER: 'Couldn\'t resolve the user ID to remove from the reaction.',
|
REACTION_RESOLVE_USER: 'Couldn\'t resolve the user ID to remove from the reaction.',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ module.exports = {
|
|||||||
// Stores
|
// Stores
|
||||||
ChannelStore: require('./stores/ChannelStore'),
|
ChannelStore: require('./stores/ChannelStore'),
|
||||||
ClientPresenceStore: require('./stores/ClientPresenceStore'),
|
ClientPresenceStore: require('./stores/ClientPresenceStore'),
|
||||||
EmojiStore: require('./stores/EmojiStore'),
|
|
||||||
GuildChannelStore: require('./stores/GuildChannelStore'),
|
GuildChannelStore: require('./stores/GuildChannelStore'),
|
||||||
|
GuildEmojiStore: require('./stores/GuildEmojiStore'),
|
||||||
GuildMemberStore: require('./stores/GuildMemberStore'),
|
GuildMemberStore: require('./stores/GuildMemberStore'),
|
||||||
GuildStore: require('./stores/GuildStore'),
|
GuildStore: require('./stores/GuildStore'),
|
||||||
ReactionUserStore: require('./stores/ReactionUserStore'),
|
ReactionUserStore: require('./stores/ReactionUserStore'),
|
||||||
@@ -64,6 +64,7 @@ module.exports = {
|
|||||||
Guild: require('./structures/Guild'),
|
Guild: require('./structures/Guild'),
|
||||||
GuildAuditLogs: require('./structures/GuildAuditLogs'),
|
GuildAuditLogs: require('./structures/GuildAuditLogs'),
|
||||||
GuildChannel: require('./structures/GuildChannel'),
|
GuildChannel: require('./structures/GuildChannel'),
|
||||||
|
GuildEmoji: require('./structures/GuildEmoji'),
|
||||||
GuildMember: require('./structures/GuildMember'),
|
GuildMember: require('./structures/GuildMember'),
|
||||||
Invite: require('./structures/Invite'),
|
Invite: require('./structures/Invite'),
|
||||||
Message: require('./structures/Message'),
|
Message: require('./structures/Message'),
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
const Collection = require('../util/Collection');
|
const Collection = require('../util/Collection');
|
||||||
const DataStore = require('./DataStore');
|
const DataStore = require('./DataStore');
|
||||||
const Emoji = require('../structures/Emoji');
|
const GuildEmoji = require('../structures/GuildEmoji');
|
||||||
const ReactionEmoji = require('../structures/ReactionEmoji');
|
const ReactionEmoji = require('../structures/ReactionEmoji');
|
||||||
const DataResolver = require('../util/DataResolver');
|
const DataResolver = require('../util/DataResolver');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores emojis.
|
* Stores guild emojis.
|
||||||
* @private
|
* @private
|
||||||
* @extends {DataStore}
|
* @extends {DataStore}
|
||||||
*/
|
*/
|
||||||
class EmojiStore extends DataStore {
|
class GuildEmojiStore extends DataStore {
|
||||||
constructor(guild, iterable) {
|
constructor(guild, iterable) {
|
||||||
super(guild.client, iterable, Emoji);
|
super(guild.client, iterable, GuildEmoji);
|
||||||
this.guild = guild;
|
this.guild = guild;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,17 +61,17 @@ class EmojiStore extends DataStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data that can be resolved into an Emoji object. This can be:
|
* Data that can be resolved into an GuildEmoji object. This can be:
|
||||||
* * A custom emoji ID
|
* * A custom emoji ID
|
||||||
* * An Emoji object
|
* * A GuildEmoji object
|
||||||
* * A ReactionEmoji object
|
* * A ReactionEmoji object
|
||||||
* @typedef {Snowflake|Emoji|ReactionEmoji} EmojiResolvable
|
* @typedef {Snowflake|GuildEmoji|ReactionEmoji} EmojiResolvable
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves a EmojiResolvable to a Emoji object.
|
* Resolves an EmojiResolvable to an Emoji object.
|
||||||
* @param {EmojiResolvable} emoji The Emoji resolvable to identify
|
* @param {EmojiResolvable} emoji The Emoji resolvable to identify
|
||||||
* @returns {?Emoji}
|
* @returns {?GuildEmoji}
|
||||||
*/
|
*/
|
||||||
resolve(emoji) {
|
resolve(emoji) {
|
||||||
if (emoji instanceof ReactionEmoji) return super.resolve(emoji.id);
|
if (emoji instanceof ReactionEmoji) return super.resolve(emoji.id);
|
||||||
@@ -79,7 +79,7 @@ class EmojiStore extends DataStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves a EmojiResolvable to a Emoji ID string.
|
* Resolves an EmojiResolvable to an Emoji ID string.
|
||||||
* @param {EmojiResolvable} emoji The Emoji resolvable to identify
|
* @param {EmojiResolvable} emoji The Emoji resolvable to identify
|
||||||
* @returns {?Snowflake}
|
* @returns {?Snowflake}
|
||||||
*/
|
*/
|
||||||
@@ -111,4 +111,4 @@ class EmojiStore extends DataStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = EmojiStore;
|
module.exports = GuildEmojiStore;
|
||||||
@@ -1,97 +1,29 @@
|
|||||||
const Collection = require('../util/Collection');
|
|
||||||
const Snowflake = require('../util/Snowflake');
|
|
||||||
const Base = require('./Base');
|
const Base = require('./Base');
|
||||||
const { TypeError } = require('../errors');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a custom emoji.
|
* Represents an emoji, see {@link GuildEmoji} and {@link ReactionEmoji}.
|
||||||
* @extends {Base}
|
* @extends {Base}
|
||||||
*/
|
*/
|
||||||
class Emoji extends Base {
|
class Emoji extends Base {
|
||||||
constructor(client, data, guild) {
|
constructor(client, emoji) {
|
||||||
super(client);
|
super(client);
|
||||||
|
|
||||||
/**
|
|
||||||
* The guild this emoji is part of
|
|
||||||
* @type {Guild}
|
|
||||||
*/
|
|
||||||
this.guild = guild;
|
|
||||||
|
|
||||||
this._patch(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
_patch(data) {
|
|
||||||
/**
|
|
||||||
* The ID of the emoji
|
|
||||||
* @type {Snowflake}
|
|
||||||
*/
|
|
||||||
this.id = data.id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of the emoji
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
this.name = data.name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not this emoji requires colons surrounding it
|
|
||||||
* @type {boolean}
|
|
||||||
*/
|
|
||||||
this.requiresColons = data.require_colons;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether this emoji is managed by an external service
|
|
||||||
* @type {boolean}
|
|
||||||
*/
|
|
||||||
this.managed = data.managed;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this emoji is animated
|
* Whether this emoji is animated
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
this.animated = data.animated;
|
this.animated = emoji.animated;
|
||||||
|
|
||||||
this._roles = data.roles;
|
/**
|
||||||
}
|
* The name of this emoji
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.name = emoji.name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The timestamp the emoji was created at
|
* The ID of this emoji
|
||||||
* @type {number}
|
* @type {?Snowflake}
|
||||||
* @readonly
|
*/
|
||||||
*/
|
this.id = emoji.id;
|
||||||
get createdTimestamp() {
|
|
||||||
return Snowflake.deconstruct(this.id).timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The time the emoji was created at
|
|
||||||
* @type {Date}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
get createdAt() {
|
|
||||||
return new Date(this.createdTimestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A collection of roles this emoji is active for (empty if all), mapped by role ID
|
|
||||||
* @type {Collection<Snowflake, Role>}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
get roles() {
|
|
||||||
const roles = new Collection();
|
|
||||||
for (const role of this._roles) {
|
|
||||||
if (this.guild.roles.has(role)) roles.set(role, this.guild.roles.get(role));
|
|
||||||
}
|
|
||||||
return roles;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The URL to the emoji file
|
|
||||||
* @type {string}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
get url() {
|
|
||||||
return this.client.rest.cdn.Emoji(this.id, this.animated ? 'gif' : 'png');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,148 +32,34 @@ class Emoji extends Base {
|
|||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
get identifier() {
|
get identifier() {
|
||||||
if (this.id) return `${this.name}:${this.id}`;
|
if (this.id) return `${this.animated ? 'a:' : ''}${this.name}:${this.id}`;
|
||||||
return encodeURIComponent(this.name);
|
return encodeURIComponent(this.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data for editing an emoji.
|
* The URL to the emoji file if its a custom emoji
|
||||||
* @typedef {Object} EmojiEditData
|
* @type {?string}
|
||||||
* @property {string} [name] The name of the emoji
|
* @readonly
|
||||||
* @property {Collection<Snowflake, Role>|RoleResolvable[]} [roles] Roles to restrict emoji to
|
|
||||||
*/
|
*/
|
||||||
|
get url() {
|
||||||
/**
|
if (!this.id) return null;
|
||||||
* Edits the emoji.
|
return this.client.rest.cdn.Emoji(this.id, this.animated ? 'gif' : 'png');
|
||||||
* @param {EmojiEditData} data The new data for the emoji
|
|
||||||
* @param {string} [reason] Reason for editing this emoji
|
|
||||||
* @returns {Promise<Emoji>}
|
|
||||||
* @example
|
|
||||||
* // Edit an emoji
|
|
||||||
* emoji.edit({name: 'newemoji'})
|
|
||||||
* .then(e => console.log(`Edited emoji ${e}`))
|
|
||||||
* .catch(console.error);
|
|
||||||
*/
|
|
||||||
edit(data, reason) {
|
|
||||||
return this.client.api.guilds(this.guild.id).emojis(this.id)
|
|
||||||
.patch({ data: {
|
|
||||||
name: data.name,
|
|
||||||
roles: data.roles ? data.roles.map(r => r.id ? r.id : r) : undefined,
|
|
||||||
}, reason })
|
|
||||||
.then(() => this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the name of the emoji.
|
* When concatenated with a string, this automatically returns the text required to form a graphical emoji on Discord
|
||||||
* @param {string} name The new name for the emoji
|
* instead of the Emoji object.
|
||||||
* @param {string} [reason] Reason for changing the emoji's name
|
|
||||||
* @returns {Promise<Emoji>}
|
|
||||||
*/
|
|
||||||
setName(name, reason) {
|
|
||||||
return this.edit({ name }, reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a role to the list of roles that can use this emoji.
|
|
||||||
* @param {Role} role The role to add
|
|
||||||
* @returns {Promise<Emoji>}
|
|
||||||
*/
|
|
||||||
addRestrictedRole(role) {
|
|
||||||
return this.addRestrictedRoles([role]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds multiple roles to the list of roles that can use this emoji.
|
|
||||||
* @param {Collection<Snowflake, Role>|RoleResolvable[]} roles Roles to add
|
|
||||||
* @returns {Promise<Emoji>}
|
|
||||||
*/
|
|
||||||
addRestrictedRoles(roles) {
|
|
||||||
const newRoles = new Collection(this.roles);
|
|
||||||
for (let role of roles instanceof Collection ? roles.values() : roles) {
|
|
||||||
role = this.guild.roles.resolve(role);
|
|
||||||
if (!role) {
|
|
||||||
return Promise.reject(new TypeError('INVALID_TYPE', 'roles',
|
|
||||||
'Array or Collection of Roles or Snowflakes', true));
|
|
||||||
}
|
|
||||||
newRoles.set(role.id, role);
|
|
||||||
}
|
|
||||||
return this.edit({ roles: newRoles });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a role from the list of roles that can use this emoji.
|
|
||||||
* @param {Role} role The role to remove
|
|
||||||
* @returns {Promise<Emoji>}
|
|
||||||
*/
|
|
||||||
removeRestrictedRole(role) {
|
|
||||||
return this.removeRestrictedRoles([role]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes multiple roles from the list of roles that can use this emoji.
|
|
||||||
* @param {Collection<Snowflake, Role>|RoleResolvable[]} roles Roles to remove
|
|
||||||
* @returns {Promise<Emoji>}
|
|
||||||
*/
|
|
||||||
removeRestrictedRoles(roles) {
|
|
||||||
const newRoles = new Collection(this.roles);
|
|
||||||
for (let role of roles instanceof Collection ? roles.values() : roles) {
|
|
||||||
role = this.guild.roles.resolve(role);
|
|
||||||
if (!role) {
|
|
||||||
return Promise.reject(new TypeError('INVALID_TYPE', 'roles',
|
|
||||||
'Array or Collection of Roles or Snowflakes', true));
|
|
||||||
}
|
|
||||||
if (newRoles.has(role.id)) newRoles.delete(role.id);
|
|
||||||
}
|
|
||||||
return this.edit({ roles: newRoles });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When concatenated with a string, this automatically concatenates the emoji's mention instead of the Emoji object.
|
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
* @example
|
* @example
|
||||||
* // Send an emoji:
|
* // Send a custom emoji from a guild:
|
||||||
* const emoji = guild.emojis.first();
|
* const emoji = guild.emojis.first();
|
||||||
* msg.reply(`Hello! ${emoji}`);
|
* msg.reply(`Hello! ${emoji}`);
|
||||||
|
* @example
|
||||||
|
* // Send the emoji used in a reaction to the channel the reaction is part of
|
||||||
|
* reaction.message.channel.send(`The emoji used was: ${reaction.emoji}`);
|
||||||
*/
|
*/
|
||||||
toString() {
|
toString() {
|
||||||
if (!this.id || !this.requiresColons) {
|
return this.id ? `<${this.animated ? 'a' : ''}:${this.name}:${this.id}>` : this.name;
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `<${this.animated ? 'a' : ''}:${this.name}:${this.id}>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the emoji.
|
|
||||||
* @param {string} [reason] Reason for deleting the emoji
|
|
||||||
* @returns {Promise<Emoji>}
|
|
||||||
*/
|
|
||||||
delete(reason) {
|
|
||||||
return this.client.api.guilds(this.guild.id).emojis(this.id).delete({ reason })
|
|
||||||
.then(() => this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether this emoji is the same as another one.
|
|
||||||
* @param {Emoji|Object} other The emoji to compare it to
|
|
||||||
* @returns {boolean} Whether the emoji is equal to the given emoji or not
|
|
||||||
*/
|
|
||||||
equals(other) {
|
|
||||||
if (other instanceof Emoji) {
|
|
||||||
return (
|
|
||||||
other.id === this.id &&
|
|
||||||
other.name === this.name &&
|
|
||||||
other.managed === this.managed &&
|
|
||||||
other.requiresColons === this.requiresColons &&
|
|
||||||
other._roles === this._roles
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
other.id === this.id &&
|
|
||||||
other.name === this.name &&
|
|
||||||
other._roles === this._roles
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const Snowflake = require('../util/Snowflake');
|
|||||||
const Shared = require('./shared');
|
const Shared = require('./shared');
|
||||||
const GuildMemberStore = require('../stores/GuildMemberStore');
|
const GuildMemberStore = require('../stores/GuildMemberStore');
|
||||||
const RoleStore = require('../stores/RoleStore');
|
const RoleStore = require('../stores/RoleStore');
|
||||||
const EmojiStore = require('../stores/EmojiStore');
|
const GuildEmojiStore = require('../stores/GuildEmojiStore');
|
||||||
const GuildChannelStore = require('../stores/GuildChannelStore');
|
const GuildChannelStore = require('../stores/GuildChannelStore');
|
||||||
const PresenceStore = require('../stores/PresenceStore');
|
const PresenceStore = require('../stores/PresenceStore');
|
||||||
const Base = require('./Base');
|
const Base = require('./Base');
|
||||||
@@ -218,9 +218,9 @@ class Guild extends Base {
|
|||||||
if (!this.emojis) {
|
if (!this.emojis) {
|
||||||
/**
|
/**
|
||||||
* A collection of emojis that are in this guild. The key is the emoji's ID, the value is the emoji.
|
* A collection of emojis that are in this guild. The key is the emoji's ID, the value is the emoji.
|
||||||
* @type {EmojiStore<Snowflake, Emoji>}
|
* @type {GuildEmojiStore<Snowflake, GuildEmoji>}
|
||||||
*/
|
*/
|
||||||
this.emojis = new EmojiStore(this);
|
this.emojis = new GuildEmojiStore(this);
|
||||||
if (data.emojis) for (const emoji of data.emojis) this.emojis.add(emoji);
|
if (data.emojis) for (const emoji of data.emojis) this.emojis.add(emoji);
|
||||||
} else {
|
} else {
|
||||||
this.client.actions.GuildEmojisUpdate.handle({
|
this.client.actions.GuildEmojisUpdate.handle({
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ class GuildAuditLogs {
|
|||||||
* * An invite
|
* * An invite
|
||||||
* * A webhook
|
* * A webhook
|
||||||
* * An object where the keys represent either the new value or the old value
|
* * An object where the keys represent either the new value or the old value
|
||||||
* @typedef {?Object|Guild|User|Role|Emoji|Invite|Webhook} AuditLogEntryTarget
|
* @typedef {?Object|Guild|User|Role|GuildEmoji|Invite|Webhook} AuditLogEntryTarget
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -92,31 +92,16 @@ class GuildChannel extends Channel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the overall set of permissions for a user in this channel, taking into account roles and permission
|
* Gets the overall set of permissions for a member or role in this channel, taking into account channel overwrites.
|
||||||
* overwrites.
|
* @param {GuildMemberResolvable|RoleResolvable} memberOrRole The member or role to obtain the overall permissions for
|
||||||
* @param {GuildMemberResolvable} member The user that you want to obtain the overall permissions for
|
|
||||||
* @returns {?Permissions}
|
* @returns {?Permissions}
|
||||||
*/
|
*/
|
||||||
permissionsFor(member) {
|
permissionsFor(memberOrRole) {
|
||||||
member = this.guild.members.resolve(member);
|
const member = this.guild.members.resolve(memberOrRole);
|
||||||
if (!member) return null;
|
if (member) return this.memberPermissions(member);
|
||||||
if (member.id === this.guild.ownerID) return new Permissions(Permissions.ALL).freeze();
|
const role = this.guild.roles.resolve(memberOrRole);
|
||||||
|
if (role) return this.rolePermissions(role);
|
||||||
const roles = member.roles;
|
return null;
|
||||||
const permissions = new Permissions(roles.map(role => role.permissions));
|
|
||||||
|
|
||||||
if (permissions.has(Permissions.FLAGS.ADMINISTRATOR)) return new Permissions(Permissions.ALL).freeze();
|
|
||||||
|
|
||||||
const overwrites = this.overwritesFor(member, true, roles);
|
|
||||||
|
|
||||||
return permissions
|
|
||||||
.remove(overwrites.everyone ? overwrites.everyone.denied : 0)
|
|
||||||
.add(overwrites.everyone ? overwrites.everyone.allowed : 0)
|
|
||||||
.remove(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.denied) : 0)
|
|
||||||
.add(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.allowed) : 0)
|
|
||||||
.remove(overwrites.member ? overwrites.member.denied : 0)
|
|
||||||
.add(overwrites.member ? overwrites.member.allowed : 0)
|
|
||||||
.freeze();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
overwritesFor(member, verified = false, roles = null) {
|
overwritesFor(member, verified = false, roles = null) {
|
||||||
@@ -145,6 +130,52 @@ class GuildChannel extends Channel {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the overall set of permissions for a member in this channel, taking into account channel overwrites.
|
||||||
|
* @param {GuildMember} member The member to obtain the overall permissions for
|
||||||
|
* @returns {Permissions}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
memberPermissions(member) {
|
||||||
|
if (member.id === this.guild.ownerID) return new Permissions(Permissions.ALL).freeze();
|
||||||
|
|
||||||
|
const roles = member.roles;
|
||||||
|
const permissions = new Permissions(roles.map(role => role.permissions));
|
||||||
|
|
||||||
|
if (permissions.has(Permissions.FLAGS.ADMINISTRATOR)) return new Permissions(Permissions.ALL).freeze();
|
||||||
|
|
||||||
|
const overwrites = this.overwritesFor(member, true, roles);
|
||||||
|
|
||||||
|
return permissions
|
||||||
|
.remove(overwrites.everyone ? overwrites.everyone.denied : 0)
|
||||||
|
.add(overwrites.everyone ? overwrites.everyone.allowed : 0)
|
||||||
|
.remove(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.denied) : 0)
|
||||||
|
.add(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.allowed) : 0)
|
||||||
|
.remove(overwrites.member ? overwrites.member.denied : 0)
|
||||||
|
.add(overwrites.member ? overwrites.member.allowed : 0)
|
||||||
|
.freeze();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the overall set of permissions for a role in this channel, taking into account channel overwrites.
|
||||||
|
* @param {Role} role The role to obtain the overall permissions for
|
||||||
|
* @returns {Permissions}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
rolePermissions(role) {
|
||||||
|
if (role.permissions.has(Permissions.FLAGS.ADMINISTRATOR)) return new Permissions(Permissions.ALL).freeze();
|
||||||
|
|
||||||
|
const everyoneOverwrites = this.permissionOverwrites.get(this.guild.id);
|
||||||
|
const roleOverwrites = this.permissionOverwrites.get(role.id);
|
||||||
|
|
||||||
|
return role.permissions
|
||||||
|
.remove(everyoneOverwrites ? everyoneOverwrites.denied : 0)
|
||||||
|
.add(everyoneOverwrites ? everyoneOverwrites.allowed : 0)
|
||||||
|
.remove(roleOverwrites ? roleOverwrites.denied : 0)
|
||||||
|
.add(roleOverwrites ? roleOverwrites.allowed : 0)
|
||||||
|
.freeze();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object mapping permission flags to `true` (enabled), `null` (default) or `false` (disabled).
|
* An object mapping permission flags to `true` (enabled), `null` (default) or `false` (disabled).
|
||||||
* ```js
|
* ```js
|
||||||
|
|||||||
197
src/structures/GuildEmoji.js
Normal file
197
src/structures/GuildEmoji.js
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
const Collection = require('../util/Collection');
|
||||||
|
const Snowflake = require('../util/Snowflake');
|
||||||
|
const Emoji = require('./Emoji');
|
||||||
|
const { TypeError } = require('../errors');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom emoji.
|
||||||
|
* @extends {Emoji}
|
||||||
|
*/
|
||||||
|
class GuildEmoji extends Emoji {
|
||||||
|
constructor(client, data, guild) {
|
||||||
|
super(client, data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The guild this emoji is part of
|
||||||
|
* @type {Guild}
|
||||||
|
*/
|
||||||
|
this.guild = guild;
|
||||||
|
|
||||||
|
this._patch(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
_patch(data) {
|
||||||
|
this.name = data.name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not this emoji requires colons surrounding it
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
this.requiresColons = data.require_colons;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this emoji is managed by an external service
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
this.managed = data.managed;
|
||||||
|
|
||||||
|
this._roles = data.roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The timestamp the emoji was created at
|
||||||
|
* @type {number}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get createdTimestamp() {
|
||||||
|
return Snowflake.deconstruct(this.id).timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time the emoji was created at
|
||||||
|
* @type {Date}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get createdAt() {
|
||||||
|
return new Date(this.createdTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A collection of roles this emoji is active for (empty if all), mapped by role ID
|
||||||
|
* @type {Collection<Snowflake, Role>}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get roles() {
|
||||||
|
const roles = new Collection();
|
||||||
|
for (const role of this._roles) {
|
||||||
|
if (this.guild.roles.has(role)) roles.set(role, this.guild.roles.get(role));
|
||||||
|
}
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data for editing an emoji.
|
||||||
|
* @typedef {Object} GuildEmojiEditData
|
||||||
|
* @property {string} [name] The name of the emoji
|
||||||
|
* @property {Collection<Snowflake, Role>|RoleResolvable[]} [roles] Roles to restrict emoji to
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edits the emoji.
|
||||||
|
* @param {Guild} data The new data for the emoji
|
||||||
|
* @param {string} [reason] Reason for editing this emoji
|
||||||
|
* @returns {Promise<GuildEmoji>}
|
||||||
|
* @example
|
||||||
|
* // Edit an emoji
|
||||||
|
* emoji.edit({name: 'newemoji'})
|
||||||
|
* .then(e => console.log(`Edited emoji ${e}`))
|
||||||
|
* .catch(console.error);
|
||||||
|
*/
|
||||||
|
edit(data, reason) {
|
||||||
|
return this.client.api.guilds(this.guild.id).emojis(this.id)
|
||||||
|
.patch({ data: {
|
||||||
|
name: data.name,
|
||||||
|
roles: data.roles ? data.roles.map(r => r.id ? r.id : r) : undefined,
|
||||||
|
}, reason })
|
||||||
|
.then(() => this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the name of the emoji.
|
||||||
|
* @param {string} name The new name for the emoji
|
||||||
|
* @param {string} [reason] Reason for changing the emoji's name
|
||||||
|
* @returns {Promise<GuildEmoji>}
|
||||||
|
*/
|
||||||
|
setName(name, reason) {
|
||||||
|
return this.edit({ name }, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a role to the list of roles that can use this emoji.
|
||||||
|
* @param {Role} role The role to add
|
||||||
|
* @returns {Promise<GuildEmoji>}
|
||||||
|
*/
|
||||||
|
addRestrictedRole(role) {
|
||||||
|
return this.addRestrictedRoles([role]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds multiple roles to the list of roles that can use this emoji.
|
||||||
|
* @param {Collection<Snowflake, Role>|RoleResolvable[]} roles Roles to add
|
||||||
|
* @returns {Promise<GuildEmoji>}
|
||||||
|
*/
|
||||||
|
addRestrictedRoles(roles) {
|
||||||
|
const newRoles = new Collection(this.roles);
|
||||||
|
for (let role of roles instanceof Collection ? roles.values() : roles) {
|
||||||
|
role = this.guild.roles.resolve(role);
|
||||||
|
if (!role) {
|
||||||
|
return Promise.reject(new TypeError('INVALID_TYPE', 'roles',
|
||||||
|
'Array or Collection of Roles or Snowflakes', true));
|
||||||
|
}
|
||||||
|
newRoles.set(role.id, role);
|
||||||
|
}
|
||||||
|
return this.edit({ roles: newRoles });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a role from the list of roles that can use this emoji.
|
||||||
|
* @param {Role} role The role to remove
|
||||||
|
* @returns {Promise<GuildEmoji>}
|
||||||
|
*/
|
||||||
|
removeRestrictedRole(role) {
|
||||||
|
return this.removeRestrictedRoles([role]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes multiple roles from the list of roles that can use this emoji.
|
||||||
|
* @param {Collection<Snowflake, Role>|RoleResolvable[]} roles Roles to remove
|
||||||
|
* @returns {Promise<GuildEmoji>}
|
||||||
|
*/
|
||||||
|
removeRestrictedRoles(roles) {
|
||||||
|
const newRoles = new Collection(this.roles);
|
||||||
|
for (let role of roles instanceof Collection ? roles.values() : roles) {
|
||||||
|
role = this.guild.roles.resolve(role);
|
||||||
|
if (!role) {
|
||||||
|
return Promise.reject(new TypeError('INVALID_TYPE', 'roles',
|
||||||
|
'Array or Collection of Roles or Snowflakes', true));
|
||||||
|
}
|
||||||
|
if (newRoles.has(role.id)) newRoles.delete(role.id);
|
||||||
|
}
|
||||||
|
return this.edit({ roles: newRoles });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the emoji.
|
||||||
|
* @param {string} [reason] Reason for deleting the emoji
|
||||||
|
* @returns {Promise<GuildEmoji>}
|
||||||
|
*/
|
||||||
|
delete(reason) {
|
||||||
|
return this.client.api.guilds(this.guild.id).emojis(this.id).delete({ reason })
|
||||||
|
.then(() => this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this emoji is the same as another one.
|
||||||
|
* @param {GuildEmoji|Object} other The emoji to compare it to
|
||||||
|
* @returns {boolean} Whether the emoji is equal to the given emoji or not
|
||||||
|
*/
|
||||||
|
equals(other) {
|
||||||
|
if (other instanceof GuildEmoji) {
|
||||||
|
return (
|
||||||
|
other.id === this.id &&
|
||||||
|
other.name === this.name &&
|
||||||
|
other.managed === this.managed &&
|
||||||
|
other.requiresColons === this.requiresColons &&
|
||||||
|
other._roles === this._roles
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
other.id === this.id &&
|
||||||
|
other.name === this.name &&
|
||||||
|
other._roles === this._roles
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = GuildEmoji;
|
||||||
@@ -295,9 +295,9 @@ class GuildMember extends Base {
|
|||||||
* @returns {?Permissions}
|
* @returns {?Permissions}
|
||||||
*/
|
*/
|
||||||
permissionsIn(channel) {
|
permissionsIn(channel) {
|
||||||
channel = this.client.channels.resolve(channel);
|
channel = this.guild.channels.resolve(channel);
|
||||||
if (!channel || !channel.guild) throw new Error('GUILD_CHANNEL_RESOLVE');
|
if (!channel) throw new Error('GUILD_CHANNEL_RESOLVE');
|
||||||
return channel.permissionsFor(this);
|
return channel.memberPermissions(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ class MessageEmbed {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the file to upload alongside the embed. This file can be accessed via `attachment://fileName.extension` when
|
* Sets the file to upload alongside the embed. This file can be accessed via `attachment://fileName.extension` when
|
||||||
* setting an embed image or author/footer icons. Only one file may be attached.
|
* setting an embed image or author/footer icons. Multiple files can be attached.
|
||||||
* @param {Array<FileOptions|string|MessageAttachment>} files Files to attach
|
* @param {Array<FileOptions|string|MessageAttachment>} files Files to attach
|
||||||
* @returns {MessageEmbed}
|
* @returns {MessageEmbed}
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const Emoji = require('./Emoji');
|
const GuildEmoji = require('./GuildEmoji');
|
||||||
const ReactionEmoji = require('./ReactionEmoji');
|
const ReactionEmoji = require('./ReactionEmoji');
|
||||||
const ReactionUserStore = require('../stores/ReactionUserStore');
|
const ReactionUserStore = require('../stores/ReactionUserStore');
|
||||||
|
|
||||||
@@ -31,18 +31,18 @@ class MessageReaction {
|
|||||||
*/
|
*/
|
||||||
this.users = new ReactionUserStore(client, undefined, this);
|
this.users = new ReactionUserStore(client, undefined, this);
|
||||||
|
|
||||||
this._emoji = new ReactionEmoji(this, data.emoji.name, data.emoji.id);
|
this._emoji = new ReactionEmoji(this, data.emoji);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The emoji of this reaction, either an Emoji object for known custom emojis, or a ReactionEmoji
|
* The emoji of this reaction, either an GuildEmoji object for known custom emojis, or a ReactionEmoji
|
||||||
* object which has fewer properties. Whatever the prototype of the emoji, it will still have
|
* object which has fewer properties. Whatever the prototype of the emoji, it will still have
|
||||||
* `name`, `id`, `identifier` and `toString()`
|
* `name`, `id`, `identifier` and `toString()`
|
||||||
* @type {Emoji|ReactionEmoji}
|
* @type {GuildEmoji|ReactionEmoji}
|
||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
get emoji() {
|
get emoji() {
|
||||||
if (this._emoji instanceof Emoji) return this._emoji;
|
if (this._emoji instanceof GuildEmoji) return this._emoji;
|
||||||
// Check to see if the emoji has become known to the client
|
// Check to see if the emoji has become known to the client
|
||||||
if (this._emoji.id) {
|
if (this._emoji.id) {
|
||||||
const emojis = this.message.client.emojis;
|
const emojis = this.message.client.emojis;
|
||||||
|
|||||||
@@ -1,49 +1,19 @@
|
|||||||
|
const Emoji = require('./Emoji');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a limited emoji set used for both custom and unicode emojis. Custom emojis
|
* Represents a limited emoji set used for both custom and unicode emojis. Custom emojis
|
||||||
* will use this class opposed to the Emoji class when the client doesn't know enough
|
* will use this class opposed to the Emoji class when the client doesn't know enough
|
||||||
* information about them.
|
* information about them.
|
||||||
|
* @extends {Emoji}
|
||||||
*/
|
*/
|
||||||
class ReactionEmoji {
|
class ReactionEmoji extends Emoji {
|
||||||
constructor(reaction, name, id) {
|
constructor(reaction, emoji) {
|
||||||
|
super(reaction.message.client, emoji);
|
||||||
/**
|
/**
|
||||||
* The message reaction this emoji refers to
|
* The message reaction this emoji refers to
|
||||||
* @type {MessageReaction}
|
* @type {MessageReaction}
|
||||||
*/
|
*/
|
||||||
this.reaction = reaction;
|
this.reaction = reaction;
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of this reaction emoji
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
this.name = name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The ID of this reaction emoji
|
|
||||||
* @type {?Snowflake}
|
|
||||||
*/
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The identifier of this emoji, used for message reactions
|
|
||||||
* @type {string}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
get identifier() {
|
|
||||||
if (this.id) return `${this.name}:${this.id}`;
|
|
||||||
return encodeURIComponent(this.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When concatenated with a string, this automatically returns the text required to form a graphical emoji on Discord
|
|
||||||
* instead of the ReactionEmoji object.
|
|
||||||
* @returns {string}
|
|
||||||
* @example
|
|
||||||
* // Send the emoji used in a reaction to the channel the reaction is part of
|
|
||||||
* reaction.message.channel.send(`The emoji used was: ${reaction.emoji}`);
|
|
||||||
*/
|
|
||||||
toString() {
|
|
||||||
return this.id ? `<:${this.name}:${this.id}>` : this.name;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -195,6 +195,18 @@ class Role extends Base {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `channel.permissionsFor(role)`. Returns permissions for a role in a guild channel,
|
||||||
|
* taking into account permission overwrites.
|
||||||
|
* @param {ChannelResolvable} channel The guild channel to use as context
|
||||||
|
* @returns {?Permissions}
|
||||||
|
*/
|
||||||
|
permissionsIn(channel) {
|
||||||
|
channel = this.guild.channels.resolve(channel);
|
||||||
|
if (!channel) throw new Error('GUILD_CHANNEL_RESOLVE');
|
||||||
|
return channel.rolePermissions(this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a new name for the role.
|
* Sets a new name for the role.
|
||||||
* @param {string} name The new name of the role
|
* @param {string} name The new name of the role
|
||||||
|
|||||||
@@ -7,19 +7,19 @@ const { RangeError } = require('../errors');
|
|||||||
*/
|
*/
|
||||||
class Permissions {
|
class Permissions {
|
||||||
/**
|
/**
|
||||||
* @param {number|PermissionResolvable[]} permissions Permissions or bitfield to read from
|
* @param {PermissionResolvable} permissions Permission(s) to read from
|
||||||
*/
|
*/
|
||||||
constructor(permissions) {
|
constructor(permissions) {
|
||||||
/**
|
/**
|
||||||
* Bitfield of the packed permissions
|
* Bitfield of the packed permissions
|
||||||
* @type {number}
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
this.bitfield = typeof permissions === 'number' ? permissions : this.constructor.resolve(permissions);
|
this.bitfield = this.constructor.resolve(permissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the bitfield has a permission, or multiple permissions.
|
* Checks whether the bitfield has a permission, or multiple permissions.
|
||||||
* @param {PermissionResolvable|PermissionResolvable[]} permission Permission(s) to check for
|
* @param {PermissionResolvable} permission Permission(s) to check for
|
||||||
* @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
|
* @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
@@ -32,11 +32,12 @@ class Permissions {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all given permissions that are missing from the bitfield.
|
* Gets all given permissions that are missing from the bitfield.
|
||||||
* @param {PermissionResolvable[]} permissions Permissions to check for
|
* @param {PermissionResolvable} permissions Permission(s) to check for
|
||||||
* @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
|
* @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
|
||||||
* @returns {PermissionResolvable[]}
|
* @returns {string[]}
|
||||||
*/
|
*/
|
||||||
missing(permissions, checkAdmin = true) {
|
missing(permissions, checkAdmin = true) {
|
||||||
|
if (!(permissions instanceof Array)) permissions = new this.constructor(permissions).toArray(false);
|
||||||
return permissions.filter(p => !this.has(p, checkAdmin));
|
return permissions.filter(p => !this.has(p, checkAdmin));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,17 +93,32 @@ class Permissions {
|
|||||||
return serialized;
|
return serialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an {@link Array} of permission names (such as `VIEW_CHANNEL`) based on the permissions available.
|
||||||
|
* @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
|
||||||
|
* @returns {string[]}
|
||||||
|
*/
|
||||||
|
toArray(checkAdmin = true) {
|
||||||
|
return Object.keys(this.constructor.FLAGS).filter(perm => this.has(perm, checkAdmin));
|
||||||
|
}
|
||||||
|
|
||||||
|
*[Symbol.iterator]() {
|
||||||
|
const keys = this.toArray();
|
||||||
|
while (keys.length) yield keys.shift();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data that can be resolved to give a permission number. This can be:
|
* Data that can be resolved to give a permission number. This can be:
|
||||||
* * A string (see {@link Permissions.FLAGS})
|
* * A string (see {@link Permissions.FLAGS})
|
||||||
* * A permission number
|
* * A permission number
|
||||||
* * An instance of Permissions
|
* * An instance of Permissions
|
||||||
* @typedef {string|number|Permissions} PermissionResolvable
|
* * An Array of PermissionResolvable
|
||||||
|
* @typedef {string|number|Permissions|PermissionResolvable[]} PermissionResolvable
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves permissions to their numeric form.
|
* Resolves permissions to their numeric form.
|
||||||
* @param {PermissionResolvable|PermissionResolvable[]} permission - Permission(s) to resolve
|
* @param {PermissionResolvable} permission - Permission(s) to resolve
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
static resolve(permission) {
|
static resolve(permission) {
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class Structures {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const structures = {
|
const structures = {
|
||||||
Emoji: require('../structures/Emoji'),
|
GuildEmoji: require('../structures/GuildEmoji'),
|
||||||
DMChannel: require('../structures/DMChannel'),
|
DMChannel: require('../structures/DMChannel'),
|
||||||
GroupDMChannel: require('../structures/GroupDMChannel'),
|
GroupDMChannel: require('../structures/GroupDMChannel'),
|
||||||
TextChannel: require('../structures/TextChannel'),
|
TextChannel: require('../structures/TextChannel'),
|
||||||
|
|||||||
2
typings
2
typings
Submodule typings updated: 0b5b13f4a5...895af7f3da
Reference in New Issue
Block a user