Guild.js (40795B)
1 'use strict'; 2 3 const Base = require('./Base'); 4 const GuildAuditLogs = require('./GuildAuditLogs'); 5 const GuildPreview = require('./GuildPreview'); 6 const Integration = require('./Integration'); 7 const Invite = require('./Invite'); 8 const VoiceRegion = require('./VoiceRegion'); 9 const Webhook = require('./Webhook'); 10 const GuildChannelManager = require('../managers/GuildChannelManager'); 11 const GuildEmojiManager = require('../managers/GuildEmojiManager'); 12 const GuildMemberManager = require('../managers/GuildMemberManager'); 13 const PresenceManager = require('../managers/PresenceManager'); 14 const RoleManager = require('../managers/RoleManager'); 15 const VoiceStateManager = require('../managers/VoiceStateManager'); 16 const Collection = require('../util/Collection'); 17 const { 18 ChannelTypes, 19 DefaultMessageNotifications, 20 PartialTypes, 21 VerificationLevels, 22 ExplicitContentFilterLevels, 23 } = require('../util/Constants'); 24 const DataResolver = require('../util/DataResolver'); 25 const Snowflake = require('../util/Snowflake'); 26 const SystemChannelFlags = require('../util/SystemChannelFlags'); 27 const Util = require('../util/Util'); 28 29 /** 30 * Represents a guild (or a server) on Discord. 31 * <info>It's recommended to see if a guild is available before performing operations or reading data from it. You can 32 * check this with `guild.available`.</info> 33 * @extends {Base} 34 */ 35 class Guild extends Base { 36 /** 37 * @param {Client} client The instantiating client 38 * @param {Object} data The data for the guild 39 */ 40 constructor(client, data) { 41 super(client); 42 43 /** 44 * A manager of the members belonging to this guild 45 * @type {GuildMemberManager} 46 */ 47 this.members = new GuildMemberManager(this); 48 49 /** 50 * A manager of the channels belonging to this guild 51 * @type {GuildChannelManager} 52 */ 53 this.channels = new GuildChannelManager(this); 54 55 /** 56 * A manager of the roles belonging to this guild 57 * @type {RoleManager} 58 */ 59 this.roles = new RoleManager(this); 60 61 /** 62 * A manager of the presences belonging to this guild 63 * @type {PresenceManager} 64 */ 65 this.presences = new PresenceManager(this.client); 66 67 /** 68 * A manager of the voice states of this guild 69 * @type {VoiceStateManager} 70 */ 71 this.voiceStates = new VoiceStateManager(this); 72 73 /** 74 * Whether the bot has been removed from the guild 75 * @type {boolean} 76 */ 77 this.deleted = false; 78 79 if (!data) return; 80 if (data.unavailable) { 81 /** 82 * Whether the guild is available to access. If it is not available, it indicates a server outage 83 * @type {boolean} 84 */ 85 this.available = false; 86 87 /** 88 * The Unique ID of the guild, useful for comparisons 89 * @type {Snowflake} 90 */ 91 this.id = data.id; 92 } else { 93 this._patch(data); 94 if (!data.channels) this.available = false; 95 } 96 97 /** 98 * The id of the shard this Guild belongs to. 99 * @type {number} 100 */ 101 this.shardID = data.shardID; 102 } 103 104 /** 105 * The Shard this Guild belongs to. 106 * @type {WebSocketShard} 107 * @readonly 108 */ 109 get shard() { 110 return this.client.ws.shards.get(this.shardID); 111 } 112 113 /** 114 * Sets up the guild. 115 * @param {*} data The raw data of the guild 116 * @private 117 */ 118 _patch(data) { 119 /** 120 * The name of the guild 121 * @type {string} 122 */ 123 this.name = data.name; 124 125 /** 126 * The hash of the guild icon 127 * @type {?string} 128 */ 129 this.icon = data.icon; 130 131 /** 132 * The hash of the guild splash image (VIP only) 133 * @type {?string} 134 */ 135 this.splash = data.splash; 136 137 /** 138 * The region the guild is located in 139 * @type {string} 140 */ 141 this.region = data.region; 142 143 /** 144 * The full amount of members in this guild 145 * @type {number} 146 */ 147 this.memberCount = data.member_count || this.memberCount; 148 149 /** 150 * Whether the guild is "large" (has more than 250 members) 151 * @type {boolean} 152 */ 153 this.large = Boolean('large' in data ? data.large : this.large); 154 155 /** 156 * An array of enabled guild features, here are the possible values: 157 * * ANIMATED_ICON 158 * * BANNER 159 * * COMMERCE 160 * * DISCOVERABLE 161 * * FEATURABLE 162 * * INVITE_SPLASH 163 * * NEWS 164 * * PARTNERED 165 * * PUBLIC 166 * * PUBLIC_DISABLED 167 * * VANITY_URL 168 * * VERIFIED 169 * * VIP_REGIONS 170 * * WELCOME_SCREEN_ENABLED 171 * @typedef {string} Features 172 */ 173 174 /** 175 * An array of guild features partnered guilds have enabled 176 * @type {Features[]} 177 */ 178 this.features = data.features; 179 180 /** 181 * The ID of the application that created this guild (if applicable) 182 * @type {?Snowflake} 183 */ 184 this.applicationID = data.application_id; 185 186 /** 187 * The time in seconds before a user is counted as "away from keyboard" 188 * @type {?number} 189 */ 190 this.afkTimeout = data.afk_timeout; 191 192 /** 193 * The ID of the voice channel where AFK members are moved 194 * @type {?Snowflake} 195 */ 196 this.afkChannelID = data.afk_channel_id; 197 198 /** 199 * The ID of the system channel 200 * @type {?Snowflake} 201 */ 202 this.systemChannelID = data.system_channel_id; 203 204 /** 205 * Whether embedded images are enabled on this guild 206 * @type {boolean} 207 */ 208 this.embedEnabled = data.embed_enabled; 209 210 /** 211 * The type of premium tier: 212 * * 0: NONE 213 * * 1: TIER_1 214 * * 2: TIER_2 215 * * 3: TIER_3 216 * @typedef {number} PremiumTier 217 */ 218 219 /** 220 * The premium tier on this guild 221 * @type {PremiumTier} 222 */ 223 this.premiumTier = data.premium_tier; 224 225 /** 226 * The total number of users currently boosting this server 227 * @type {?number} 228 * @name Guild#premiumSubscriptionCount 229 */ 230 if (typeof data.premium_subscription_count !== 'undefined') { 231 this.premiumSubscriptionCount = data.premium_subscription_count; 232 } 233 234 /** 235 * Whether widget images are enabled on this guild 236 * @type {?boolean} 237 * @name Guild#widgetEnabled 238 */ 239 if (typeof data.widget_enabled !== 'undefined') this.widgetEnabled = data.widget_enabled; 240 241 /** 242 * The widget channel ID, if enabled 243 * @type {?string} 244 * @name Guild#widgetChannelID 245 */ 246 if (typeof data.widget_channel_id !== 'undefined') this.widgetChannelID = data.widget_channel_id; 247 248 /** 249 * The embed channel ID, if enabled 250 * @type {?string} 251 * @name Guild#embedChannelID 252 */ 253 if (typeof data.embed_channel_id !== 'undefined') this.embedChannelID = data.embed_channel_id; 254 255 /** 256 * The verification level of the guild 257 * @type {VerificationLevel} 258 */ 259 this.verificationLevel = VerificationLevels[data.verification_level]; 260 261 /** 262 * The explicit content filter level of the guild 263 * @type {ExplicitContentFilterLevel} 264 */ 265 this.explicitContentFilter = ExplicitContentFilterLevels[data.explicit_content_filter]; 266 267 /** 268 * The required MFA level for the guild 269 * @type {number} 270 */ 271 this.mfaLevel = data.mfa_level; 272 273 /** 274 * The timestamp the client user joined the guild at 275 * @type {number} 276 */ 277 this.joinedTimestamp = data.joined_at ? new Date(data.joined_at).getTime() : this.joinedTimestamp; 278 279 /** 280 * The value set for the guild's default message notifications 281 * @type {DefaultMessageNotifications|number} 282 */ 283 this.defaultMessageNotifications = 284 DefaultMessageNotifications[data.default_message_notifications] || data.default_message_notifications; 285 286 /** 287 * The value set for the guild's system channel flags 288 * @type {Readonly<SystemChannelFlags>} 289 */ 290 this.systemChannelFlags = new SystemChannelFlags(data.system_channel_flags).freeze(); 291 292 /** 293 * The maximum amount of members the guild can have 294 * <info>You will need to fetch the guild using {@link Guild#fetch} if you want to receive this parameter</info> 295 * @type {?number} 296 * @name Guild#maximumMembers 297 */ 298 if (typeof data.max_members !== 'undefined') this.maximumMembers = data.max_members || 250000; 299 300 /** 301 * The maximum amount of presences the guild can have 302 * <info>You will need to fetch the guild using {@link Guild#fetch} if you want to receive this parameter</info> 303 * @type {?number} 304 * @name Guild#maximumPresences 305 */ 306 if (typeof data.max_presences !== 'undefined') this.maximumPresences = data.max_presences || 25000; 307 308 /** 309 * The vanity URL code of the guild, if any 310 * @type {?string} 311 */ 312 this.vanityURLCode = data.vanity_url_code; 313 314 /** 315 * The description of the guild, if any 316 * @type {?string} 317 */ 318 this.description = data.description; 319 320 /** 321 * The hash of the guild banner 322 * @type {?string} 323 */ 324 this.banner = data.banner; 325 326 this.id = data.id; 327 this.available = !data.unavailable; 328 this.features = data.features || this.features || []; 329 330 /** 331 * The ID of the rules channel for the guild 332 * <info>This is only available on guilds with the `PUBLIC` feature</info> 333 * @type {?Snowflake} 334 */ 335 this.rulesChannelID = data.rules_channel_id; 336 337 /** 338 * The ID of the public updates channel for the guild 339 * <info>This is only available on guilds with the `PUBLIC` feature</info> 340 * @type {?Snowflake} 341 */ 342 this.publicUpdatesChannelID = data.public_updates_channel_id; 343 344 if (data.channels) { 345 this.channels.cache.clear(); 346 for (const rawChannel of data.channels) { 347 this.client.channels.add(rawChannel, this); 348 } 349 } 350 351 if (data.roles) { 352 this.roles.cache.clear(); 353 for (const role of data.roles) this.roles.add(role); 354 } 355 356 if (data.members) { 357 this.members.cache.clear(); 358 for (const guildUser of data.members) this.members.add(guildUser); 359 } 360 361 if (data.owner_id) { 362 /** 363 * The user ID of this guild's owner 364 * @type {Snowflake} 365 */ 366 this.ownerID = data.owner_id; 367 } 368 369 if (data.presences) { 370 for (const presence of data.presences) { 371 this.presences.add(Object.assign(presence, { guild: this })); 372 } 373 } 374 375 if (data.voice_states) { 376 this.voiceStates.cache.clear(); 377 for (const voiceState of data.voice_states) { 378 this.voiceStates.add(voiceState); 379 } 380 } 381 382 if (!this.emojis) { 383 /** 384 * A manager of the emojis belonging to this guild 385 * @type {GuildEmojiManager} 386 */ 387 this.emojis = new GuildEmojiManager(this); 388 if (data.emojis) for (const emoji of data.emojis) this.emojis.add(emoji); 389 } else if (data.emojis) { 390 this.client.actions.GuildEmojisUpdate.handle({ 391 guild_id: this.id, 392 emojis: data.emojis, 393 }); 394 } 395 } 396 397 /** 398 * The URL to this guild's banner. 399 * @param {ImageURLOptions} [options={}] Options for the Image URL 400 * @returns {?string} 401 */ 402 bannerURL({ format, size } = {}) { 403 if (!this.banner) return null; 404 return this.client.rest.cdn.Banner(this.id, this.banner, format, size); 405 } 406 407 /** 408 * The timestamp the guild was created at 409 * @type {number} 410 * @readonly 411 */ 412 get createdTimestamp() { 413 return Snowflake.deconstruct(this.id).timestamp; 414 } 415 416 /** 417 * The time the guild was created at 418 * @type {Date} 419 * @readonly 420 */ 421 get createdAt() { 422 return new Date(this.createdTimestamp); 423 } 424 425 /** 426 * The time the client user joined the guild 427 * @type {Date} 428 * @readonly 429 */ 430 get joinedAt() { 431 return new Date(this.joinedTimestamp); 432 } 433 434 /** 435 * If this guild is partnered 436 * @type {boolean} 437 * @readonly 438 */ 439 get partnered() { 440 return this.features.includes('PARTNERED'); 441 } 442 443 /** 444 * If this guild is verified 445 * @type {boolean} 446 * @readonly 447 */ 448 get verified() { 449 return this.features.includes('VERIFIED'); 450 } 451 452 /** 453 * The URL to this guild's icon. 454 * @param {ImageURLOptions} [options={}] Options for the Image URL 455 * @returns {?string} 456 */ 457 iconURL({ format, size, dynamic } = {}) { 458 if (!this.icon) return null; 459 return this.client.rest.cdn.Icon(this.id, this.icon, format, size, dynamic); 460 } 461 462 /** 463 * The acronym that shows up in place of a guild icon. 464 * @type {string} 465 * @readonly 466 */ 467 get nameAcronym() { 468 return this.name.replace(/\w+/g, name => name[0]).replace(/\s/g, ''); 469 } 470 471 /** 472 * The URL to this guild's splash. 473 * @param {ImageURLOptions} [options={}] Options for the Image URL 474 * @returns {?string} 475 */ 476 splashURL({ format, size } = {}) { 477 if (!this.splash) return null; 478 return this.client.rest.cdn.Splash(this.id, this.splash, format, size); 479 } 480 481 /** 482 * The owner of the guild 483 * @type {?GuildMember} 484 * @readonly 485 */ 486 get owner() { 487 return ( 488 this.members.cache.get(this.ownerID) || 489 (this.client.options.partials.includes(PartialTypes.GUILD_MEMBER) 490 ? this.members.add({ user: { id: this.ownerID } }, true) 491 : null) 492 ); 493 } 494 495 /** 496 * AFK voice channel for this guild 497 * @type {?VoiceChannel} 498 * @readonly 499 */ 500 get afkChannel() { 501 return this.client.channels.cache.get(this.afkChannelID) || null; 502 } 503 504 /** 505 * System channel for this guild 506 * @type {?TextChannel} 507 * @readonly 508 */ 509 get systemChannel() { 510 return this.client.channels.cache.get(this.systemChannelID) || null; 511 } 512 513 /** 514 * Widget channel for this guild 515 * @type {?TextChannel} 516 * @readonly 517 */ 518 get widgetChannel() { 519 return this.client.channels.cache.get(this.widgetChannelID) || null; 520 } 521 522 /** 523 * Embed channel for this guild 524 * @type {?TextChannel} 525 * @readonly 526 */ 527 get embedChannel() { 528 return this.client.channels.cache.get(this.embedChannelID) || null; 529 } 530 531 /** 532 * Rules channel for this guild 533 * <info>This is only available on guilds with the `PUBLIC` feature</info> 534 * @type {?TextChannel} 535 * @readonly 536 */ 537 get rulesChannel() { 538 return this.client.channels.cache.get(this.rulesChannelID) || null; 539 } 540 541 /** 542 * Public updates channel for this guild 543 * <info>This is only available on guilds with the `PUBLIC` feature</info> 544 * @type {?TextChannel} 545 * @readonly 546 */ 547 get publicUpdatesChannel() { 548 return this.client.channels.cache.get(this.publicUpdatesChannelID) || null; 549 } 550 551 /** 552 * The client user as a GuildMember of this guild 553 * @type {?GuildMember} 554 * @readonly 555 */ 556 get me() { 557 return ( 558 this.members.cache.get(this.client.user.id) || 559 (this.client.options.partials.includes(PartialTypes.GUILD_MEMBER) 560 ? this.members.add({ user: { id: this.client.user.id } }, true) 561 : null) 562 ); 563 } 564 565 /** 566 * The voice state for the client user of this guild, if any 567 * @type {?VoiceState} 568 * @readonly 569 */ 570 get voice() { 571 return this.voiceStates.cache.get(this.client.user.id); 572 } 573 574 /** 575 * Returns the GuildMember form of a User object, if the user is present in the guild. 576 * @param {UserResolvable} user The user that you want to obtain the GuildMember of 577 * @returns {?GuildMember} 578 * @example 579 * // Get the guild member of a user 580 * const member = guild.member(message.author); 581 */ 582 member(user) { 583 return this.members.resolve(user); 584 } 585 586 /** 587 * Fetches this guild. 588 * @returns {Promise<Guild>} 589 */ 590 fetch() { 591 return this.client.api 592 .guilds(this.id) 593 .get() 594 .then(data => { 595 this._patch(data); 596 return this; 597 }); 598 } 599 600 /** 601 * An object containing information about a guild member's ban. 602 * @typedef {Object} BanInfo 603 * @property {User} user User that was banned 604 * @property {?string} reason Reason the user was banned 605 */ 606 607 /** 608 * Fetches information on a banned user from this guild. 609 * @param {UserResolvable} user The User to fetch the ban info of 610 * @returns {Promise<BanInfo>} 611 */ 612 fetchBan(user) { 613 const id = this.client.users.resolveID(user); 614 if (!id) throw new Error('FETCH_BAN_RESOLVE_ID'); 615 return this.client.api 616 .guilds(this.id) 617 .bans(id) 618 .get() 619 .then(ban => ({ 620 reason: ban.reason, 621 user: this.client.users.add(ban.user), 622 })); 623 } 624 625 /** 626 * Fetches a collection of banned users in this guild. 627 * @returns {Promise<Collection<Snowflake, BanInfo>>} 628 */ 629 fetchBans() { 630 return this.client.api 631 .guilds(this.id) 632 .bans.get() 633 .then(bans => 634 bans.reduce((collection, ban) => { 635 collection.set(ban.user.id, { 636 reason: ban.reason, 637 user: this.client.users.add(ban.user), 638 }); 639 return collection; 640 }, new Collection()), 641 ); 642 } 643 644 /** 645 * Fetches a collection of integrations to this guild. 646 * Resolves with a collection mapping integrations by their ids. 647 * @returns {Promise<Collection<string, Integration>>} 648 * @example 649 * // Fetch integrations 650 * guild.fetchIntegrations() 651 * .then(integrations => console.log(`Fetched ${integrations.size} integrations`)) 652 * .catch(console.error); 653 */ 654 fetchIntegrations() { 655 return this.client.api 656 .guilds(this.id) 657 .integrations.get() 658 .then(data => 659 data.reduce( 660 (collection, integration) => collection.set(integration.id, new Integration(this.client, integration, this)), 661 new Collection(), 662 ), 663 ); 664 } 665 666 /** 667 * The data for creating an integration. 668 * @typedef {Object} IntegrationData 669 * @property {string} id The integration id 670 * @property {string} type The integration type 671 */ 672 673 /** 674 * Creates an integration by attaching an integration object 675 * @param {IntegrationData} data The data for the integration 676 * @param {string} reason Reason for creating the integration 677 * @returns {Promise<Guild>} 678 */ 679 createIntegration(data, reason) { 680 return this.client.api 681 .guilds(this.id) 682 .integrations.post({ data, reason }) 683 .then(() => this); 684 } 685 686 /** 687 * Fetches a collection of invites to this guild. 688 * Resolves with a collection mapping invites by their codes. 689 * @returns {Promise<Collection<string, Invite>>} 690 * @example 691 * // Fetch invites 692 * guild.fetchInvites() 693 * .then(invites => console.log(`Fetched ${invites.size} invites`)) 694 * .catch(console.error); 695 * @example 696 * // Fetch invite creator by their id 697 * guild.fetchInvites() 698 * .then(invites => console.log(invites.find(invite => invite.inviter.id === '84484653687267328'))) 699 * .catch(console.error); 700 */ 701 fetchInvites() { 702 return this.client.api 703 .guilds(this.id) 704 .invites.get() 705 .then(inviteItems => { 706 const invites = new Collection(); 707 for (const inviteItem of inviteItems) { 708 const invite = new Invite(this.client, inviteItem); 709 invites.set(invite.code, invite); 710 } 711 return invites; 712 }); 713 } 714 715 /** 716 * Obtains a guild preview for this guild from Discord, only available for public guilds. 717 * @returns {Promise<GuildPreview>} 718 */ 719 fetchPreview() { 720 return this.client.api 721 .guilds(this.id) 722 .preview.get() 723 .then(data => new GuildPreview(this.client, data)); 724 } 725 726 /** 727 * Fetches the vanity url invite code to this guild. 728 * Resolves with a string matching the vanity url invite code, not the full url. 729 * @returns {Promise<string>} 730 * @example 731 * // Fetch invites 732 * guild.fetchVanityCode() 733 * .then(code => { 734 * console.log(`Vanity URL: https://discord.gg/${code}`); 735 * }) 736 * .catch(console.error); 737 */ 738 fetchVanityCode() { 739 if (!this.features.includes('VANITY_URL')) { 740 return Promise.reject(new Error('VANITY_URL')); 741 } 742 return this.client.api 743 .guilds(this.id, 'vanity-url') 744 .get() 745 .then(res => res.code); 746 } 747 748 /** 749 * Fetches all webhooks for the guild. 750 * @returns {Promise<Collection<Snowflake, Webhook>>} 751 * @example 752 * // Fetch webhooks 753 * guild.fetchWebhooks() 754 * .then(webhooks => console.log(`Fetched ${webhooks.size} webhooks`)) 755 * .catch(console.error); 756 */ 757 fetchWebhooks() { 758 return this.client.api 759 .guilds(this.id) 760 .webhooks.get() 761 .then(data => { 762 const hooks = new Collection(); 763 for (const hook of data) hooks.set(hook.id, new Webhook(this.client, hook)); 764 return hooks; 765 }); 766 } 767 768 /** 769 * Fetches available voice regions. 770 * @returns {Promise<Collection<string, VoiceRegion>>} 771 */ 772 fetchVoiceRegions() { 773 return this.client.api 774 .guilds(this.id) 775 .regions.get() 776 .then(res => { 777 const regions = new Collection(); 778 for (const region of res) regions.set(region.id, new VoiceRegion(region)); 779 return regions; 780 }); 781 } 782 783 /** 784 * The Guild Embed object 785 * @typedef {Object} GuildEmbedData 786 * @property {boolean} enabled Whether the embed is enabled 787 * @property {?GuildChannel} channel The embed channel 788 */ 789 790 /** 791 * Fetches the guild embed. 792 * @returns {Promise<GuildEmbedData>} 793 * @example 794 * // Fetches the guild embed 795 * guild.fetchEmbed() 796 * .then(embed => console.log(`The embed is ${embed.enabled ? 'enabled' : 'disabled'}`)) 797 * .catch(console.error); 798 */ 799 fetchEmbed() { 800 return this.client.api 801 .guilds(this.id) 802 .embed.get() 803 .then(data => ({ 804 enabled: data.enabled, 805 channel: data.channel_id ? this.channels.cache.get(data.channel_id) : null, 806 })); 807 } 808 809 /** 810 * Fetches audit logs for this guild. 811 * @param {Object} [options={}] Options for fetching audit logs 812 * @param {Snowflake|GuildAuditLogsEntry} [options.before] Limit to entries from before specified entry 813 * @param {number} [options.limit] Limit number of entries 814 * @param {UserResolvable} [options.user] Only show entries involving this user 815 * @param {AuditLogAction|number} [options.type] Only show entries involving this action type 816 * @returns {Promise<GuildAuditLogs>} 817 * @example 818 * // Output audit log entries 819 * guild.fetchAuditLogs() 820 * .then(audit => console.log(audit.entries.first())) 821 * .catch(console.error); 822 */ 823 fetchAuditLogs(options = {}) { 824 if (options.before && options.before instanceof GuildAuditLogs.Entry) options.before = options.before.id; 825 if (typeof options.type === 'string') options.type = GuildAuditLogs.Actions[options.type]; 826 827 return this.client.api 828 .guilds(this.id) 829 ['audit-logs'].get({ 830 query: { 831 before: options.before, 832 limit: options.limit, 833 user_id: this.client.users.resolveID(options.user), 834 action_type: options.type, 835 }, 836 }) 837 .then(data => GuildAuditLogs.build(this, data)); 838 } 839 840 /** 841 * Adds a user to the guild using OAuth2. Requires the `CREATE_INSTANT_INVITE` permission. 842 * @param {UserResolvable} user User to add to the guild 843 * @param {Object} options Options for the addition 844 * @param {string} options.accessToken An OAuth2 access token for the user with the `guilds.join` scope granted to the 845 * bot's application 846 * @param {string} [options.nick] Nickname to give the member (requires `MANAGE_NICKNAMES`) 847 * @param {Collection<Snowflake, Role>|RoleResolvable[]} [options.roles] Roles to add to the member 848 * (requires `MANAGE_ROLES`) 849 * @param {boolean} [options.mute] Whether the member should be muted (requires `MUTE_MEMBERS`) 850 * @param {boolean} [options.deaf] Whether the member should be deafened (requires `DEAFEN_MEMBERS`) 851 * @returns {Promise<GuildMember>} 852 */ 853 addMember(user, options) { 854 user = this.client.users.resolveID(user); 855 if (!user) return Promise.reject(new TypeError('INVALID_TYPE', 'user', 'UserResolvable')); 856 if (this.members.cache.has(user)) return Promise.resolve(this.members.cache.get(user)); 857 options.access_token = options.accessToken; 858 if (options.roles) { 859 const roles = []; 860 for (let role of options.roles instanceof Collection ? options.roles.values() : options.roles) { 861 role = this.roles.resolve(role); 862 if (!role) { 863 return Promise.reject( 864 new TypeError('INVALID_TYPE', 'options.roles', 'Array or Collection of Roles or Snowflakes', true), 865 ); 866 } 867 roles.push(role.id); 868 } 869 options.roles = roles; 870 } 871 return this.client.api 872 .guilds(this.id) 873 .members(user) 874 .put({ data: options }) 875 .then(data => this.members.add(data)); 876 } 877 878 /** 879 * The data for editing a guild. 880 * @typedef {Object} GuildEditData 881 * @property {string} [name] The name of the guild 882 * @property {string} [region] The region of the guild 883 * @property {VerificationLevel|number} [verificationLevel] The verification level of the guild 884 * @property {ExplicitContentFilterLevel|number} [explicitContentFilter] The level of the explicit content filter 885 * @property {ChannelResolvable} [afkChannel] The AFK channel of the guild 886 * @property {ChannelResolvable} [systemChannel] The system channel of the guild 887 * @property {number} [afkTimeout] The AFK timeout of the guild 888 * @property {Base64Resolvable} [icon] The icon of the guild 889 * @property {GuildMemberResolvable} [owner] The owner of the guild 890 * @property {Base64Resolvable} [splash] The splash screen of the guild 891 * @property {Base64Resolvable} [banner] The banner of the guild 892 * @property {DefaultMessageNotifications|number} [defaultMessageNotifications] The default message notifications 893 * @property {SystemChannelFlagsResolvable} [systemChannelFlags] The system channel flags of the guild 894 */ 895 896 /** 897 * Updates the guild with new information - e.g. a new name. 898 * @param {GuildEditData} data The data to update the guild with 899 * @param {string} [reason] Reason for editing this guild 900 * @returns {Promise<Guild>} 901 * @example 902 * // Set the guild name and region 903 * guild.edit({ 904 * name: 'Discord Guild', 905 * region: 'london', 906 * }) 907 * .then(updated => console.log(`New guild name ${updated} in region ${updated.region}`)) 908 * .catch(console.error); 909 */ 910 edit(data, reason) { 911 const _data = {}; 912 if (data.name) _data.name = data.name; 913 if (data.region) _data.region = data.region; 914 if (typeof data.verificationLevel !== 'undefined') { 915 _data.verification_level = 916 typeof data.verificationLevel === 'number' 917 ? Number(data.verificationLevel) 918 : VerificationLevels.indexOf(data.verificationLevel); 919 } 920 if (typeof data.afkChannel !== 'undefined') { 921 _data.afk_channel_id = this.client.channels.resolveID(data.afkChannel); 922 } 923 if (typeof data.systemChannel !== 'undefined') { 924 _data.system_channel_id = this.client.channels.resolveID(data.systemChannel); 925 } 926 if (data.afkTimeout) _data.afk_timeout = Number(data.afkTimeout); 927 if (typeof data.icon !== 'undefined') _data.icon = data.icon; 928 if (data.owner) _data.owner_id = this.client.users.resolveID(data.owner); 929 if (data.splash) _data.splash = data.splash; 930 if (data.banner) _data.banner = data.banner; 931 if (typeof data.explicitContentFilter !== 'undefined') { 932 _data.explicit_content_filter = 933 typeof data.explicitContentFilter === 'number' 934 ? data.explicitContentFilter 935 : ExplicitContentFilterLevels.indexOf(data.explicitContentFilter); 936 } 937 if (typeof data.defaultMessageNotifications !== 'undefined') { 938 _data.default_message_notifications = 939 typeof data.defaultMessageNotifications === 'string' 940 ? DefaultMessageNotifications.indexOf(data.defaultMessageNotifications) 941 : data.defaultMessageNotifications; 942 } 943 if (typeof data.systemChannelFlags !== 'undefined') { 944 _data.system_channel_flags = SystemChannelFlags.resolve(data.systemChannelFlags); 945 } 946 return this.client.api 947 .guilds(this.id) 948 .patch({ data: _data, reason }) 949 .then(newData => this.client.actions.GuildUpdate.handle(newData).updated); 950 } 951 952 /** 953 * Edits the level of the explicit content filter. 954 * @param {ExplicitContentFilterLevel|number} explicitContentFilter The new level of the explicit content filter 955 * @param {string} [reason] Reason for changing the level of the guild's explicit content filter 956 * @returns {Promise<Guild>} 957 */ 958 setExplicitContentFilter(explicitContentFilter, reason) { 959 return this.edit({ explicitContentFilter }, reason); 960 } 961 962 /* eslint-disable max-len */ 963 /** 964 * Edits the setting of the default message notifications of the guild. 965 * @param {DefaultMessageNotifications|number} defaultMessageNotifications The new setting for the default message notifications 966 * @param {string} [reason] Reason for changing the setting of the default message notifications 967 * @returns {Promise<Guild>} 968 */ 969 setDefaultMessageNotifications(defaultMessageNotifications, reason) { 970 return this.edit({ defaultMessageNotifications }, reason); 971 } 972 /* eslint-enable max-len */ 973 974 /** 975 * Edits the flags of the default message notifications of the guild. 976 * @param {SystemChannelFlagsResolvable} systemChannelFlags The new flags for the default message notifications 977 * @param {string} [reason] Reason for changing the flags of the default message notifications 978 * @returns {Promise<Guild>} 979 */ 980 setSystemChannelFlags(systemChannelFlags, reason) { 981 return this.edit({ systemChannelFlags }, reason); 982 } 983 984 /** 985 * Edits the name of the guild. 986 * @param {string} name The new name of the guild 987 * @param {string} [reason] Reason for changing the guild's name 988 * @returns {Promise<Guild>} 989 * @example 990 * // Edit the guild name 991 * guild.setName('Discord Guild') 992 * .then(updated => console.log(`Updated guild name to ${guild}`)) 993 * .catch(console.error); 994 */ 995 setName(name, reason) { 996 return this.edit({ name }, reason); 997 } 998 999 /** 1000 * Edits the region of the guild. 1001 * @param {string} region The new region of the guild 1002 * @param {string} [reason] Reason for changing the guild's region 1003 * @returns {Promise<Guild>} 1004 * @example 1005 * // Edit the guild region 1006 * guild.setRegion('london') 1007 * .then(updated => console.log(`Updated guild region to ${updated.region}`)) 1008 * .catch(console.error); 1009 */ 1010 setRegion(region, reason) { 1011 return this.edit({ region }, reason); 1012 } 1013 1014 /** 1015 * Edits the verification level of the guild. 1016 * @param {VerificationLevel|number} verificationLevel The new verification level of the guild 1017 * @param {string} [reason] Reason for changing the guild's verification level 1018 * @returns {Promise<Guild>} 1019 * @example 1020 * // Edit the guild verification level 1021 * guild.setVerificationLevel(1) 1022 * .then(updated => console.log(`Updated guild verification level to ${guild.verificationLevel}`)) 1023 * .catch(console.error); 1024 */ 1025 setVerificationLevel(verificationLevel, reason) { 1026 return this.edit({ verificationLevel }, reason); 1027 } 1028 1029 /** 1030 * Edits the AFK channel of the guild. 1031 * @param {ChannelResolvable} afkChannel The new AFK channel 1032 * @param {string} [reason] Reason for changing the guild's AFK channel 1033 * @returns {Promise<Guild>} 1034 * @example 1035 * // Edit the guild AFK channel 1036 * guild.setAFKChannel(channel) 1037 * .then(updated => console.log(`Updated guild AFK channel to ${guild.afkChannel.name}`)) 1038 * .catch(console.error); 1039 */ 1040 setAFKChannel(afkChannel, reason) { 1041 return this.edit({ afkChannel }, reason); 1042 } 1043 1044 /** 1045 * Edits the system channel of the guild. 1046 * @param {ChannelResolvable} systemChannel The new system channel 1047 * @param {string} [reason] Reason for changing the guild's system channel 1048 * @returns {Promise<Guild>} 1049 * @example 1050 * // Edit the guild system channel 1051 * guild.setSystemChannel(channel) 1052 * .then(updated => console.log(`Updated guild system channel to ${guild.systemChannel.name}`)) 1053 * .catch(console.error); 1054 */ 1055 setSystemChannel(systemChannel, reason) { 1056 return this.edit({ systemChannel }, reason); 1057 } 1058 1059 /** 1060 * Edits the AFK timeout of the guild. 1061 * @param {number} afkTimeout The time in seconds that a user must be idle to be considered AFK 1062 * @param {string} [reason] Reason for changing the guild's AFK timeout 1063 * @returns {Promise<Guild>} 1064 * @example 1065 * // Edit the guild AFK channel 1066 * guild.setAFKTimeout(60) 1067 * .then(updated => console.log(`Updated guild AFK timeout to ${guild.afkTimeout}`)) 1068 * .catch(console.error); 1069 */ 1070 setAFKTimeout(afkTimeout, reason) { 1071 return this.edit({ afkTimeout }, reason); 1072 } 1073 1074 /** 1075 * Sets a new guild icon. 1076 * @param {Base64Resolvable|BufferResolvable} icon The new icon of the guild 1077 * @param {string} [reason] Reason for changing the guild's icon 1078 * @returns {Promise<Guild>} 1079 * @example 1080 * // Edit the guild icon 1081 * guild.setIcon('./icon.png') 1082 * .then(updated => console.log('Updated the guild icon')) 1083 * .catch(console.error); 1084 */ 1085 async setIcon(icon, reason) { 1086 return this.edit({ icon: await DataResolver.resolveImage(icon), reason }); 1087 } 1088 1089 /** 1090 * Sets a new owner of the guild. 1091 * @param {GuildMemberResolvable} owner The new owner of the guild 1092 * @param {string} [reason] Reason for setting the new owner 1093 * @returns {Promise<Guild>} 1094 * @example 1095 * // Edit the guild owner 1096 * guild.setOwner(guild.members.cache.first()) 1097 * .then(updated => console.log(`Updated the guild owner to ${updated.owner.displayName}`)) 1098 * .catch(console.error); 1099 */ 1100 setOwner(owner, reason) { 1101 return this.edit({ owner }, reason); 1102 } 1103 1104 /** 1105 * Sets a new guild splash screen. 1106 * @param {Base64Resolvable|BufferResolvable} splash The new splash screen of the guild 1107 * @param {string} [reason] Reason for changing the guild's splash screen 1108 * @returns {Promise<Guild>} 1109 * @example 1110 * // Edit the guild splash 1111 * guild.setSplash('./splash.png') 1112 * .then(updated => console.log('Updated the guild splash')) 1113 * .catch(console.error); 1114 */ 1115 async setSplash(splash, reason) { 1116 return this.edit({ splash: await DataResolver.resolveImage(splash), reason }); 1117 } 1118 1119 /** 1120 * Sets a new guild banner. 1121 * @param {Base64Resolvable|BufferResolvable} banner The new banner of the guild 1122 * @param {string} [reason] Reason for changing the guild's banner 1123 * @returns {Promise<Guild>} 1124 * @example 1125 * guild.setBanner('./banner.png') 1126 * .then(updated => console.log('Updated the guild banner')) 1127 * .catch(console.error); 1128 */ 1129 async setBanner(banner, reason) { 1130 return this.edit({ banner: await DataResolver.resolveImage(banner), reason }); 1131 } 1132 1133 /** 1134 * The data needed for updating a channel's position. 1135 * @typedef {Object} ChannelPosition 1136 * @property {ChannelResolvable} channel Channel to update 1137 * @property {number} position New position for the channel 1138 */ 1139 1140 /** 1141 * Batch-updates the guild's channels' positions. 1142 * @param {ChannelPosition[]} channelPositions Channel positions to update 1143 * @returns {Promise<Guild>} 1144 * @example 1145 * guild.setChannelPositions([{ channel: channelID, position: newChannelIndex }]) 1146 * .then(guild => console.log(`Updated channel positions for ${guild}`)) 1147 * .catch(console.error); 1148 */ 1149 setChannelPositions(channelPositions) { 1150 const updatedChannels = channelPositions.map(r => ({ 1151 id: this.client.channels.resolveID(r.channel), 1152 position: r.position, 1153 })); 1154 1155 return this.client.api 1156 .guilds(this.id) 1157 .channels.patch({ data: updatedChannels }) 1158 .then( 1159 () => 1160 this.client.actions.GuildChannelsPositionUpdate.handle({ 1161 guild_id: this.id, 1162 channels: updatedChannels, 1163 }).guild, 1164 ); 1165 } 1166 1167 /** 1168 * The data needed for updating a guild role's position 1169 * @typedef {Object} GuildRolePosition 1170 * @property {RoleResolveable} role The ID of the role 1171 * @property {number} position The position to update 1172 */ 1173 1174 /** 1175 * Batch-updates the guild's role positions 1176 * @param {GuildRolePosition[]} rolePositions Role positions to update 1177 * @returns {Promise<Guild>} 1178 * @example 1179 * guild.setRolePositions([{ role: roleID, position: updatedRoleIndex }]) 1180 * .then(guild => console.log(`Role permissions updated for ${guild}`)) 1181 * .catch(console.error); 1182 */ 1183 setRolePositions(rolePositions) { 1184 // Make sure rolePositions are prepared for API 1185 rolePositions = rolePositions.map(o => ({ 1186 id: this.roles.resolveID(o.role), 1187 position: o.position, 1188 })); 1189 1190 // Call the API to update role positions 1191 return this.client.api 1192 .guilds(this.id) 1193 .roles.patch({ 1194 data: rolePositions, 1195 }) 1196 .then( 1197 () => 1198 this.client.actions.GuildRolesPositionUpdate.handle({ 1199 guild_id: this.id, 1200 roles: rolePositions, 1201 }).guild, 1202 ); 1203 } 1204 1205 /** 1206 * Edits the guild's embed. 1207 * @param {GuildEmbedData} embed The embed for the guild 1208 * @param {string} [reason] Reason for changing the guild's embed 1209 * @returns {Promise<Guild>} 1210 */ 1211 setEmbed(embed, reason) { 1212 return this.client.api 1213 .guilds(this.id) 1214 .embed.patch({ 1215 data: { 1216 enabled: embed.enabled, 1217 channel_id: this.channels.resolveID(embed.channel), 1218 }, 1219 reason, 1220 }) 1221 .then(() => this); 1222 } 1223 1224 /** 1225 * Leaves the guild. 1226 * @returns {Promise<Guild>} 1227 * @example 1228 * // Leave a guild 1229 * guild.leave() 1230 * .then(g => console.log(`Left the guild ${g}`)) 1231 * .catch(console.error); 1232 */ 1233 leave() { 1234 if (this.ownerID === this.client.user.id) return Promise.reject(new Error('GUILD_OWNED')); 1235 return this.client.api 1236 .users('@me') 1237 .guilds(this.id) 1238 .delete() 1239 .then(() => this.client.actions.GuildDelete.handle({ id: this.id }).guild); 1240 } 1241 1242 /** 1243 * Deletes the guild. 1244 * @returns {Promise<Guild>} 1245 * @example 1246 * // Delete a guild 1247 * guild.delete() 1248 * .then(g => console.log(`Deleted the guild ${g}`)) 1249 * .catch(console.error); 1250 */ 1251 delete() { 1252 return this.client.api 1253 .guilds(this.id) 1254 .delete() 1255 .then(() => this.client.actions.GuildDelete.handle({ id: this.id }).guild); 1256 } 1257 1258 /** 1259 * Whether this guild equals another guild. It compares all properties, so for most operations 1260 * it is advisable to just compare `guild.id === guild2.id` as it is much faster and is often 1261 * what most users need. 1262 * @param {Guild} guild The guild to compare with 1263 * @returns {boolean} 1264 */ 1265 equals(guild) { 1266 let equal = 1267 guild && 1268 guild instanceof this.constructor && 1269 this.id === guild.id && 1270 this.available === guild.available && 1271 this.splash === guild.splash && 1272 this.region === guild.region && 1273 this.name === guild.name && 1274 this.memberCount === guild.memberCount && 1275 this.large === guild.large && 1276 this.icon === guild.icon && 1277 this.ownerID === guild.ownerID && 1278 this.verificationLevel === guild.verificationLevel && 1279 this.embedEnabled === guild.embedEnabled && 1280 (this.features === guild.features || 1281 (this.features.length === guild.features.length && 1282 this.features.every((feat, i) => feat === guild.features[i]))); 1283 1284 if (equal) { 1285 if (this.embedChannel) { 1286 if (!guild.embedChannel || this.embedChannel.id !== guild.embedChannel.id) equal = false; 1287 } else if (guild.embedChannel) { 1288 equal = false; 1289 } 1290 } 1291 1292 return equal; 1293 } 1294 1295 /** 1296 * When concatenated with a string, this automatically returns the guild's name instead of the Guild object. 1297 * @returns {string} 1298 * @example 1299 * // Logs: Hello from My Guild! 1300 * console.log(`Hello from ${guild}!`); 1301 */ 1302 toString() { 1303 return this.name; 1304 } 1305 1306 toJSON() { 1307 const json = super.toJSON({ 1308 available: false, 1309 createdTimestamp: true, 1310 nameAcronym: true, 1311 presences: false, 1312 voiceStates: false, 1313 }); 1314 json.iconURL = this.iconURL(); 1315 json.splashURL = this.splashURL(); 1316 json.bannerURL = this.bannerURL(); 1317 return json; 1318 } 1319 1320 /** 1321 * Creates a collection of this guild's roles, sorted by their position and IDs. 1322 * @returns {Collection<Role>} 1323 * @private 1324 */ 1325 _sortedRoles() { 1326 return Util.discordSort(this.roles.cache); 1327 } 1328 1329 /** 1330 * Creates a collection of this guild's or a specific category's channels, sorted by their position and IDs. 1331 * @param {GuildChannel} [channel] Category to get the channels of 1332 * @returns {Collection<GuildChannel>} 1333 * @private 1334 */ 1335 _sortedChannels(channel) { 1336 const category = channel.type === ChannelTypes.CATEGORY; 1337 return Util.discordSort( 1338 this.channels.cache.filter( 1339 c => 1340 (['text', 'news', 'store'].includes(channel.type) 1341 ? ['text', 'news', 'store'].includes(c.type) 1342 : c.type === channel.type) && 1343 (category || c.parent === channel.parent), 1344 ), 1345 ); 1346 } 1347 } 1348 1349 module.exports = Guild;