buddy

node MVC discord bot
Log | Files | Refs | README

MessageMentions.js (6887B)


      1 'use strict';
      2 
      3 const Collection = require('../util/Collection');
      4 const { ChannelTypes } = require('../util/Constants');
      5 const Util = require('../util/Util');
      6 
      7 /**
      8  * Keeps track of mentions in a {@link Message}.
      9  */
     10 class MessageMentions {
     11   constructor(message, users, roles, everyone, crosspostedChannels) {
     12     /**
     13      * The client the message is from
     14      * @type {Client}
     15      * @readonly
     16      */
     17     Object.defineProperty(this, 'client', { value: message.client });
     18 
     19     /**
     20      * The guild the message is in
     21      * @type {?Guild}
     22      * @readonly
     23      */
     24     Object.defineProperty(this, 'guild', { value: message.guild });
     25 
     26     /**
     27      * The initial message content
     28      * @type {string}
     29      * @readonly
     30      * @private
     31      */
     32     Object.defineProperty(this, '_content', { value: message.content });
     33 
     34     /**
     35      * Whether `@everyone` or `@here` were mentioned
     36      * @type {boolean}
     37      */
     38     this.everyone = Boolean(everyone);
     39 
     40     if (users) {
     41       if (users instanceof Collection) {
     42         /**
     43          * Any users that were mentioned
     44          * <info>Order as received from the API, not as they appear in the message content</info>
     45          * @type {Collection<Snowflake, User>}
     46          */
     47         this.users = new Collection(users);
     48       } else {
     49         this.users = new Collection();
     50         for (const mention of users) {
     51           if (mention.member && message.guild) {
     52             message.guild.members.add(Object.assign(mention.member, { user: mention }));
     53           }
     54           const user = message.client.users.add(mention);
     55           this.users.set(user.id, user);
     56         }
     57       }
     58     } else {
     59       this.users = new Collection();
     60     }
     61 
     62     if (roles) {
     63       if (roles instanceof Collection) {
     64         /**
     65          * Any roles that were mentioned
     66          * <info>Order as received from the API, not as they appear in the message content</info>
     67          * @type {Collection<Snowflake, Role>}
     68          */
     69         this.roles = new Collection(roles);
     70       } else {
     71         this.roles = new Collection();
     72         for (const mention of roles) {
     73           const role = message.channel.guild.roles.cache.get(mention);
     74           if (role) this.roles.set(role.id, role);
     75         }
     76       }
     77     } else {
     78       this.roles = new Collection();
     79     }
     80 
     81     /**
     82      * Cached members for {@link MessageMention#members}
     83      * @type {?Collection<Snowflake, GuildMember>}
     84      * @private
     85      */
     86     this._members = null;
     87 
     88     /**
     89      * Cached channels for {@link MessageMention#channels}
     90      * @type {?Collection<Snowflake, GuildChannel>}
     91      * @private
     92      */
     93     this._channels = null;
     94 
     95     /**
     96      * Crossposted channel data.
     97      * @typedef {Object} CrosspostedChannel
     98      * @property {string} channelID ID of the mentioned channel
     99      * @property {string} guildID ID of the guild that has the channel
    100      * @property {string} type Type of the channel
    101      * @property {string} name The name of the channel
    102      */
    103 
    104     if (crosspostedChannels) {
    105       if (crosspostedChannels instanceof Collection) {
    106         /**
    107          * A collection of crossposted channels
    108          * <info>Order as received from the API, not as they appear in the message content</info>
    109          * @type {Collection<Snowflake, CrosspostedChannel>}
    110          */
    111         this.crosspostedChannels = new Collection(crosspostedChannels);
    112       } else {
    113         this.crosspostedChannels = new Collection();
    114         const channelTypes = Object.keys(ChannelTypes);
    115         for (const d of crosspostedChannels) {
    116           const type = channelTypes[d.type];
    117           this.crosspostedChannels.set(d.id, {
    118             channelID: d.id,
    119             guildID: d.guild_id,
    120             type: type ? type.toLowerCase() : 'unknown',
    121             name: d.name,
    122           });
    123         }
    124       }
    125     } else {
    126       this.crosspostedChannels = new Collection();
    127     }
    128   }
    129 
    130   /**
    131    * Any members that were mentioned (only in {@link TextChannel}s)
    132    * <info>Order as received from the API, not as they appear in the message content</info>
    133    * @type {?Collection<Snowflake, GuildMember>}
    134    * @readonly
    135    */
    136   get members() {
    137     if (this._members) return this._members;
    138     if (!this.guild) return null;
    139     this._members = new Collection();
    140     this.users.forEach(user => {
    141       const member = this.guild.member(user);
    142       if (member) this._members.set(member.user.id, member);
    143     });
    144     return this._members;
    145   }
    146 
    147   /**
    148    * Any channels that were mentioned
    149    * <info>Order as they appear first in the message content</info>
    150    * @type {Collection<Snowflake, GuildChannel>}
    151    * @readonly
    152    */
    153   get channels() {
    154     if (this._channels) return this._channels;
    155     this._channels = new Collection();
    156     let matches;
    157     while ((matches = this.constructor.CHANNELS_PATTERN.exec(this._content)) !== null) {
    158       const chan = this.client.channels.cache.get(matches[1]);
    159       if (chan) this._channels.set(chan.id, chan);
    160     }
    161     return this._channels;
    162   }
    163 
    164   /**
    165    * Checks if a user, guild member, role, or channel is mentioned.
    166    * Takes into account user mentions, role mentions, and @everyone/@here mentions.
    167    * @param {UserResolvable|GuildMember|Role|GuildChannel} data User/GuildMember/Role/Channel to check
    168    * @param {Object} [options] Options
    169    * @param {boolean} [options.ignoreDirect=false] - Whether to ignore direct mentions to the item
    170    * @param {boolean} [options.ignoreRoles=false] - Whether to ignore role mentions to a guild member
    171    * @param {boolean} [options.ignoreEveryone=false] - Whether to ignore everyone/here mentions
    172    * @returns {boolean}
    173    */
    174   has(data, { ignoreDirect = false, ignoreRoles = false, ignoreEveryone = false } = {}) {
    175     if (!ignoreEveryone && this.everyone) return true;
    176     const GuildMember = require('./GuildMember');
    177     if (!ignoreRoles && data instanceof GuildMember) {
    178       for (const role of this.roles.values()) if (data.roles.cache.has(role.id)) return true;
    179     }
    180 
    181     if (!ignoreDirect) {
    182       const id = data.id || data;
    183       return this.users.has(id) || this.channels.has(id) || this.roles.has(id);
    184     }
    185 
    186     return false;
    187   }
    188 
    189   toJSON() {
    190     return Util.flatten(this, {
    191       members: true,
    192       channels: true,
    193     });
    194   }
    195 }
    196 
    197 /**
    198  * Regular expression that globally matches `@everyone` and `@here`
    199  * @type {RegExp}
    200  */
    201 MessageMentions.EVERYONE_PATTERN = /@(everyone|here)/g;
    202 
    203 /**
    204  * Regular expression that globally matches user mentions like `<@81440962496172032>`
    205  * @type {RegExp}
    206  */
    207 MessageMentions.USERS_PATTERN = /<@!?(\d{17,19})>/g;
    208 
    209 /**
    210  * Regular expression that globally matches role mentions like `<@&297577916114403338>`
    211  * @type {RegExp}
    212  */
    213 MessageMentions.ROLES_PATTERN = /<@&(\d{17,19})>/g;
    214 
    215 /**
    216  * Regular expression that globally matches channel mentions like `<#222079895583457280>`
    217  * @type {RegExp}
    218  */
    219 MessageMentions.CHANNELS_PATTERN = /<#(\d{17,19})>/g;
    220 
    221 module.exports = MessageMentions;