From 038ee99604cded41d4c67edf4bd6bc7969712f52 Mon Sep 17 00:00:00 2001 From: ThumusLive <42680097+ThumusLive@users.noreply.github.com> Date: Tue, 15 Jun 2021 13:02:18 +0200 Subject: [PATCH] feat(Widget): wrapper for widget.json (#5619) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: monbrey Co-authored-by: BannerBomb Co-authored-by: SpaceEEC Co-authored-by: Antonio Román Co-authored-by: Noel --- src/client/Client.js | 13 +++++ src/index.js | 2 + src/structures/Widget.js | 81 ++++++++++++++++++++++++++ src/structures/WidgetMember.js | 102 +++++++++++++++++++++++++++++++++ typings/index.d.ts | 39 +++++++++++++ 5 files changed, 237 insertions(+) create mode 100644 src/structures/Widget.js create mode 100644 src/structures/WidgetMember.js diff --git a/src/client/Client.js b/src/client/Client.js index c2d6148fe39c..f6848ab2b9c7 100644 --- a/src/client/Client.js +++ b/src/client/Client.js @@ -15,6 +15,7 @@ const GuildTemplate = require('../structures/GuildTemplate'); const Invite = require('../structures/Invite'); const VoiceRegion = require('../structures/VoiceRegion'); const Webhook = require('../structures/Webhook'); +const Widget = require('../structures/Widget'); const Collection = require('../util/Collection'); const { Events, DefaultOptions, InviteScopes } = require('../util/Constants'); const DataResolver = require('../util/DataResolver'); @@ -365,6 +366,18 @@ class Client extends BaseClient { .then(data => new GuildPreview(this, data)); } + /** + * Obtains the widget of a guild from Discord, available for guilds with the widget enabled. + * @param {GuildResolvable} guild The guild to fetch the widget for + * @returns {Promise} + */ + async fetchWidget(guild) { + const id = this.guilds.resolveID(guild); + if (!id) throw new TypeError('INVALID_TYPE', 'guild', 'GuildResolvable'); + const data = await this.api.guilds(id, 'widget.json').get(); + return new Widget(this, data); + } + /** * Options for {@link Client#generateInvite}. * @typedef {Object} InviteGenerationOptions diff --git a/src/index.js b/src/index.js index c3e64b85dbe2..0b8a96e827a6 100644 --- a/src/index.js +++ b/src/index.js @@ -124,6 +124,8 @@ module.exports = { VoiceRegion: require('./structures/VoiceRegion'), VoiceState: require('./structures/VoiceState'), Webhook: require('./structures/Webhook'), + Widget: require('./structures/Widget'), + WidgetMember: require('./structures/WidgetMember'), WebSocket: require('./WebSocket'), }; diff --git a/src/structures/Widget.js b/src/structures/Widget.js new file mode 100644 index 000000000000..3b232505eadd --- /dev/null +++ b/src/structures/Widget.js @@ -0,0 +1,81 @@ +'use strict'; + +const Base = require('./Base'); +const WidgetMember = require('./WidgetMember'); +const Collection = require('../util/Collection'); + +/** + * Represents a Widget. + */ +class Widget extends Base { + /** + * @param {Client} client The instantiating client + * @param {Object} data The raw data + */ + constructor(client, data) { + super(client); + this._patch(data); + } + + /** + * Builds the widget with the provided data. + * @param {*} data The raw data of the widget + * @private + */ + _patch(data) { + /** + * The id of the guild. + * @type {Snowflake} + */ + this.id = data.id; + + /** + * The name of the guild. + * @type {string} + */ + this.name = data.name; + + /** + * The invite of the guild. + * @type {?string} + */ + this.instantInvite = data.instant_invite; + + /** + * The list of channels in the guild. + * @type {Collection} + */ + this.channels = new Collection(); + for (const channel of data.channels) { + this.channels.set(channel.id, channel); + } + + /** + * The list of members in the guild. + * These strings are just arbitrary numbers, they aren't Snowflakes. + * @type {Collection} + */ + this.members = new Collection(); + for (const member of data.members) { + this.members.set(member.id, new WidgetMember(this.client, member)); + } + + /** + * The number of the members online. + * @type {number} + */ + this.presenceCount = data.presence_count; + } + + /** + * Update the Widget. + * @returns {Promise} + */ + async fetch() { + const data = await this.client.api.guilds(this.id, 'widget.json').get(); + this._patch(data); + return this; + } +} + +module.exports = Widget; diff --git a/src/structures/WidgetMember.js b/src/structures/WidgetMember.js new file mode 100644 index 000000000000..e56511efa73d --- /dev/null +++ b/src/structures/WidgetMember.js @@ -0,0 +1,102 @@ +'use strict'; + +const Base = require('./Base'); + +/** + * Represents a WidgetMember. + */ +class WidgetMember extends Base { + /** + * Activity sent in a {@link WidgetMember}. + * @typedef {Object} WidgetActivity + * @property {string} name The name of the activity + */ + + /** + * @param {Client} client The instantiating client + * @param {Object} data The raw data + */ + constructor(client, data) { + super(client); + + /** + * The id of the user. It's an arbitrary number. + * @type {string} + */ + this.id = data.id; + + /** + * The username of the member. + * @type {string} + */ + this.username = data.username; + + /** + * The discriminator of the member. + * @type {string} + */ + this.discriminator = data.discriminator; + + /** + * The avatar of the member. + * @type {?string} + */ + this.avatar = data.avatar; + + /** + * The status of the member. + * @type {PresenceStatus} + */ + this.status = data.status; + + /** + * IIf the member is server deafened + * @type {?boolean} + */ + this.deaf = data.deaf; + + /** + * If the member is server muted + * @type {?boolean} + */ + this.mute = data.mute; + + /** + * If the member is self deafened + * @type {?boolean} + */ + this.selfDeaf = data.self_deaf; + + /** + * If the member is self muted + * @type {?boolean} + */ + this.selfMute = data.self_mute; + + /** + * If the member is suppressed + * @type {?boolean} + */ + this.suppress = data.suppress; + + /** + * The id of the voice channel the member is in, if any + * @type {?Snowflake} + */ + this.channelID = data.channel_id; + + /** + * The avatar URL of the member. + * @type {string} + */ + this.avatarURL = data.avatar_url; + + /** + * The activity of the member. + * @type {?WidgetActivity} + */ + this.activity = data.activity; + } +} + +module.exports = WidgetMember; diff --git a/typings/index.d.ts b/typings/index.d.ts index 5aa6b15d434e..83c5dc5f3c25 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -350,6 +350,7 @@ declare module 'discord.js' { public fetchGuildTemplate(template: GuildTemplateResolvable): Promise; public fetchVoiceRegions(): Promise>; public fetchWebhook(id: Snowflake, token?: string): Promise; + public fetchWidget(id: Snowflake): Promise; public generateInvite(options?: InviteGenerationOptions): string; public login(token?: string): Promise; public sweepMessages(lifetime?: number): number; @@ -2028,6 +2029,34 @@ declare module 'discord.js' { public once(event: string, listener: (...args: any[]) => Awaited): this; } + export class Widget extends Base { + constructor(client: Client, data: object); + private _patch(data: object): void; + public fetch(): Promise; + public id: Snowflake; + public instantInvite?: string; + public channels: Collection; + public members: Collection; + public presenceCount: number; + } + + export class WidgetMember extends Base { + constructor(client: Client, data: object); + public id: string; + public username: string; + public discriminator: string; + public avatar?: string; + public status: PresenceStatus; + public deaf?: boolean; + public mute?: boolean; + public selfDeaf?: boolean; + public selfMute?: boolean; + public suppress?: boolean; + public channelID?: Snowflake; + public avatarURL: string; + public activity?: WidgetActivity; + } + //#endregion //#region Collections @@ -3861,6 +3890,16 @@ declare module 'discord.js' { $device?: string; } + interface WidgetActivity { + name: string; + } + + interface WidgetChannel { + id: Snowflake; + name: string; + position: number; + } + type WSEventType = | 'READY' | 'RESUMED'