Skip to content

Commit

Permalink
feat(Integration): add guild integrations (#3756)
Browse files Browse the repository at this point in the history
  • Loading branch information
SpaceEEC authored Feb 2, 2020
1 parent a12e1e8 commit c955fd0
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 0 deletions.
49 changes: 49 additions & 0 deletions src/client/rest/RESTMethods.js
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,55 @@ class RESTMethods {
patchClientUserGuildSettings(guildID, data) {
return this.rest.makeRequest('patch', Constants.Endpoints.User('@me').Guild(guildID).settings, true, data);
}

getIntegrations(guild) {
return this.rest.makeRequest(
'get',
Constants.Endpoints.Guild(guild.id).integrations,
true
);
}

createIntegration(guild, data, reason) {
return this.rest.makeRequest(
'post',
Constants.Endpoints.Guild(guild.id).integrations,
true,
data,
undefined,
reason
);
}

syncIntegration(integration) {
return this.rest.makeRequest(
'post',
Constants.Endpoints.Guild(integration.guild.id).Integration(integration.id),
true
);
}

editIntegration(integration, data, reason) {
return this.rest.makeRequest(
'patch',
Constants.Endpoints.Guild(integration.guild.id).Integration(integration.id),
true,
data,
undefined,
reason
);
}

deleteIntegration(integration, reason) {
return this.rest.makeRequest(
'delete',
Constants.Endpoints.Guild(integration.guild.id).Integration(integration.id),
true,
undefined,
undefined,
reason
);
}
}

module.exports = RESTMethods;
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ module.exports = {
GuildAuditLogs: require('./structures/GuildAuditLogs'),
GuildChannel: require('./structures/GuildChannel'),
GuildMember: require('./structures/GuildMember'),
Integration: require('./structures/Integration'),
Invite: require('./structures/Invite'),
Message: require('./structures/Message'),
MessageAttachment: require('./structures/MessageAttachment'),
Expand Down
37 changes: 37 additions & 0 deletions src/structures/Guild.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const Role = require('./Role');
const Emoji = require('./Emoji');
const Presence = require('./Presence').Presence;
const GuildMember = require('./GuildMember');
const Integration = require('./Integration');
const Constants = require('../util/Constants');
const Collection = require('../util/Collection');
const Util = require('../util/Util');
Expand Down Expand Up @@ -634,6 +635,42 @@ class Guild {
});
}

/**
* Fetches a collection of integrations to this guild.
* Resolves with a collection mapping integrations by their ids.
* @returns {Promise<Collection<string, Integration>>}
* @example
* // Fetch integrations
* guild.fetchIntegrations()
* .then(integrations => console.log(`Fetched ${integrations.size} integrations`))
* .catch(console.error);
*/
fetchIntegrations() {
return this.client.rest.methods.getIntegrations(this).then(data =>
data.reduce((collection, integration) =>
collection.set(integration.id, new Integration(this.client, integration, this)),
new Collection())
);
}

/**
* The data for creating an integration.
* @typedef {Object} IntegrationData
* @property {string} id The integration id
* @property {string} type The integration type
*/

/**
* Creates an integration by attaching an integration object
* @param {IntegrationData} data The data for thes integration
* @param {string} reason Reason for creating the integration
* @returns {Promise<Guild>}
*/
createIntegration(data, reason) {
return this.client.rest.methods.createIntegration(this, data, reason)
.then(() => this);
}

/**
* Fetch a collection of invites to this guild.
* Resolves with a collection mapping invites by their codes.
Expand Down
151 changes: 151 additions & 0 deletions src/structures/Integration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/**
* The information account for an integration
* @typedef {Object} IntegrationAccount
* @property {string} id The id of the account
* @property {string} name The name of the account
*/

