238 lines
5.7 KiB
JavaScript
238 lines
5.7 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
const { setTimeout, clearTimeout } = require('node:timers');
|
||
|
const { RouteBases, Routes } = require('discord-api-types/v9');
|
||
|
const Base = require('./Base');
|
||
|
const DataResolver = require('../util/DataResolver');
|
||
|
const Events = require('../util/Events');
|
||
|
|
||
|
/**
|
||
|
* Represents the template for a guild.
|
||
|
* @extends {Base}
|
||
|
*/
|
||
|
class GuildTemplate extends Base {
|
||
|
constructor(client, data) {
|
||
|
super(client);
|
||
|
this._patch(data);
|
||
|
}
|
||
|
|
||
|
_patch(data) {
|
||
|
if ('code' in data) {
|
||
|
/**
|
||
|
* The unique code of this template
|
||
|
* @type {string}
|
||
|
*/
|
||
|
this.code = data.code;
|
||
|
}
|
||
|
|
||
|
if ('name' in data) {
|
||
|
/**
|
||
|
* The name of this template
|
||
|
* @type {string}
|
||
|
*/
|
||
|
this.name = data.name;
|
||
|
}
|
||
|
|
||
|
if ('description' in data) {
|
||
|
/**
|
||
|
* The description of this template
|
||
|
* @type {?string}
|
||
|
*/
|
||
|
this.description = data.description;
|
||
|
}
|
||
|
|
||
|
if ('usage_count' in data) {
|
||
|
/**
|
||
|
* The amount of times this template has been used
|
||
|
* @type {number}
|
||
|
*/
|
||
|
this.usageCount = data.usage_count;
|
||
|
}
|
||
|
|
||
|
if ('creator_id' in data) {
|
||
|
/**
|
||
|
* The id of the user that created this template
|
||
|
* @type {Snowflake}
|
||
|
*/
|
||
|
this.creatorId = data.creator_id;
|
||
|
}
|
||
|
|
||
|
if ('creator' in data) {
|
||
|
/**
|
||
|
* The user that created this template
|
||
|
* @type {User}
|
||
|
*/
|
||
|
this.creator = this.client.users._add(data.creator);
|
||
|
}
|
||
|
|
||
|
if ('created_at' in data) {
|
||
|
/**
|
||
|
* The timestamp of when this template was created at
|
||
|
* @type {number}
|
||
|
*/
|
||
|
this.createdTimestamp = Date.parse(data.created_at);
|
||
|
}
|
||
|
|
||
|
if ('updated_at' in data) {
|
||
|
/**
|
||
|
* The timestamp of when this template was last synced to the guild
|
||
|
* @type {number}
|
||
|
*/
|
||
|
this.updatedTimestamp = Date.parse(data.updated_at);
|
||
|
}
|
||
|
|
||
|
if ('source_guild_id' in data) {
|
||
|
/**
|
||
|
* The id of the guild that this template belongs to
|
||
|
* @type {Snowflake}
|
||
|
*/
|
||
|
this.guildId = data.source_guild_id;
|
||
|
}
|
||
|
|
||
|
if ('serialized_source_guild' in data) {
|
||
|
/**
|
||
|
* The data of the guild that this template would create
|
||
|
* @type {APIGuild}
|
||
|
*/
|
||
|
this.serializedGuild = data.serialized_source_guild;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Whether this template has unsynced changes
|
||
|
* @type {?boolean}
|
||
|
*/
|
||
|
this.unSynced = 'is_dirty' in data ? Boolean(data.is_dirty) : null;
|
||
|
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a guild based on this template.
|
||
|
* <warn>This is only available to bots in fewer than 10 guilds.</warn>
|
||
|
* @param {string} name The name of the guild
|
||
|
* @param {BufferResolvable|Base64Resolvable} [icon] The icon for the guild
|
||
|
* @returns {Promise<Guild>}
|
||
|
*/
|
||
|
async createGuild(name, icon) {
|
||
|
const { client } = this;
|
||
|
const data = await client.rest.post(Routes.template(this.code), {
|
||
|
body: {
|
||
|
name,
|
||
|
icon: await DataResolver.resolveImage(icon),
|
||
|
},
|
||
|
});
|
||
|
|
||
|
if (client.guilds.cache.has(data.id)) return client.guilds.cache.get(data.id);
|
||
|
|
||
|
return new Promise(resolve => {
|
||
|
const resolveGuild = guild => {
|
||
|
client.off(Events.GuildCreate, handleGuild);
|
||
|
client.decrementMaxListeners();
|
||
|
resolve(guild);
|
||
|
};
|
||
|
|
||
|
const handleGuild = guild => {
|
||
|
if (guild.id === data.id) {
|
||
|
clearTimeout(timeout);
|
||
|
resolveGuild(guild);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
client.incrementMaxListeners();
|
||
|
client.on(Events.GuildCreate, handleGuild);
|
||
|
|
||
|
const timeout = setTimeout(() => resolveGuild(client.guilds._add(data)), 10_000).unref();
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Options used to edit a guild template.
|
||
|
* @typedef {Object} EditGuildTemplateOptions
|
||
|
* @property {string} [name] The name of this template
|
||
|
* @property {string} [description] The description of this template
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Updates the metadata of this template.
|
||
|
* @param {EditGuildTemplateOptions} [options] Options for editing the template
|
||
|
* @returns {Promise<GuildTemplate>}
|
||
|
*/
|
||
|
async edit({ name, description } = {}) {
|
||
|
const data = await this.client.api.guilds(this.guildId).templates(this.code).patch({ body: { name, description } });
|
||
|
return this._patch(data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Deletes this template.
|
||
|
* @returns {Promise<GuildTemplate>}
|
||
|
*/
|
||
|
async delete() {
|
||
|
await this.client.api.guilds(this.guildId).templates(this.code).delete();
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Syncs this template to the current state of the guild.
|
||
|
* @returns {Promise<GuildTemplate>}
|
||
|
*/
|
||
|
async sync() {
|
||
|
const data = await this.client.api.guilds(this.guildId).templates(this.code).put();
|
||
|
return this._patch(data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* The time when this template was created at
|
||
|
* @type {Date}
|
||
|
* @readonly
|
||
|
*/
|
||
|
get createdAt() {
|
||
|
return new Date(this.createdTimestamp);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* The time when this template was last synced to the guild
|
||
|
* @type {Date}
|
||
|
* @readonly
|
||
|
*/
|
||
|
get updatedAt() {
|
||
|
return new Date(this.updatedTimestamp);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* The guild that this template belongs to
|
||
|
* @type {?Guild}
|
||
|
* @readonly
|
||
|
*/
|
||
|
get guild() {
|
||
|
return this.client.guilds.resolve(this.guildId);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* The URL of this template
|
||
|
* @type {string}
|
||
|
* @readonly
|
||
|
*/
|
||
|
get url() {
|
||
|
return `${RouteBases.template}/${this.code}`;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* When concatenated with a string, this automatically returns the template's code instead of the template object.
|
||
|
* @returns {string}
|
||
|
* @example
|
||
|
* // Logs: Template: FKvmczH2HyUf
|
||
|
* console.log(`Template: ${guildTemplate}!`);
|
||
|
*/
|
||
|
toString() {
|
||
|
return this.code;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Regular expression that globally matches guild template links
|
||
|
* @type {RegExp}
|
||
|
*/
|
||
|
GuildTemplate.GUILD_TEMPLATES_PATTERN = /discord(?:app)?\.(?:com\/template|new)\/([\w-]{2,255})/gi;
|
||
|
|
||
|
module.exports = GuildTemplate;
|