BetterDiscordApp-v2/client/src/structs/discord/message.js

320 lines
10 KiB
JavaScript

/**
* BetterDiscord Message Struct
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { DiscordApi, DiscordApiModules as Modules } from 'modules';
import { List, InsufficientPermissions } from 'structs';
import { Channel } from './channel';
import { User } from './user';
const reactions = new WeakMap();
/**
* Class representing a Discord Reaction
*/
export class Reaction {
constructor(data, message_id, channel_id) {
if (reactions.has(data)) return reactions.get(data);
reactions.set(data, this);
this.discordObject = data;
this.messageId = message_id;
this.channelId = channel_id;
}
get emoji() {
const id = this.discordObject.emoji.id;
if (!id || !this.guild) return this.discordObject.emoji;
return this.guild.emojis.find(e => e.id === id);
}
get count() { return this.discordObject.count }
get me() { return this.discordObject.me }
get channel() {
return Channel.fromId(this.channel_id);
}
get message() {
return this.channel ? this.channel.messages.find(m => m.id === this.messageId) : null;
}
get guild() {
return this.channel ? this.channel.guild : null;
}
}
const embeds = new WeakMap();
/**
* Class representing a Discord Embed
*/
export class Embed {
constructor(data, message_id, channel_id) {
if (embeds.has(data)) return embeds.get(data);
embeds.set(data, this);
this.discordObject = data;
this.messageId = message_id;
this.channelId = channel_id;
}
get title() { return this.discordObject.title }
get type() { return this.discordObject.type }
get description() { return this.discordObject.description }
get url() { return this.discordObject.url }
get timestamp() { return this.discordObject.timestamp }
get colour() { return this.discordObject.color }
get footer() { return this.discordObject.footer }
get image() { return this.discordObject.image }
get thumbnail() { return this.discordObject.thumbnail }
get video() { return this.discordObject.video }
get provider() { return this.discordObject.provider }
get author() { return this.discordObject.author }
get fields() { return this.discordObject.fields }
get channel() {
return Channel.fromId(this.channelId);
}
get message() {
return this.channel ? this.channel.messages.find(m => m.id === this.messageId) : null;
}
get guild() {
return this.channel ? this.channel.guild : null;
}
}
const messages = new WeakMap();
/**
* Class representing a Discord Message
*/
export class Message {
constructor(data) {
if (messages.has(data)) return messages.get(data);
messages.set(data, this);
this.discordObject = data;
}
static from(data) {
switch (data.type) {
default: return new Message(data);
case 0: return new DefaultMessage(data);
case 1: return new RecipientAddMessage(data);
case 2: return new RecipientRemoveMessage(data);
case 3: return new CallMessage(data);
case 4: return new GroupChannelNameChangeMessage(data);
case 5: return new GroupChannelIconChangeMessage(data);
case 6: return new MessagePinnedMessage(data);
case 7: return new GuildMemberJoinMessage(data);
}
}
static get DefaultMessage() { return DefaultMessage }
static get RecipientAddMessage() { return RecipientAddMessage }
static get RecipientRemoveMessage() { return RecipientRemoveMessage }
static get CallMessage() { return CallMessage }
static get GroupChannelNameChangeMessage() { return GroupChannelNameChangeMessage }
static get GroupChannelIconChangeMessage() { return GroupChannelIconChangeMessage }
static get MessagePinnedMessage() { return MessagePinnedMessage }
static get GuildMemberJoinMessage() { return GuildMemberJoinMessage }
static get Reaction() { return Reaction }
static get Embed() { return Embed }
get id() { return this.discordObject.id }
get channelId() { return this.discordObject.channel_id }
get nonce() { return this.discordObject.nonce }
get type() { return this.discordObject.type }
get timestamp() { return this.discordObject.timestamp }
get state() { return this.discordObject.state }
get nick() { return this.discordObject.nick }
get colourString() { return this.discordObject.colorString }
get author() {
if (this.discordObject.author && !this.webhookId) return User.from(this.discordObject.author);
return null;
}
get channel() {
return Channel.fromId(this.channelId);
}
get guild() {
return this.channel ? this.channel.guild : null;
}
/**
* Deletes the message.
* @return {Promise}
*/
delete() {
if (!this.isDeletable) throw new Error(`Message type ${this.type} is not deletable.`);
if (this.author === DiscordApi.currentUser) {}
else if (this.channel.assertPermissions) this.channel.assertPermissions('MANAGE_MESSAGES', Modules.DiscordPermissions.MANAGE_MESSAGES);
else if (!this.channel.owner === DiscordApi.currentUser) throw new InsufficientPermissions('MANAGE_MESSAGES');
return Modules.APIModule.delete(`${Modules.DiscordConstants.Endpoints.MESSAGES(this.channelId)}/${this.id}`);
}
get isDeletable() {
return this.type === 'DEFAULT' || this.type === 'CHANNEL_PINNED_MESSAGE' || this.type === 'GUILD_MEMBER_JOIN';
}
/**
* Jumps to the message.
*/
jumpTo(flash = true) {
Modules.MessageActions.jumpToMessage(this.channelId, this.id, flash);
}
}
/**
* Class representing a default Discord Message
*/
export class DefaultMessage extends Message {
get webhookId() { return this.discordObject.webhookId }
get type() { return 'DEFAULT' }
get content() { return this.discordObject.content }
get contentParsed() { return this.discordObject.contentParsed }
get inviteCodes() { return this.discordObject.invites }
get attachments() { return this.discordObject.attachments }
get mentionIds() { return this.discordObject.mentions }
get mentionRoleIds() { return this.discordObject.mentionRoles }
get mentionEveryone() { return this.discordObject.mentionEveryone }
get editedTimestamp() { return this.discordObject.editedTimestamp }
get tts() { return this.discordObject.tts }
get mentioned() { return this.discordObject.mentioned }
get bot() { return this.discordObject.bot }
get blocked() { return this.discordObject.blocked }
get pinned() { return this.discordObject.pinned }
get activity() { return this.discordObject.activity }
get application() { return this.discordObject.application }
get webhook() {
return this.webhookId ? this.discordObject.author : null;
}
get mentions() {
return List.from(this.mentionIds, id => User.fromId(id));
}
get mention_roles() {
return List.from(this.mentionRoleIds, id => this.guild.roles.find(r => r.id === id));
}
get embeds() {
return List.from(this.discordObject.embeds, r => new Embed(r, this.id, this.channelId));
}
get reactions() {
return List.from(this.discordObject.reactions, r => new Reaction(r, this.id, this.channelId));
}
get edited() {
return !!this.editedTimestamp;
}
/**
* Programmatically update the message's content.
* @param {String} content The message's new content
* @param {Boolean} parse Whether to parse the message or update it as it is
* @return {Promise}
*/
async edit(content, parse = false) {
if (this.author !== DiscordApi.currentUser) throw new Error('Cannot edit messages sent by other users.');
if (parse) content = Modules.MessageParser.parse(this.discordObject, content);
else content = {content};
const response = await Modules.APIModule.patch({
url: `${Modules.DiscordConstants.Endpoints.MESSAGES(this.channelId)}/${this.id}`,
body: content
});
this.discordObject = Modules.MessageStore.getMessage(this.id, response.body.id);
messages.set(this.discordObject, this);
}
/**
* Start the edit mode of the UI.
* @param {String} content A string to show in the message text area - if empty the message's current content will be used
*/
startEdit(content) {
if (this.author !== DiscordApi.currentUser) throw new Error('Cannot edit messages sent by other users.');
Modules.MessageActions.startEditMessage(this.channelId, this.id, content || this.content);
}
/**
* Exit the edit mode of the UI.
*/
endEdit() {
Modules.MessageActions.endEditMessage();
}
}
export class RecipientAddMessage extends Message {
get type() { return 'RECIPIENT_ADD' }
get addedUserId() { return this.discordObject.mentions[0] }
get addedUser() {
return User.fromId(this.addedUserId);
}
}
export class RecipientRemoveMessage extends Message {
get type() { return 'RECIPIENT_REMOVE' }
get removedUserId() { return this.discordObject.mentions[0] }
get removedUser() {
return User.fromId(this.removedUserId);
}
get userLeft() {
return this.author === this.removedUser;
}
}
export class CallMessage extends Message {
get type() { return 'CALL' }
get mentionIds() { return this.discordObject.mentions }
get call() { return this.discordObject.call }
get endedTimestamp() { return this.call.endedTimestamp }
get mentions() {
return List.from(this.mentionIds, id => User.fromId(id));
}
get participants() {
return List.from(this.call.participants, id => User.fromId(id));
}
}
export class GroupChannelNameChangeMessage extends Message {
get type() { return 'CHANNEL_NAME_CHANGE' }
get newName() { return this.discordObject.content }
}
export class GroupChannelIconChangeMessage extends Message {
get type() { return 'CHANNEL_ICON_CHANGE' }
}
export class MessagePinnedMessage extends Message {
get type() { return 'CHANNEL_PINNED_MESSAGE' }
}
export class GuildMemberJoinMessage extends Message {
get type() { return 'GUILD_MEMBER_JOIN' }
}