chore: Miscellaneous fixes

#9271 djs

> Backports the following pull requests to version 13:
>
> * docs: describe private properties #8879
> * fix(snowflake): snowflakes length #9144
> * fix(Message): `bulkDeletable` permissions should be retrieved later for DMs #9146
> * fix(Message#editable): update editable check in threads locked #9216
> * fix: add support for new guild feature `GUILD_WEB_PAGE_VANITY_URL` #9219
> * fix(AutocompleteInteraction): Send `name_localizations` correctly #9238
> * fix(ThreadManager): Respect `cache` and `force` in fetching #9239
> * docs(FetchArchivedThreadOptions): `before` respects `archive_timestamp`, not creation timestamp #9240
> * refactor(FetchThreadsOptions): Remove `active` #9241
> * docs: differ `User#send` #9251
> * docs: add more examples #9252
> * fix(ClientUser): No mutation on edit #9259
> * fix: resolving string bitfield #9262
> * refactor: call `GuildBanManager#create()` directly #9263
> * docs(Role): Fix example for `comparePositionTo()` #9270
> * docs: fix compare position example #9272
> * fix: Keep symbols in actions manager #9293
This commit is contained in:
Elysia
2023-04-02 12:46:18 +07:00
parent 89fe3a5f7e
commit d1d842098a
14 changed files with 108 additions and 79 deletions

View File

@@ -95,9 +95,7 @@ class AutocompleteInteraction extends Interaction {
await this.client.api.interactions(this.id, this.token).callback.post({
data: {
type: InteractionResponseTypes.APPLICATION_COMMAND_AUTOCOMPLETE_RESULT,
data: {
choices: options,
},
data: { choices: { ...options, name_localizations: options.nameLocalizations } },
},
auth: false,
});

View File

@@ -142,17 +142,13 @@ class ClientUser extends User {
* @param {ClientUserEditData} data The new data
* @returns {Promise<ClientUser>}
*/
async edit(data) {
if (typeof data.avatar !== 'undefined') {
data.avatar = await DataResolver.resolveImage(data.avatar);
}
if (typeof data.banner !== 'undefined') {
data.banner = await DataResolver.resolveImage(data.banner);
}
const newData = await this.client.api.users('@me').patch({ data });
this.client.token = newData.token;
this.client.password = data?.password ? data?.password : this.client.password;
const { updated } = this.client.actions.UserUpdate.handle(newData);
async edit({ username, avatar }) {
const data = await this.client.api
.users('@me')
.patch({ username, avatar: avatar && (await DataResolver.resolveImage(avatar)) });
this.client.token = data.token;
const { updated } = this.client.actions.UserUpdate.handle(data);
return updated ?? this;
}

View File

@@ -769,9 +769,6 @@ class Guild extends AnonymousGuild {
* .catch(console.error);
*/
async fetchVanityData() {
if (!this.features.includes('VANITY_URL')) {
throw new Error('VANITY_URL');
}
const data = await this.client.api.guilds(this.id, 'vanity-url').get();
this.vanityURLCode = data.code;
this.vanityURLUses = data.uses;
@@ -1462,7 +1459,7 @@ class Guild extends AnonymousGuild {
* @example
* // Leave a guild
* guild.leave()
* .then(g => console.log(`Left the guild ${g}`))
* .then(guild => console.log(`Left the guild ${guild.name}`))
* .catch(console.error);
*/
async leave() {
@@ -1488,7 +1485,7 @@ class Guild extends AnonymousGuild {
* @example
* // Delete a guild
* guild.delete()
* .then(g => console.log(`Deleted the guild ${g}`))
* .then(guild => console.log(`Deleted the guild ${guild.name}`))
* .catch(console.error);
*/
async delete() {
@@ -1634,9 +1631,6 @@ class Guild extends AnonymousGuild {
* .catch(console.error);
*/
async setVanityCode(code = '') {
if (!this.features.includes('VANITY_URL')) {
throw new Error('VANITY_URL');
}
if (typeof code !== 'string') throw new TypeError('INVALID_VANITY_URL_CODE');
const data = await this.client.api.guilds(this.id, 'vanity-url').patch({
data: { code },

View File

@@ -63,6 +63,11 @@ class GuildMember extends Base {
*/
this.communicationDisabledUntilTimestamp = null;
/**
* The role ids of the member
* @type {Snowflake[]}
* @private
*/
this._roles = [];
if (data) this._patch(data);
}
@@ -414,6 +419,16 @@ class GuildMember extends Base {
* @param {?string} nick The nickname for the guild member, or `null` if you want to reset their nickname
* @param {string} [reason] Reason for setting the nickname
* @returns {Promise<GuildMember>}
* @example
* // Set a nickname for a guild member
* guildMember.setNickname('cool nickname', 'Needed a new nickname')
* .then(member => console.log(`Set nickname of ${member.user.username}`))
* .catch(console.error);
* @example
* // Remove a nickname for a guild member
* guildMember.setNickname(null, 'No nicknames allowed!')
* .then(member => console.log(`Removed nickname for ${member.user.username}`))
* .catch(console.error);
*/
setNickname(nick, reason) {
return this.edit({ nick }, reason);
@@ -539,7 +554,7 @@ class GuildMember extends Base {
* .catch(console.error);
*/
ban(options) {
return this.guild.members.ban(this, options);
return this.guild.bans.create(this, options);
}
/**
@@ -553,6 +568,11 @@ class GuildMember extends Base {
* guildMember.disableCommunicationUntil(Date.now() + (5 * 60 * 1000), 'They deserved it')
* .then(console.log)
* .catch(console.error);
* @example
* // Remove the timeout of a guild member
* guildMember.disableCommunicationUntil(null)
* .then(member => console.log(`Removed timeout for ${member.displayName}`))
* .catch(console.error);
*/
disableCommunicationUntil(communicationDisabledUntil, reason) {
return this.edit({ communicationDisabledUntil }, reason);
@@ -639,12 +659,22 @@ class GuildMember extends Base {
json.displayAvatarURL = this.displayAvatarURL();
return json;
}
// These are here only for documentation purposes - they are implemented by TextBasedChannel
/* eslint-disable no-empty-function */
send() {}
}
/**
* Sends a message to this user.
* @method send
* @memberof GuildMember
* @instance
* @param {string|MessagePayload|MessageOptions} options The options to provide
* @returns {Promise<Message>}
* @example
* // Send a direct message
* guildMember.send('Hello!')
* .then(message => console.log(`Sent message: ${message.content} to ${guildMember.displayName}`))
* .catch(console.error);
*/
TextBasedChannel.applyToClass(GuildMember);
exports.GuildMember = GuildMember;

View File

@@ -21,7 +21,6 @@ const MessageFlags = require('../util/MessageFlags');
const Permissions = require('../util/Permissions');
const SnowflakeUtil = require('../util/SnowflakeUtil');
const Util = require('../util/Util');
// Const { ApplicationCommand } = require('discord.js-selfbot-v13'); - Not being used in this file, not necessary.
/**
* @type {WeakSet<Message>}
@@ -337,10 +336,7 @@ class Message extends Base {
}
if (data.referenced_message) {
this.channel?.messages._add({
guild_id: data.message_reference?.guild_id,
...data.referenced_message,
});
this.channel?.messages._add({ guild_id: data.message_reference?.guild_id, ...data.referenced_message });
}
/**
@@ -605,11 +601,17 @@ class Message extends Base {
const precheck = Boolean(
this.author.id === this.client.user.id && !deletedMessages.has(this) && (!this.guild || this.channel?.viewable),
);
// Regardless of permissions thread messages cannot be edited if
// the thread is locked.
// the thread is archived or the thread is locked and the bot does not have permission to manage threads.
if (this.channel?.isThread()) {
return precheck && !this.channel.locked;
if (this.channel.archived) return false;
if (this.channel.locked) {
const permissions = this.permissionsFor(this.client.user);
if (!permissions?.has(Permissions.FLAGS.MANAGE_THREADS, true)) return false;
}
}
return precheck;
}
@@ -651,13 +653,12 @@ class Message extends Base {
* channel.bulkDelete(messages.filter(message => message.bulkDeletable));
*/
get bulkDeletable() {
if (!this.client.user.bot) return false;
const permissions = this.channel?.permissionsFor(this.client.user);
return (
(this.inGuild() &&
this.client.user.bot &&
Date.now() - this.createdTimestamp < MaxBulkDeletableMessageAge &&
this.deletable &&
permissions?.has(Permissions.FLAGS.MANAGE_MESSAGES, false)) ??
this.channel?.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_MESSAGES, false)) ??
false
);
}
@@ -901,9 +902,7 @@ class Message extends Base {
if (!['GUILD_TEXT', 'GUILD_NEWS'].includes(this.channel.type)) {
return Promise.reject(new Error('MESSAGE_THREAD_PARENT'));
}
if (this.hasThread) {
return Promise.reject(new Error('MESSAGE_EXISTING_THREAD'));
}
if (this.hasThread) return Promise.reject(new Error('MESSAGE_EXISTING_THREAD'));
return this.channel.threads.create({ ...options, startMessage: this });
}
@@ -923,9 +922,7 @@ class Message extends Base {
*/
fetchWebhook() {
if (!this.webhookId) return Promise.reject(new Error('WEBHOOK_MESSAGE'));
if (this.webhookId === this.applicationId) {
return Promise.reject(new Error('WEBHOOK_APPLICATION'));
}
if (this.webhookId === this.applicationId) return Promise.reject(new Error('WEBHOOK_APPLICATION'));
return this.client.fetchWebhook(this.webhookId);
}
@@ -974,9 +971,7 @@ class Message extends Base {
equals(message, rawData) {
if (!message) return false;
const embedUpdate = !message.author && !message.attachments;
if (embedUpdate) {
return this.id === message.id && this.embeds.length === message.embeds.length;
}
if (embedUpdate) return this.id === message.id && this.embeds.length === message.embeds.length;
let equal =
this.id === message.id &&

View File

@@ -176,6 +176,12 @@ class Presence extends Base {
*/
class Activity {
constructor(presence, data) {
/**
* The presence of the Activity
* @type {Presence}
* @readonly
* @name Activity#presence
*/
Object.defineProperty(this, 'presence', { value: presence });
/**
@@ -346,6 +352,12 @@ class Activity {
*/
class RichPresenceAssets {
constructor(activity, assets) {
/**
* The activity of the RichPresenceAssets
* @type {Activity}
* @readonly
* @name RichPresenceAssets#activity
*/
Object.defineProperty(this, 'activity', { value: activity });
/**

View File

@@ -233,6 +233,10 @@ class Role extends Base {
* @param {RoleResolvable} role Role to compare to this one
* @returns {number} Negative number if this role's position is lower (other role's is higher),
* positive number if this one is higher (other's is lower), 0 if equal
* @example
* // Compare the position of a role to another
* const roleCompare = role.comparePositionTo(otherRole);
* if (roleCompare >= 1) console.log(`${role.name} is higher than ${otherRole.name}`);
*/
comparePositionTo(role) {
return this.guild.roles.comparePositions(this, role);

View File

@@ -645,12 +645,22 @@ class User extends Base {
);
return data;
}
// These are here only for documentation purposes - they are implemented by TextBasedChannel
/* eslint-disable no-empty-function */
send() {}
}
/**
* Sends a message to this user.
* @method send
* @memberof User
* @instance
* @param {string|MessagePayload|MessageOptions} options The options to provide
* @returns {Promise<Message>}
* @example
* // Send a direct message
* user.send('Hello!')
* .then(message => console.log(`Sent message: ${message.content} to ${user.tag}`))
* .catch(console.error);
*/
TextBasedChannel.applyToClass(User);
module.exports = User;

View File

@@ -155,25 +155,6 @@ class TextBasedChannel {
* })
* .then(console.log)
* .catch(console.error);
* @example
* // Send an embed with a local image inside
* channel.send({
* content: 'This is an embed',
* embeds: [
* {
* thumbnail: {
* url: 'attachment://file.jpg'
* }
* }
* ],
* files: [{
* attachment: 'entire/path/to/file.jpg',
* name: 'file.jpg'
* description: 'A description of the file'
* }]
* })
* .then(console.log)
* .catch(console.error);
*/
async send(options) {
const User = require('../User');