/**
* Represents a guild integration.
*/
class Integration {
constructor(client, data, guild) {
/**
* The client that created this integration
* @name Integration#client
* @type {Client}
* @readonly
*/
Object.defineProperty(this, 'client', { value: client });

/**
* The guild this integration belongs to
* @type {Guild}
*/
this.guild = guild;

/**
* The integration id
* @type {Snowflake}
*/
this.id = data.id;

/**
* The integration name
* @type {string}
*/
this.name = data.name;
/**
* The integration type (twitch, youtube, etc)
* @type {string}
*/
this.type = data.type;

/**
* Whether this integration is enabled
* @type {boolean}
*/
this.enabled = data.enabled;

/**
* Whether this integration is syncing
* @type {boolean}
*/
this.syncing = data.syncing;

/**
* The role that this integration uses for subscribers
* @type {Role}
*/
this.role = this.guild.roles.get(data.role_id);

/**
* The user for this integration
* @type {User}
*/
this.user = this.client.dataManager.newUser(data.user);

/**
* The account integration information
* @type {IntegrationAccount}
*/
this.account = data.account;

/**
* The last time this integration was last synced
* @type {number}
*/
this.syncedAt = data.synced_at;
this._patch(data);
}

_patch(data) {
/**
* The behavior of expiring subscribers
* @type {number}
*/
this.expireBehavior = data.expire_behavior;

/**
* The grace period before expiring subscribers
* @type {number}
*/
this.expireGracePeriod = data.expire_grace_period;
}

/**
* Syncs this integration
* @returns {Promise<Integration>}
*/
sync() {
this.syncing = true;
return this.client.rest.methods.syncIntegration(this)
.then(() => {
this.syncing = false;
this.syncedAt = Date.now();
return this;
});
}

/**
* The data for editing an integration.
* @typedef {Object} IntegrationEditData
* @property {number} [expireBehavior] The new behaviour of expiring subscribers
* @property {number} [expireGracePeriod] The new grace period before expiring subscribers
*/

/**
* Edits this integration.
* @param {IntegrationEditData} data The data to edit this integration with
* @param {string} reason Reason for editing this integration
* @returns {Promise<Integration>}
*/
edit(data, reason) {
if ('expireBehavior' in data) {
data.expire_behavior = data.expireBehavior;
data.expireBehavior = undefined;
}
if ('expireGracePeriod' in data) {
data.expire_grace_period = data.expireGracePeriod;
data.expireGracePeriod = undefined;
}
// The option enable_emoticons is only available for Twitch at this moment
return this.client.rest.methods.editIntegration(this, data, reason)
.then(() => {
this._patch(data);
return this;
});
}

/**
* Deletes this integration.
* @returns {Promise<Integration>}
* @param {string} [reason] Reason for deleting this integration
*/
delete(reason) {
return this.client.rest.methods.deleteIntegration(this, reason)
.then(() => this);
}
}

module.exports = Integration;
1 change: 1 addition & 0 deletions src/util/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ const Endpoints = exports.Endpoints = {
nickname: `${base}/members/@me/nick`,
};
},
Integration: id => `${base}/integrations/${id}`,
};
},
channels: '/channels',
Expand Down
36 changes: 36 additions & 0 deletions typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,7 @@ declare module 'discord.js' {
public createChannel(name: string, options?: ChannelData): Promise<CategoryChannel | TextChannel | VoiceChannel>;
public createChannel(name: string, type?: 'category' | 'text' | 'voice' | 'news' | 'store', permissionOverwrites?: PermissionOverwrites[] | ChannelCreationOverwrites[], reason?: string): Promise<CategoryChannel | TextChannel | VoiceChannel>;
public createEmoji(attachment: BufferResolvable | Base64Resolvable, name: string, roles?: Collection<Snowflake, Role> | Role[], reason?: string): Promise<Emoji>;
public createIntegration(data: IntegrationData, reason?: string): Promise<Guild>;
public createRole(data?: RoleData, reason?: string): Promise<Role>;
public delete(): Promise<Guild>;
public deleteEmoji(emoji: Emoji | string, reason?: string): Promise<void>;
Expand All @@ -563,6 +564,7 @@ declare module 'discord.js' {
public fetchBans(withReasons: true): Promise<Collection<Snowflake, BanInfo>>;
public fetchBans(withReasons: boolean): Promise<Collection<Snowflake, BanInfo | User>>;
public fetchEmbed(): Promise<GuildEmbedData>;
public fetchIntegrations(): Promise<Collection<string, Integration>>;
public fetchInvites(): Promise<Collection<Snowflake, Invite>>;
public fetchMember(user: UserResolvable, cache?: boolean): Promise<GuildMember>;
public fetchMembers(query?: string, limit?: number): Promise<Guild>;
Expand Down Expand Up @@ -715,6 +717,25 @@ declare module 'discord.js' {
public toString(): string;
}

export class Integration {
constructor(client: Client, data: object, guild: Guild);
public account: IntegrationAccount;
public enabled: boolean;
public expireBehavior: number;
public expireGracePeriod: number;
public guild: Guild;
public id: Snowflake;
public name: string;
public role: Role;
public syncedAt: number;
public syncing: boolean;
public type: number;
public user: User;
public delete(reason?: string): Promise<Integration>;
public edit(data: IntegrationEditData, reason?: string): Promise<Integration>;
public sync(): Promise<Integration>;
}

export class Invite {
constructor(client: Client, data: object);
public channel: GuildChannel | PartialGuildChannel;
Expand Down Expand Up @@ -1929,6 +1950,21 @@ declare module 'discord.js' {
cdn?: string;
};

type IntegrationData = {
id: string;
type: string;
}

type IntegrationEditData = {
expireBehavior?: number;
expireGracePeriod?: number;
}

type IntegrationAccount = {
id: string;
number: string;
}

type InviteOptions = {
temporary?: boolean;
maxAge?: number;
Expand Down

0 comments on commit c955fd0

Please sign in to comment.