feat: add Message#bulkDeletable (v13)

#8761 djs
This commit is contained in:
March 7th 2022-11-26 22:17:33 +07:00
parent 69c5eb94d2
commit f8a8ac7fc6
5 changed files with 49 additions and 4 deletions

View File

@ -154,6 +154,7 @@ const Messages = {
INTERACTION_ALREADY_REPLIED: 'The reply to this interaction has already been sent or deferred.', INTERACTION_ALREADY_REPLIED: 'The reply to this interaction has already been sent or deferred.',
INTERACTION_NOT_REPLIED: 'The reply to this interaction has not been sent or deferred.', INTERACTION_NOT_REPLIED: 'The reply to this interaction has not been sent or deferred.',
/** @deprecated */
INTERACTION_EPHEMERAL_REPLIED: 'Ephemeral responses cannot be deleted.', INTERACTION_EPHEMERAL_REPLIED: 'Ephemeral responses cannot be deleted.',
COMMAND_INTERACTION_OPTION_NOT_FOUND: name => `Required option "${name}" not found.`, COMMAND_INTERACTION_OPTION_NOT_FOUND: name => `Required option "${name}" not found.`,

View File

@ -15,7 +15,7 @@ const ReactionCollector = require('./ReactionCollector');
const { Sticker } = require('./Sticker'); const { Sticker } = require('./Sticker');
const { Error } = require('../errors'); const { Error } = require('../errors');
const ReactionManager = require('../managers/ReactionManager'); const ReactionManager = require('../managers/ReactionManager');
const { InteractionTypes, MessageTypes, SystemMessageTypes } = require('../util/Constants'); const { InteractionTypes, MessageTypes, SystemMessageTypes, MaxBulkDeletableMessageAge } = require('../util/Constants');
const MessageFlags = require('../util/MessageFlags'); const MessageFlags = require('../util/MessageFlags');
const Permissions = require('../util/Permissions'); const Permissions = require('../util/Permissions');
const SnowflakeUtil = require('../util/SnowflakeUtil'); const SnowflakeUtil = require('../util/SnowflakeUtil');
@ -641,6 +641,26 @@ class Message extends Base {
); );
} }
/**
* Whether the message is bulk deletable by the client user
* @type {boolean}
* @readonly
* @example
* // Filter for bulk deletable messages
* 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() &&
Date.now() - this.createdTimestamp < MaxBulkDeletableMessageAge &&
this.deletable &&
permissions?.has(Permissions.FLAGS.MANAGE_MESSAGES, false)) ??
false
);
}
/** /**
* Whether the message is pinnable by the client user * Whether the message is pinnable by the client user
* @type {boolean} * @type {boolean}

View File

@ -6,7 +6,7 @@ const MessageCollector = require('../MessageCollector');
const MessagePayload = require('../MessagePayload'); const MessagePayload = require('../MessagePayload');
const SnowflakeUtil = require('../../util/SnowflakeUtil'); const SnowflakeUtil = require('../../util/SnowflakeUtil');
const { Collection } = require('@discordjs/collection'); const { Collection } = require('@discordjs/collection');
const { InteractionTypes } = require('../../util/Constants'); const { InteractionTypes, MaxBulkDeletableMessageAge } = require('../../util/Constants');
const { TypeError, Error } = require('../../errors'); const { TypeError, Error } = require('../../errors');
const InteractionCollector = require('../InteractionCollector'); const InteractionCollector = require('../InteractionCollector');
const { lazy } = require('../../util/Util'); const { lazy } = require('../../util/Util');
@ -314,7 +314,7 @@ class TextBasedChannel {
if (Array.isArray(messages) || messages instanceof Collection) { if (Array.isArray(messages) || messages instanceof Collection) {
let messageIds = messages instanceof Collection ? [...messages.keys()] : messages.map(m => m.id ?? m); let messageIds = messages instanceof Collection ? [...messages.keys()] : messages.map(m => m.id ?? m);
if (filterOld) { if (filterOld) {
messageIds = messageIds.filter(id => Date.now() - SnowflakeUtil.timestampFrom(id) < 1_209_600_000); messageIds = messageIds.filter(id => Date.now() - SnowflakeUtil.timestampFrom(id) < MaxBulkDeletableMessageAge);
} }
if (messageIds.length === 0) return new Collection(); if (messageIds.length === 0) return new Collection();
if (messageIds.length === 1) { if (messageIds.length === 1) {

View File

@ -30,6 +30,12 @@ const listUserAgent = [
'Mozilla/5.0 (Macintosh; Intel Mac OS X 13_0_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.52', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 13_0_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.52',
]; ];
/**
* Max bulk deletable message age
* @typedef {number} MaxBulkDeletableMessageAge
*/
exports.MaxBulkDeletableMessageAge = 1_209_600_000;
/** /**
* API captcha solver * API captcha solver
* * `2captcha` - 2captcha.com * * `2captcha` - 2captcha.com
@ -1738,6 +1744,7 @@ function createEnum(keys) {
* @property {SweeperKey[]} SweeperKeys The name of an item to be swept in Sweepers. * @property {SweeperKey[]} SweeperKeys The name of an item to be swept in Sweepers.
* @property {SystemMessageType[]} SystemMessageTypes The types of messages that are `System`. * @property {SystemMessageType[]} SystemMessageTypes The types of messages that are `System`.
* @property {Object<TextInputStyle, number>} TextInputStyles The style of a text input component. * @property {Object<TextInputStyle, number>} TextInputStyles The style of a text input component.
* @property {number} MaxBulkDeletableMessageAge Max bulk deletable message age
* @property {string} UserAgent The user agent used for requests. * @property {string} UserAgent The user agent used for requests.
* @property {Object<VerificationLevel, number>} VerificationLevels * @property {Object<VerificationLevel, number>} VerificationLevels
* The value set for the verification levels for a guild. * The value set for the verification levels for a guild.

19
typings/index.d.ts vendored
View File

@ -82,6 +82,9 @@ import {
MessageTypes, MessageTypes,
ModalComponentTypes, ModalComponentTypes,
MFALevels, MFALevels,
NitroType as NitroTypes,
HypeSquadType as HypeSquadTypes,
localeSetting as localeSettings,
NSFWLevels, NSFWLevels,
OverwriteTypes, OverwriteTypes,
PremiumTiers, PremiumTiers,
@ -1903,6 +1906,7 @@ export class Message<Cached extends boolean = boolean> extends Base {
public applicationId: Snowflake | null; public applicationId: Snowflake | null;
public attachments: Collection<Snowflake, MessageAttachment>; public attachments: Collection<Snowflake, MessageAttachment>;
public author: User; public author: User;
public readonly bulkDeletable: boolean;
public readonly channel: If<Cached, GuildTextBasedChannel, TextBasedChannel>; public readonly channel: If<Cached, GuildTextBasedChannel, TextBasedChannel>;
public channelId: Snowflake; public channelId: Snowflake;
public readonly cleanContent: string; public readonly cleanContent: string;
@ -3402,9 +3406,10 @@ export const Constants: {
devDependencies: Record<string, string>; devDependencies: Record<string, string>;
[key: string]: unknown; [key: string]: unknown;
}; };
MaxBulkDeletableMessageAge: 1_209_600_000;
UserAgent: string;
Endpoints: { Endpoints: {
botGateway: string; botGateway: string;
userGateway: string;
invite: (root: string, code: string, eventId?: Snowflake) => string; invite: (root: string, code: string, eventId?: Snowflake) => string;
scheduledEvent: (root: string, guildId: Snowflake, eventId: Snowflake) => string; scheduledEvent: (root: string, guildId: Snowflake, eventId: Snowflake) => string;
CDN: (root: string) => { CDN: (root: string) => {
@ -3507,6 +3512,8 @@ export const Constants: {
InteractionResponseTypes: EnumHolder<typeof InteractionResponseTypes>; InteractionResponseTypes: EnumHolder<typeof InteractionResponseTypes>;
MessageComponentTypes: EnumHolder<typeof MessageComponentTypes>; MessageComponentTypes: EnumHolder<typeof MessageComponentTypes>;
MessageButtonStyles: EnumHolder<typeof MessageButtonStyles>; MessageButtonStyles: EnumHolder<typeof MessageButtonStyles>;
ModalComponentTypes: EnumHolder<typeof ModalComponentTypes>;
TextInputStyles: EnumHolder<typeof TextInputStyles>;
MFALevels: EnumHolder<typeof MFALevels>; MFALevels: EnumHolder<typeof MFALevels>;
NSFWLevels: EnumHolder<typeof NSFWLevels>; NSFWLevels: EnumHolder<typeof NSFWLevels>;
PrivacyLevels: EnumHolder<typeof PrivacyLevels>; PrivacyLevels: EnumHolder<typeof PrivacyLevels>;
@ -3516,7 +3523,17 @@ export const Constants: {
GuildScheduledEventEntityTypes: EnumHolder<typeof GuildScheduledEventEntityTypes>; GuildScheduledEventEntityTypes: EnumHolder<typeof GuildScheduledEventEntityTypes>;
GuildScheduledEventStatuses: EnumHolder<typeof GuildScheduledEventStatuses>; GuildScheduledEventStatuses: EnumHolder<typeof GuildScheduledEventStatuses>;
GuildScheduledEventPrivacyLevels: EnumHolder<typeof GuildScheduledEventPrivacyLevels>; GuildScheduledEventPrivacyLevels: EnumHolder<typeof GuildScheduledEventPrivacyLevels>;
VideoQualityModes: EnumHolder<typeof VideoQualityModes>;
SweeperKeys: SweeperKey[];
// Add
randomUA: () => string; randomUA: () => string;
captchaServices: string[];
DMScanLevel: EnumHolder<typeof DMScanLevel>;
stickerAnimationMode: EnumHolder<typeof stickerAnimationMode>;
NitroType: EnumHolder<typeof NitroTypes>;
HypeSquadType: EnumHolder<typeof HypeSquadTypes>;
localeSetting: EnumHolder<typeof localeSettings>;
userGateway: string;
}; };
export const version: string; export const version: string;