mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-09 16:13:31 +01:00
Clean up Message#mentions and message updates
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
const Action = require('./Action');
|
||||
const Constants = require('../../util/Constants');
|
||||
const Message = require('../../structures/Message');
|
||||
|
||||
class MessageUpdateAction extends Action {
|
||||
handle(data) {
|
||||
@@ -10,14 +9,11 @@ class MessageUpdateAction extends Action {
|
||||
if (channel) {
|
||||
const message = channel.messages.get(data.id);
|
||||
if (message) {
|
||||
const newMessage = new Message(message.channel, this.patchDataPacket(data, message), client);
|
||||
newMessage._edits.push(message, ...message._edits);
|
||||
newMessage.reactions = message.reactions;
|
||||
channel.messages.set(data.id, newMessage);
|
||||
client.emit(Constants.Events.MESSAGE_UPDATE, message, newMessage);
|
||||
message.patch(data);
|
||||
client.emit(Constants.Events.MESSAGE_UPDATE, message._edits[0], message);
|
||||
return {
|
||||
old: message,
|
||||
updated: newMessage,
|
||||
old: message._edits[0],
|
||||
updated: message,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -32,29 +28,6 @@ class MessageUpdateAction extends Action {
|
||||
updated: null,
|
||||
};
|
||||
}
|
||||
|
||||
patchDataPacket(data, message) {
|
||||
data.type = 'type' in data ? data.type : Constants.MessageTypes.indexOf(message.type);
|
||||
data.tts = 'tts' in data ? data.tts : message.tts;
|
||||
data.timestamp = 'timestamp' in data ? data.timestamp : message.createdAt.toString();
|
||||
data.pinned = 'pinned' in data ? data.pinned : message.pinned;
|
||||
data.nonce = 'nonce' in data ? data.nonce : message.nonce;
|
||||
data.mentions = 'mentions' in data ? data.mentions : message.mentions.users.keyArray();
|
||||
data.mentions_roles = 'mentions_roles' in data ?
|
||||
data.mentions_roles : message.mentions.roles.keyArray();
|
||||
data.mention_everyone = 'mention_everyone' in data ? data.mention_everyone : message.mentions.everyone;
|
||||
data.embeds = 'embeds' in data ? data.embeds : message.embeds;
|
||||
data.content = 'content' in data ? data.content : message.content;
|
||||
data.author = 'author' in data ? data.author : {
|
||||
username: message.author.username,
|
||||
id: message.author.id,
|
||||
discriminator: message.author.discriminator,
|
||||
avatar: message.author.avatar,
|
||||
};
|
||||
data.attachments = 'attachments' in data ? data.attachments : message.attachments.array();
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
const Mentions = require('./MessageMentions');
|
||||
const Attachment = require('./MessageAttachment');
|
||||
const Embed = require('./MessageEmbed');
|
||||
const MessageReaction = require('./MessageReaction');
|
||||
@@ -110,69 +111,11 @@ class Message {
|
||||
*/
|
||||
this.editedTimestamp = data.edited_timestamp ? new Date(data.edited_timestamp).getTime() : null;
|
||||
|
||||
/**
|
||||
* An object containing a further users, roles or channels collections
|
||||
* @type {Object}
|
||||
* @property {Collection<Snowflake, User>} mentions.users Mentioned users, maps their ID to the user object.
|
||||
* @property {Collection<Snowflake, GuildMember>} mentions.members Mentioned members, maps their ID
|
||||
* to the member object.
|
||||
* @property {Collection<Snowflake, Role>} mentions.roles Mentioned roles, maps their ID to the role object.
|
||||
* @property {Collection<Snowflake, GuildChannel>} mentions.channels Mentioned channels,
|
||||
* maps their ID to the channel object.
|
||||
* @property {boolean} mentions.everyone Whether or not @everyone was mentioned.
|
||||
*/
|
||||
this.mentions = {
|
||||
users: new Collection(),
|
||||
roles: new Collection(),
|
||||
channels: new Collection(),
|
||||
everyone: data.mention_everyone,
|
||||
};
|
||||
|
||||
// Add user mentions
|
||||
for (const mention of data.mentions) {
|
||||
let user = this.client.users.get(mention.id);
|
||||
if (!user) user = this.client.dataManager.newUser(mention);
|
||||
this.mentions.users.set(user.id, user);
|
||||
}
|
||||
|
||||
// Add getter for member mentions
|
||||
Object.defineProperty(this.mentions, 'members', {
|
||||
get: () => {
|
||||
if (this.channel.type !== 'text') return null;
|
||||
const members = new Collection();
|
||||
this.mentions.users.forEach(user => {
|
||||
const member = this.client.resolver.resolveGuildMember(this.channel.guild, user);
|
||||
if (member) members.set(member.id, member);
|
||||
});
|
||||
return members;
|
||||
},
|
||||
});
|
||||
|
||||
// Add role mentions
|
||||
if (data.mention_roles) {
|
||||
for (const mention of data.mention_roles) {
|
||||
const role = this.channel.guild.roles.get(mention);
|
||||
if (role) this.mentions.roles.set(role.id, role);
|
||||
}
|
||||
}
|
||||
|
||||
// Add channel mentions
|
||||
if (this.channel.type === 'text') {
|
||||
const channMentionsRaw = data.content.match(/<#([0-9]{14,20})>/g) || [];
|
||||
for (const raw of channMentionsRaw) {
|
||||
const chan = this.channel.guild.channels.get(raw.match(/([0-9]{14,20})/g)[0]);
|
||||
if (chan) this.mentions.channels.set(chan.id, chan);
|
||||
}
|
||||
}
|
||||
|
||||
this._edits = [];
|
||||
|
||||
/**
|
||||
* A collection of reactions to this message, mapped by the reaction "id".
|
||||
* @type {Collection<Snowflake, MessageReaction>}
|
||||
*/
|
||||
this.reactions = new Collection();
|
||||
|
||||
if (data.reactions && data.reactions.length > 0) {
|
||||
for (const reaction of data.reactions) {
|
||||
const id = reaction.emoji.id ? `${reaction.emoji.name}:${reaction.emoji.id}` : reaction.emoji.name;
|
||||
@@ -180,6 +123,12 @@ class Message {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All valid mentions that the message contains
|
||||
* @type {MessageMentions}
|
||||
*/
|
||||
this.mentions = new Mentions(this, data.mentions, data.mentions_roles, data.mention_everyone);
|
||||
|
||||
/**
|
||||
* ID of the webhook that sent the message, if applicable
|
||||
* @type {?Snowflake}
|
||||
@@ -191,6 +140,44 @@ class Message {
|
||||
* @type {?boolean}
|
||||
*/
|
||||
this.hit = typeof data.hit === 'boolean' ? data.hit : null;
|
||||
|
||||
/**
|
||||
* The previous versions of the message, sorted with the most recent first
|
||||
* @type {Message[]}
|
||||
* @private
|
||||
*/
|
||||
this._edits = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the message
|
||||
* @param {Object} data Raw Discord message update data
|
||||
* @private
|
||||
*/
|
||||
patch(data) {
|
||||
const clone = Util.cloneObject(this);
|
||||
this._edits.unshift(clone);
|
||||
|
||||
this.editedTimestamp = data.edited_timestamp;
|
||||
if ('content' in data) this.content = data.content;
|
||||
if ('pinned' in data) this.pinned = data.pinned;
|
||||
if ('tts' in data) this.tts = data.tts;
|
||||
if ('embeds' in data) this.embeds = data.embeds.map(e => new Embed(this, e));
|
||||
else this.embeds = new Collection(this.embeds);
|
||||
|
||||
if ('attachments' in data) {
|
||||
this.attachments = new Collection();
|
||||
for (const attachment of data.attachments) this.attachments.set(attachment.id, new Attachment(this, attachment));
|
||||
} else {
|
||||
this.attachments = new Collection(this.attachments);
|
||||
}
|
||||
|
||||
this.mentions = new Mentions(
|
||||
this,
|
||||
'mentions' in data ? data.mentions : this.mentions.users,
|
||||
'mentions_roles' in data ? data.mentions_roles : this.mentions.roles,
|
||||
'mention_everyone' in data ? data.mention_everyone : this.mentions.everyone
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
145
src/structures/MessageMentions.js
Normal file
145
src/structures/MessageMentions.js
Normal file
@@ -0,0 +1,145 @@
|
||||
const Collection = require('../util/Collection');
|
||||
|
||||
/**
|
||||
* Keeps track of mentions in a {@link Message}
|
||||
*/
|
||||
class MessageMentions {
|
||||
/**
|
||||
* @param {Message} message Message to read mentions from
|
||||
* @param {?Array<Object>} users Raw user objects from Discord
|
||||
* @param {?Array<Object>} roles Raw role objects from Discord
|
||||
* @param {?boolean} everyone Whether @everyone or @here were mentioned
|
||||
* @private
|
||||
*/
|
||||
constructor(message, users, roles, everyone) {
|
||||
/**
|
||||
* Whether `@everyone` or ``@here` were mentioned
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.everyone = Boolean(everyone);
|
||||
|
||||
if (users) {
|
||||
if (users instanceof Collection) {
|
||||
/**
|
||||
* Any users that were mentioned
|
||||
* @type {Collection<Snowflake, User>}
|
||||
*/
|
||||
this.users = new Collection(users);
|
||||
} else {
|
||||
this.users = new Collection();
|
||||
for (const mention of users) {
|
||||
let user = message.client.users.get(mention.id);
|
||||
if (!user) user = message.client.dataManager.newUser(mention);
|
||||
this.users.set(user.id, user);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.users = new Collection();
|
||||
}
|
||||
|
||||
if (roles) {
|
||||
if (roles instanceof Collection) {
|
||||
/**
|
||||
* Any roles that were mentioned
|
||||
* @type {Collection<Snowflake, Role>}
|
||||
*/
|
||||
this.roles = new Collection(roles);
|
||||
} else {
|
||||
this.roles = new Collection();
|
||||
for (const mention of roles) {
|
||||
const role = message.channel.guild.roles.get(mention);
|
||||
if (role) this.roles.set(role.id, role);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.roles = new Collection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Content of the message
|
||||
* @type {Message}
|
||||
* @private
|
||||
*/
|
||||
this._content = message.content;
|
||||
|
||||
/**
|
||||
* Guild the message is in
|
||||
* @type {?Guild}
|
||||
* @private
|
||||
*/
|
||||
this._guild = message.channel.guild;
|
||||
|
||||
/**
|
||||
* Cached members for {@MessageMention#members}
|
||||
* @type {?Collection<Snowflake, GuildMember>}
|
||||
* @private
|
||||
*/
|
||||
this._members = null;
|
||||
|
||||
/**
|
||||
* Cached channels for {@MessageMention#channels}
|
||||
* @type {?Collection<Snowflake, GuildChannel>}
|
||||
* @private
|
||||
*/
|
||||
this._channels = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Any members that were mentioned (only in {@link TextChannel}s)
|
||||
* @type {?Collection<Snowflake, GuildMember>}
|
||||
* @readonly
|
||||
*/
|
||||
get members() {
|
||||
if (this._members) return this._members;
|
||||
if (!this.guild) return null;
|
||||
this._members = new Collection();
|
||||
this.users.forEach(user => {
|
||||
const member = this._guild.member(user);
|
||||
if (member) this._members.set(member.user.id, member);
|
||||
});
|
||||
return this._members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Any channels that were mentioned (only in {@link TextChannel}s)
|
||||
* @type {?Collection<Snowflake, GuildChannel>}
|
||||
* @readonly
|
||||
*/
|
||||
get channels() {
|
||||
if (this._channels) return this._channels;
|
||||
if (!this.guild) return null;
|
||||
this._channels = new Collection();
|
||||
let matches;
|
||||
while ((matches = this.constructor.CHANNELS_PATTERN.exec(this._content)) !== null) {
|
||||
const chan = this._guild.channels.get(matches[1]);
|
||||
if (chan) this._channels.set(chan.id, chan);
|
||||
}
|
||||
return this._channels;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Regular expression that globally matches `@everyone` and `@here`
|
||||
* @type {RegExp}
|
||||
*/
|
||||
MessageMentions.EVERYONE_PATTERN = /@(everyone|here)/g;
|
||||
|
||||
/**
|
||||
* Regular expression that globally matches user mentions like `<#81440962496172032>`
|
||||
* @type {RegExp}
|
||||
*/
|
||||
MessageMentions.USERS_PATTERN = /<@!?[0-9]+>/g;
|
||||
|
||||
/**
|
||||
* Regular expression that globally matches role mentions like `<@&297577916114403338>`
|
||||
* @type {RegExp}
|
||||
*/
|
||||
MessageMentions.ROLES_PATTERN = /<@&[0-9]+>/g;
|
||||
|
||||
/**
|
||||
* Regular expression that globally matches channel mentions like `<#222079895583457280>`
|
||||
* @type {RegExp}
|
||||
*/
|
||||
MessageMentions.CHANNELS_PATTERN = /<#([0-9]+)>/g;
|
||||
|
||||
module.exports = MessageMentions;
|
||||
Reference in New Issue
Block a user