Skip to content

Commit

Permalink
Merge branch 'v13' into 13-repliable
Browse files Browse the repository at this point in the history
  • Loading branch information
Jiralite committed Mar 2, 2022
2 parents 7fd5c06 + 13dd82d commit 85f5d5c
Show file tree
Hide file tree
Showing 24 changed files with 194 additions and 63 deletions.
4 changes: 2 additions & 2 deletions src/managers/GuildMemberManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ class GuildMemberManager extends CachedManager {
* @example
* // Kick a user by id (or with a user/guild member object)
* guild.members.kick('84484653687267328')
* .then(banInfo => console.log(`Kicked ${banInfo.user?.tag ?? banInfo.tag ?? banInfo}`))
* .then(kickInfo => console.log(`Kicked ${kickInfo.user?.tag ?? kickInfo.tag ?? kickInfo}`))
* .catch(console.error);
*/
async kick(user, reason) {
Expand All @@ -376,7 +376,7 @@ class GuildMemberManager extends CachedManager {
* @example
* // Ban a user by id (or with a user/guild member object)
* guild.members.ban('84484653687267328')
* .then(kickInfo => console.log(`Banned ${kickInfo.user?.tag ?? kickInfo.tag ?? kickInfo}`))
* .then(banInfo => console.log(`Banned ${banInfo.user?.tag ?? banInfo.tag ?? banInfo}`))
* .catch(console.error);
*/
ban(user, options = { days: 0 }) {
Expand Down
7 changes: 7 additions & 0 deletions src/managers/GuildScheduledEventManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const CachedManager = require('./CachedManager');
const { TypeError, Error } = require('../errors');
const { GuildScheduledEvent } = require('../structures/GuildScheduledEvent');
const { PrivacyLevels, GuildScheduledEventEntityTypes, GuildScheduledEventStatuses } = require('../util/Constants');
const DataResolver = require('../util/DataResolver');

/**
* Manages API methods for GuildScheduledEvents and stores their cache.
Expand Down Expand Up @@ -49,6 +50,7 @@ class GuildScheduledEventManager extends CachedManager {
* @property {GuildScheduledEventEntityMetadataOptions} [entityMetadata] The entity metadata of the
* guild scheduled event
* <warn>This is required if `entityType` is 'EXTERNAL'</warn>
* @property {?(BufferResolvable|Base64Resolvable)} [image] The cover image of the guild scheduled event
* @property {string} [reason] The reason for creating the guild scheduled event
*/

Expand Down Expand Up @@ -76,6 +78,7 @@ class GuildScheduledEventManager extends CachedManager {
scheduledEndTime,
entityMetadata,
reason,
image,
} = options;

if (typeof privacyLevel === 'string') privacyLevel = PrivacyLevels[privacyLevel];
Expand All @@ -99,6 +102,7 @@ class GuildScheduledEventManager extends CachedManager {
scheduled_start_time: new Date(scheduledStartTime).toISOString(),
scheduled_end_time: scheduledEndTime ? new Date(scheduledEndTime).toISOString() : scheduledEndTime,
description,
image: image && (await DataResolver.resolveImage(image)),
entity_type: entityType,
entity_metadata,
},
Expand Down Expand Up @@ -172,6 +176,7 @@ class GuildScheduledEventManager extends CachedManager {
* @property {GuildScheduledEventEntityMetadataOptions} [entityMetadata] The entity metadata of the
* guild scheduled event
* <warn>This can be modified only if `entityType` of the `GuildScheduledEvent` to be edited is 'EXTERNAL'</warn>
* @property {?(BufferResolvable|Base64Resolvable)} [image] The cover image of the guild scheduled event
* @property {string} [reason] The reason for editing the guild scheduled event
*/

Expand All @@ -197,6 +202,7 @@ class GuildScheduledEventManager extends CachedManager {
scheduledEndTime,
entityMetadata,
reason,
image,
} = options;

if (typeof privacyLevel === 'string') privacyLevel = PrivacyLevels[privacyLevel];
Expand All @@ -220,6 +226,7 @@ class GuildScheduledEventManager extends CachedManager {
description,
entity_type: entityType,
status,
image: image && (await DataResolver.resolveImage(image)),
entity_metadata,
},
reason,
Expand Down
10 changes: 6 additions & 4 deletions src/managers/MessageManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,25 +156,27 @@ class MessageManager extends CachedManager {
/**
* Pins a message to the channel's pinned messages, even if it's not cached.
* @param {MessageResolvable} message The message to pin
* @param {string} [reason] Reason for pinning
* @returns {Promise<void>}
*/
async pin(message) {
async pin(message, reason) {
message = this.resolveId(message);
if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');

await this.client.api.channels(this.channel.id).pins(message).put();
await this.client.api.channels(this.channel.id).pins(message).put({ reason });
}

/**
* Unpins a message from the channel's pinned messages, even if it's not cached.
* @param {MessageResolvable} message The message to unpin
* @param {string} [reason] Reason for unpinning
* @returns {Promise<void>}
*/
async unpin(message) {
async unpin(message, reason) {
message = this.resolveId(message);
if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');

await this.client.api.channels(this.channel.id).pins(message).delete();
await this.client.api.channels(this.channel.id).pins(message).delete({ reason });
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/managers/RoleManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ class RoleManager extends CachedManager {
* @example
* // Delete a role
* guild.roles.delete('222079219327434752', 'The role needed to go')
* .then(deleted => console.log(`Deleted role ${deleted.name}`))
* .then(() => console.log('Deleted the role.'))
* .catch(console.error);
*/
async delete(role, reason) {
Expand Down
2 changes: 1 addition & 1 deletion src/rest/RateLimitError.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class RateLimitError extends Error {
this.name = 'RateLimitError';

/**
* Time until this rate limit ends, in ms
* Time until this rate limit ends, in milliseconds
* @type {number}
*/
this.timeout = timeout;
Expand Down
2 changes: 1 addition & 1 deletion src/rest/RequestHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ class RequestHandler {
/**
* @typedef {Object} InvalidRequestWarningData
* @property {number} count Number of invalid requests that have been made in the window
* @property {number} remainingTime Time in ms remaining before the count resets
* @property {number} remainingTime Time in milliseconds remaining before the count resets
*/

/**
Expand Down
2 changes: 1 addition & 1 deletion src/structures/Guild.js
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ class Guild extends AnonymousGuild {
/**
* The preferred locale of the guild, defaults to `en-US`
* @type {string}
* @see {@link https://discord.com/developers/docs/dispatch/field-values#predefined-field-values-accepted-locales}
* @see {@link https://discord.com/developers/docs/reference#locales}
*/
this.preferredLocale = data.preferred_locale;
}
Expand Down
6 changes: 5 additions & 1 deletion src/structures/GuildMember.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,11 @@ class GuildMember extends Base {
* @readonly
*/
get moderatable() {
return this.manageable && (this.guild.me?.permissions.has(Permissions.FLAGS.MODERATE_MEMBERS) ?? false);
return (
!this.permissions.has(Permissions.FLAGS.ADMINISTRATOR) &&
this.manageable &&
(this.guild.me?.permissions.has(Permissions.FLAGS.MODERATE_MEMBERS) ?? false)
);
}

/**
Expand Down
10 changes: 10 additions & 0 deletions src/structures/GuildPreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const { Collection } = require('@discordjs/collection');
const Base = require('./Base');
const GuildPreviewEmoji = require('./GuildPreviewEmoji');
const { Sticker } = require('./Sticker');
const SnowflakeUtil = require('../util/SnowflakeUtil');

/**
Expand Down Expand Up @@ -103,6 +104,15 @@ class GuildPreview extends Base {
for (const emoji of data.emojis) {
this.emojis.set(emoji.id, new GuildPreviewEmoji(this.client, emoji, this));
}

/**
* Collection of stickers belonging to this guild
* @type {Collection<Snowflake, Sticker>}
*/
this.stickers = data.stickers.reduce(
(stickers, sticker) => stickers.set(sticker.id, new Sticker(this.client, sticker)),
new Collection(),
);
}
/**
* The timestamp this guild was created at
Expand Down
2 changes: 1 addition & 1 deletion src/structures/Interaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class Interaction extends Base {
/**
* The locale of the user who invoked this interaction
* @type {string}
* @see {@link https://discord.com/developers/docs/dispatch/field-values#predefined-field-values-accepted-locales}
* @see {@link https://discord.com/developers/docs/reference#locales}
*/
this.locale = data.locale;

Expand Down
10 changes: 6 additions & 4 deletions src/structures/Message.js
Original file line number Diff line number Diff line change
Expand Up @@ -720,31 +720,33 @@ class Message extends Base {

/**
* Pins this message to the channel's pinned messages.
* @param {string} [reason] Reason for pinning
* @returns {Promise<Message>}
* @example
* // Pin a message
* message.pin()
* .then(console.log)
* .catch(console.error)
*/
async pin() {
async pin(reason) {
if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
await this.channel.messages.pin(this.id);
await this.channel.messages.pin(this.id, reason);
return this;
}

/**
* Unpins this message from the channel's pinned messages.
* @param {string} [reason] Reason for unpinning
* @returns {Promise<Message>}
* @example
* // Unpin a message
* message.unpin()
* .then(console.log)
* .catch(console.error)
*/
async unpin() {
async unpin(reason) {
if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
await this.channel.messages.unpin(this.id);
await this.channel.messages.unpin(this.id, reason);
return this;
}

Expand Down
2 changes: 1 addition & 1 deletion src/structures/MessageAttachment.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class MessageAttachment {

if ('content_type' in data) {
/**
* This media type of this attachment
* The media type of this attachment
* @type {?string}
*/
this.contentType = data.content_type;
Expand Down
12 changes: 9 additions & 3 deletions src/structures/MessagePayload.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,17 @@ class MessagePayload {
}

let flags;
if ((this.isMessage && typeof this.options.reply === 'undefined') || this.isMessageManager) {
if (
typeof this.options.flags !== 'undefined' ||
(this.isMessage && typeof this.options.reply === 'undefined') ||
this.isMessageManager
) {
// eslint-disable-next-line eqeqeq
flags = this.options.flags != null ? new MessageFlags(this.options.flags).bitfield : this.target.flags?.bitfield;
} else if (isInteraction && this.options.ephemeral) {
flags = MessageFlags.FLAGS.EPHEMERAL;
}

if (isInteraction && this.options.ephemeral) {
flags |= MessageFlags.FLAGS.EPHEMERAL;
}

let allowedMentions =
Expand Down
2 changes: 1 addition & 1 deletion src/structures/MessageReaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class MessageReaction {
if (this.partial) return;
this.users.cache.set(user.id, user);
if (!this.me || user.id !== this.message.client.user.id || this.count === 0) this.count++;
this.me ??= user.id === this.message.client.user.id;
this.me ||= user.id === this.message.client.user.id;
}

_remove(user) {
Expand Down
41 changes: 30 additions & 11 deletions src/structures/Presence.js
Original file line number Diff line number Diff line change
Expand Up @@ -351,13 +351,21 @@ class RichPresenceAssets {
* @returns {?string}
*/
smallImageURL({ format, size } = {}) {
return (
this.smallImage &&
this.activity.presence.client.rest.cdn.AppAsset(this.activity.applicationId, this.smallImage, {
format,
size,
})
);
if (!this.smallImage) return null;
if (this.smallImage.includes(':')) {
const [platform, id] = this.smallImage.split(':');
switch (platform) {
case 'mp':
return `https://media.discordapp.net/${id}`;
default:
return null;
}
}

return this.activity.presence.client.rest.cdn.AppAsset(this.activity.applicationId, this.smallImage, {
format,
size,
});
}

/**
Expand All @@ -367,11 +375,22 @@ class RichPresenceAssets {
*/
largeImageURL({ format, size } = {}) {
if (!this.largeImage) return null;
if (/^spotify:/.test(this.largeImage)) {
return `https://i.scdn.co/image/${this.largeImage.slice(8)}`;
} else if (/^twitch:/.test(this.largeImage)) {
return `https://static-cdn.jtvnw.net/previews-ttv/live_user_${this.largeImage.slice(7)}.png`;
if (this.largeImage.includes(':')) {
const [platform, id] = this.largeImage.split(':');
switch (platform) {
case 'mp':
return `https://media.discordapp.net/${id}`;
case 'spotify':
return `https://i.scdn.co/image/${id}`;
case 'youtube':
return `https://i.ytimg.com/vi/${id}/hqdefault_live.jpg`;
case 'twitch':
return `https://static-cdn.jtvnw.net/previews-ttv/live_user_${id}.png`;
default:
return null;
}
}

return this.activity.presence.client.rest.cdn.AppAsset(this.activity.applicationId, this.largeImage, {
format,
size,
Expand Down
36 changes: 35 additions & 1 deletion src/structures/ThreadChannel.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ class ThreadChannel extends Channel {
* @type {?number}
*/
this.archiveTimestamp = new Date(data.thread_metadata.archive_timestamp).getTime();

if ('create_timestamp' in data.thread_metadata) {
// Note: this is needed because we can't assign directly to getters
this._createdTimestamp = Date.parse(data.thread_metadata.create_timestamp);
}
} else {
this.locked ??= null;
this.archived ??= null;
Expand All @@ -108,6 +113,8 @@ class ThreadChannel extends Channel {
this.invitable ??= null;
}

this._createdTimestamp ??= this.type === 'GUILD_PRIVATE_THREAD' ? super.createdTimestamp : null;

if ('owner_id' in data) {
/**
* The id of the member who created this thread
Expand Down Expand Up @@ -176,6 +183,16 @@ class ThreadChannel extends Channel {
if (data.messages) for (const message of data.messages) this.messages._add(message);
}

/**
* The timestamp when this thread was created. This isn't available for threads
* created before 2022-01-09
* @type {?number}
* @readonly
*/
get createdTimestamp() {
return this._createdTimestamp;
}

/**
* A collection of associated guild member objects of this thread's members
* @type {Collection<Snowflake, GuildMember>}
Expand All @@ -196,6 +213,15 @@ class ThreadChannel extends Channel {
return new Date(this.archiveTimestamp);
}

/**
* The time the thread was created at
* @type {?Date}
* @readonly
*/
get createdAt() {
return this.createdTimestamp && new Date(this.createdTimestamp);
}

/**
* The parent channel of this thread
* @type {?(NewsChannel|TextChannel)}
Expand Down Expand Up @@ -487,7 +513,15 @@ class ThreadChannel extends Channel {
* @readonly
*/
get unarchivable() {
return this.archived && (this.locked ? this.manageable : this.sendable);
return this.archived && this.sendable && (!this.locked || this.manageable);
}

/**
* Whether this thread is a private thread
* @returns {boolean}
*/
isPrivate() {
return this.type === 'GUILD_PRIVATE_THREAD';
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/structures/Webhook.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ class Webhook {
* @property {string} [avatarURL] Avatar URL override for the message
* @property {Snowflake} [threadId] The id of the thread in the channel to send to.
* <info>For interaction webhooks, this property is ignored</info>
* @property {MessageFlags} [flags] Which flags to set for the message. Only `SUPPRESS_EMBEDS` can be set.
*/

/**
Expand Down

0 comments on commit 85f5d5c

Please sign in to comment.