mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-15 02:53:31 +01:00
feat: add Message#bulkDeletable (#8760)
* feat: add `Message#bulkDeletable` * feat: add requested changes * fix: add check for `ManageMessages` permission * fix: `.permissionsFor()` exist only in guild channels * feat: apply requested changes * types: add type * fix: do not return `undefined` * fix: add property to docs Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
@@ -22,7 +22,7 @@ const { Sticker } = require('./Sticker');
|
|||||||
const { DiscordjsError, ErrorCodes } = require('../errors');
|
const { DiscordjsError, ErrorCodes } = require('../errors');
|
||||||
const ReactionManager = require('../managers/ReactionManager');
|
const ReactionManager = require('../managers/ReactionManager');
|
||||||
const { createComponent } = require('../util/Components');
|
const { createComponent } = require('../util/Components');
|
||||||
const { NonSystemMessageTypes } = require('../util/Constants');
|
const { NonSystemMessageTypes, MaxBulkDeletableMessageAge } = require('../util/Constants');
|
||||||
const MessageFlagsBitField = require('../util/MessageFlagsBitField');
|
const MessageFlagsBitField = require('../util/MessageFlagsBitField');
|
||||||
const PermissionsBitField = require('../util/PermissionsBitField');
|
const PermissionsBitField = require('../util/PermissionsBitField');
|
||||||
const { cleanContent, resolvePartialEmoji } = require('../util/Util');
|
const { cleanContent, resolvePartialEmoji } = require('../util/Util');
|
||||||
@@ -611,6 +611,25 @@ 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() {
|
||||||
|
const permissions = this.channel?.permissionsFor(this.client.user);
|
||||||
|
return (
|
||||||
|
(this.inGuild() &&
|
||||||
|
Date.now() - this.createdTimestamp < MaxBulkDeletableMessageAge &&
|
||||||
|
this.deletable &&
|
||||||
|
permissions?.has(PermissionFlagsBits.ManageMessages, false)) ??
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the message is pinnable by the client user
|
* Whether the message is pinnable by the client user
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const { Collection } = require('@discordjs/collection');
|
|||||||
const { DiscordSnowflake } = require('@sapphire/snowflake');
|
const { DiscordSnowflake } = require('@sapphire/snowflake');
|
||||||
const { InteractionType, Routes } = require('discord-api-types/v10');
|
const { InteractionType, Routes } = require('discord-api-types/v10');
|
||||||
const { DiscordjsTypeError, DiscordjsError, ErrorCodes } = require('../../errors');
|
const { DiscordjsTypeError, DiscordjsError, ErrorCodes } = require('../../errors');
|
||||||
|
const { MaxBulkDeletableMessageAge } = require('../../util/Constants');
|
||||||
const InteractionCollector = require('../InteractionCollector');
|
const InteractionCollector = require('../InteractionCollector');
|
||||||
const MessageCollector = require('../MessageCollector');
|
const MessageCollector = require('../MessageCollector');
|
||||||
const MessagePayload = require('../MessagePayload');
|
const MessagePayload = require('../MessagePayload');
|
||||||
@@ -294,7 +295,9 @@ 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() - DiscordSnowflake.timestampFrom(id) < 1_209_600_000);
|
messageIds = messageIds.filter(
|
||||||
|
id => Date.now() - DiscordSnowflake.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) {
|
||||||
|
|||||||
@@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
const { ChannelType, MessageType, ComponentType } = require('discord-api-types/v10');
|
const { ChannelType, MessageType, ComponentType } = require('discord-api-types/v10');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Max bulk deletable message age
|
||||||
|
* @typedef {number} MaxBulkDeletableMessageAge
|
||||||
|
*/
|
||||||
|
exports.MaxBulkDeletableMessageAge = 1_209_600_000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of an item to be swept in Sweepers
|
* The name of an item to be swept in Sweepers
|
||||||
* * `applicationCommands` - both global and guild commands
|
* * `applicationCommands` - both global and guild commands
|
||||||
@@ -132,6 +138,7 @@ exports.SelectMenuTypes = [
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} Constants Constants that can be used in an enum or object-like way.
|
* @typedef {Object} Constants Constants that can be used in an enum or object-like way.
|
||||||
|
* @property {number} MaxBulkDeletableMessageAge Max bulk deletable message age
|
||||||
* @property {SweeperKey[]} SweeperKeys The possible names of items that can be swept in sweepers
|
* @property {SweeperKey[]} SweeperKeys The possible names of items that can be swept in sweepers
|
||||||
* @property {NonSystemMessageTypes} NonSystemMessageTypes The types of messages that are not deemed a system type
|
* @property {NonSystemMessageTypes} NonSystemMessageTypes The types of messages that are not deemed a system type
|
||||||
* @property {TextBasedChannelTypes} TextBasedChannelTypes The types of channels that are text-based
|
* @property {TextBasedChannelTypes} TextBasedChannelTypes The types of channels that are text-based
|
||||||
|
|||||||
2
packages/discord.js/typings/index.d.ts
vendored
2
packages/discord.js/typings/index.d.ts
vendored
@@ -1774,6 +1774,7 @@ export class Message<InGuild extends boolean = boolean> extends Base {
|
|||||||
public applicationId: Snowflake | null;
|
public applicationId: Snowflake | null;
|
||||||
public attachments: Collection<Snowflake, Attachment>;
|
public attachments: Collection<Snowflake, Attachment>;
|
||||||
public author: User;
|
public author: User;
|
||||||
|
public get bulkDeletable(): boolean;
|
||||||
public get channel(): If<InGuild, GuildTextBasedChannel, TextBasedChannel>;
|
public get channel(): If<InGuild, GuildTextBasedChannel, TextBasedChannel>;
|
||||||
public channelId: Snowflake;
|
public channelId: Snowflake;
|
||||||
public get cleanContent(): string;
|
public get cleanContent(): string;
|
||||||
@@ -3294,6 +3295,7 @@ export type NonSystemMessageType =
|
|||||||
| MessageType.ContextMenuCommand;
|
| MessageType.ContextMenuCommand;
|
||||||
|
|
||||||
export const Constants: {
|
export const Constants: {
|
||||||
|
MaxBulkDeletableMessageAge: 1_209_600_000;
|
||||||
SweeperKeys: SweeperKey[];
|
SweeperKeys: SweeperKey[];
|
||||||
NonSystemMessageTypes: NonSystemMessageType[];
|
NonSystemMessageTypes: NonSystemMessageType[];
|
||||||
TextBasedChannelTypes: TextBasedChannelTypes[];
|
TextBasedChannelTypes: TextBasedChannelTypes[];
|
||||||
|
|||||||
Reference in New Issue
Block a user