refactor, use cache and channel handlers
This commit is contained in:
parent
0d900bfdcd
commit
0d62a410ad
@ -1,5 +1,4 @@
|
||||
const { Client } = require('discord.js');
|
||||
const fs = require('fs');
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { TextChannel, GuildMember } = require('./extensions');
|
||||
@ -7,6 +6,7 @@ const { Logger } = require('../logger');
|
||||
const Modmail = require('./Modmail');
|
||||
const Registry = require('./Registry');
|
||||
const Resolver = require('./Resolver');
|
||||
const Cache = require('./Cache');
|
||||
|
||||
class ModmailClient extends Client {
|
||||
|
||||
@ -20,16 +20,15 @@ class ModmailClient extends Client {
|
||||
this.prefix = options.prefix;
|
||||
|
||||
this.logger = new Logger(this, options.loggerOptions);
|
||||
this.modmail = new Modmail(this);
|
||||
this.registry = new Registry(this);
|
||||
this.resolver = new Resolver(this);
|
||||
this.cache = new Cache(this);
|
||||
this.modmail = new Modmail(this);
|
||||
|
||||
this.on('ready', () => {
|
||||
this.logger.info(`Client ready, logged in as ${this.user.tag}`);
|
||||
});
|
||||
|
||||
this.cache = null;
|
||||
|
||||
}
|
||||
|
||||
async init() {
|
||||
@ -38,14 +37,7 @@ class ModmailClient extends Client {
|
||||
|
||||
this.on('message', this.handleMessage.bind(this));
|
||||
|
||||
if (fs.existsSync('./persistent_cache.json')) {
|
||||
this.logger.info('Loading cache');
|
||||
this.cache = JSON.parse(fs.readFileSync('./persistent_cache.json', { encoding: 'utf-8' }));
|
||||
} else {
|
||||
this.logger.info('Cache file missing, creating...');
|
||||
this.cache = {};
|
||||
this.saveCache();
|
||||
}
|
||||
this.cache.load();
|
||||
|
||||
this.logger.info(`Logging in`);
|
||||
await this.login(this._options.discordToken);
|
||||
@ -58,27 +50,19 @@ class ModmailClient extends Client {
|
||||
|
||||
process.on('exit', () => {
|
||||
this.logger.warn('process exiting');
|
||||
this.saveCache();
|
||||
this.modmail.saveHistory();
|
||||
this.cache.save();
|
||||
this.cache.saveModmailHistory(this.modmail);
|
||||
});
|
||||
process.on('SIGINT', () => {
|
||||
this.logger.warn('received sigint');
|
||||
this.saveCache.bind(this);
|
||||
this.modmail.saveHistory();
|
||||
this.cache.save();
|
||||
this.cache.saveModmailHistory(this.modmail);
|
||||
// eslint-disable-next-line no-process-exit
|
||||
process.exit();
|
||||
});
|
||||
|
||||
this._ready = true;
|
||||
|
||||
this.cacheSaver = setInterval(this.saveCache.bind(this), 10 * 60 * 1000);
|
||||
|
||||
}
|
||||
|
||||
saveCache() {
|
||||
this.logger.debug('Saving cache');
|
||||
delete this.cache._channels;
|
||||
fs.writeFileSync('./persistent_cache.json', JSON.stringify(this.cache));
|
||||
}
|
||||
|
||||
ready() {
|
||||
@ -112,7 +96,7 @@ class ModmailClient extends Client {
|
||||
if(!roles.some((r) => this._options.staffRoles.includes(r)) && !member.hasPermission('ADMINISTRATOR')) return;
|
||||
|
||||
const [rawCommand, ...args] = content.split(' ');
|
||||
const commandName = rawCommand.substring(prefix.length).toLowerCase();
|
||||
const commandName = rawCommand.substring(prefix.length);
|
||||
const command = this.registry.find(commandName);
|
||||
if (!command) return;
|
||||
message._caller = commandName;
|
||||
@ -142,12 +126,20 @@ class ModmailClient extends Client {
|
||||
|
||||
}
|
||||
|
||||
resolveUser(input) {
|
||||
return this.resolver.resolveUser(input);
|
||||
resolveUser(...args) {
|
||||
return this.resolver.resolveUser(...args);
|
||||
}
|
||||
|
||||
resolveUsers(input) {
|
||||
return this.resolver.resolveUsers(input);
|
||||
resolveUsers(...args) {
|
||||
return this.resolver.resolveUsers(...args);
|
||||
}
|
||||
|
||||
resolveChannels(...args) {
|
||||
return this.resolver.resolveChannels(...args);
|
||||
}
|
||||
|
||||
resolveChannel(...args) {
|
||||
return this.resolver.resolveChannel(...args);
|
||||
}
|
||||
|
||||
async prompt(str, { author, channel, time }) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
const fs = require('fs');
|
||||
const ChannelHandler = require('./ChannelHandler');
|
||||
|
||||
class Modmail {
|
||||
|
||||
@ -8,30 +9,28 @@ class Modmail {
|
||||
constructor(client) {
|
||||
|
||||
this.client = client;
|
||||
this.cache = client.cache;
|
||||
this.mainServer = null;
|
||||
this.bansServer = null;
|
||||
|
||||
const opts = client._options;
|
||||
|
||||
this.categories = opts.modmailCategory;
|
||||
this.graveyardInactive = opts.graveyardInactive;
|
||||
this.readInactive = opts.readInactive;
|
||||
this.channelSweepInterval = opts.channelSweepInterval;
|
||||
this.saveInterval = opts.saveInterval;
|
||||
this.anonColor = opts.anonColor;
|
||||
this.reminderInterval = opts.modmailReminderInterval || 30;
|
||||
this._reminderChannel = opts.modmailReminderChannel || null;
|
||||
this.reminderChannel = null;
|
||||
this.categories = opts.modmailCategory;
|
||||
|
||||
this.updatedThreads = [];
|
||||
this.queue = [];
|
||||
this.mmcache = {};
|
||||
this.spammers = {};
|
||||
this.replies = {};
|
||||
this.awaitingChannel = {};
|
||||
|
||||
this.lastReminder = null;
|
||||
|
||||
this.channels = new ChannelHandler(this, opts);
|
||||
this._ready = false;
|
||||
|
||||
}
|
||||
|
||||
init() {
|
||||
@ -44,29 +43,24 @@ class Modmail {
|
||||
|
||||
if (!this.anonColor) this.anonColor = this.mainServer.me.highestRoleColor;
|
||||
|
||||
const { channels } = this.mainServer;
|
||||
this.newMail = channels.resolve(this.categories[0]);
|
||||
this.readMail = channels.resolve(this.categories[1]);
|
||||
this.graveyard = channels.resolve(this.categories[2]);
|
||||
|
||||
this.replies = this.loadReplies();
|
||||
this.queue = this.client.cache.queue || [];
|
||||
this.queue = this.client.cache.queue;
|
||||
|
||||
if (this._reminderChannel) {
|
||||
this.reminderChannel = this.client.channels.resolve(this._reminderChannel);
|
||||
this.reminder = setInterval(this.sendReminder.bind(this), this.reminderInterval * 60 * 1000);
|
||||
this.sendReminder();
|
||||
}
|
||||
|
||||
// Sweep graveyard every 30 min and move stale channels to graveyard
|
||||
this.sweeper = setInterval(this.sweepChannels.bind(this), this.channelSweepInterval * 60 * 1000);
|
||||
this.saver = setInterval(this.saveHistory.bind(this), this.saveInterval * 60 * 1000);
|
||||
|
||||
let logStr = `Started modmail handler for ${this.mainServer.name}`;
|
||||
if (this.bansServer) logStr += ` with ${this.bansServer.name} for ban appeals`;
|
||||
this.client.logger.info(logStr);
|
||||
//this.client.logger.info(`Fetching messages from discord for modmail`);
|
||||
// TODO: Fetch messages from discord in modmail channels
|
||||
|
||||
this.channels.init();
|
||||
this._ready = true;
|
||||
|
||||
}
|
||||
|
||||
async getMember(user) {
|
||||
@ -105,7 +99,6 @@ class Modmail {
|
||||
if (!member) return; // No member object found in main or bans server?
|
||||
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
if (!this.client.cache.lastActivity) this.client.cache.lastActivity = {};
|
||||
const lastActivity = this.client.cache.lastActivity[author.id];
|
||||
//console.log(now - lastActivity, lastActivity, now)
|
||||
if (!lastActivity || now - lastActivity > 30 * 60) {
|
||||
@ -114,7 +107,6 @@ class Modmail {
|
||||
this.client.cache.lastActivity[author.id] = now;
|
||||
|
||||
const { cache } = this.client;
|
||||
if (!cache.channels) cache.channels = {};
|
||||
|
||||
// Anti spam
|
||||
if (!this.spammers[author.id]) this.spammers[author.id] = { start: now, count: 1, timeout: false, warned: false };
|
||||
@ -135,14 +127,14 @@ class Modmail {
|
||||
}
|
||||
}
|
||||
|
||||
const pastModmail = await this.loadHistory(author.id)
|
||||
const pastModmail = await this.cache.loadModmailHistory(author.id)
|
||||
.catch((err) => {
|
||||
this.client.logger.error(`Error during loading of past mail:\n${err.stack}`);
|
||||
return { error: true };
|
||||
});
|
||||
if (pastModmail.error) return author.send(`Internal error, this has been logged.`);
|
||||
|
||||
const channel = await this.loadChannel(member, pastModmail)
|
||||
const channel = await this.channels.load(member, pastModmail)
|
||||
.catch((err) => {
|
||||
this.client.logger.error(`Error during channel handling:\n${err.stack}`);
|
||||
return { error: true };
|
||||
@ -177,7 +169,7 @@ class Modmail {
|
||||
|
||||
pastModmail.push({ attachments, author: author.id, content, timestamp: Date.now(), isReply: false });
|
||||
if (!this.updatedThreads.includes(author.id)) this.updatedThreads.push(author.id);
|
||||
this.queue.push(author.id);
|
||||
if(!this.queue.includes(author.id)) this.queue.push(author.id);
|
||||
|
||||
await channel.send({ embed }).catch((err) => {
|
||||
this.client.logger.error(`channel.send errored:\n${err.stack}\nContent: "${content}"`);
|
||||
@ -185,115 +177,6 @@ class Modmail {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Process channels for incoming modmail
|
||||
*
|
||||
* @param {GuildMember} member
|
||||
* @param {string} id
|
||||
* @param {Array<object>} history
|
||||
* @return {TextChannel}
|
||||
* @memberof Modmail
|
||||
*/
|
||||
loadChannel(member, history) {
|
||||
|
||||
if (this.awaitingChannel[member.id]) return this.awaitingChannel[member.id];
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
const promise = new Promise(async (resolve, reject) => {
|
||||
|
||||
const channelID = this.client.cache.channels[member.id];
|
||||
const guild = this.mainServer;
|
||||
const { user } = member;
|
||||
let channel = guild.channels.resolve(channelID);
|
||||
const { context } = this.client._options;
|
||||
|
||||
if (this.newMail.children.size >= 45) this.overflow();
|
||||
|
||||
if (!channel) { // Create and populate channel
|
||||
channel = await guild.channels.create(`${user.username}_${user.discriminator}`, {
|
||||
parent: this.newMail.id
|
||||
});
|
||||
|
||||
// Start with user info embed
|
||||
const embed = {
|
||||
author: { name: user.tag },
|
||||
thumbnail: {
|
||||
url: user.displayAvatarURL({ dynamic: true })
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: '__User Data__',
|
||||
value: `**User:** <@${user.id}>\n` +
|
||||
`**Account created:** ${user.createdAt.toDateString()}\n`,
|
||||
inline: false
|
||||
}
|
||||
],
|
||||
footer: { text: `• User ID: ${user.id}` },
|
||||
color: guild.me.highestRoleColor
|
||||
};
|
||||
if (member.banned) embed.description = `**__USER IS IN BANLAND__**`;
|
||||
else embed.fields.push({
|
||||
name: '__Member Data__',
|
||||
value: `**Nickname:** ${member.nickname || 'N/A'}\n` +
|
||||
`**Server join date:** ${member.joinedAt.toDateString()}\n` +
|
||||
`**Roles:** ${member.roles.cache.map((r) => `<@&${r.id}>`).join(' ')}`,
|
||||
inline: false
|
||||
});
|
||||
await channel.send({ embed });
|
||||
|
||||
// Load in context
|
||||
const len = history.length;
|
||||
for (let i = context < len ? context : len; i > 0; i--) {
|
||||
const entry = history[len - i];
|
||||
if (!entry) continue;
|
||||
if (entry.markread) continue;
|
||||
|
||||
const user = await this.client.resolveUser(entry.author).catch(this.client.logger.error.bind(this.client.logger));
|
||||
const mem = await this.getMember(user.id).catch(this.client.logger.error.bind(this.client.logger));
|
||||
if (!user) return reject(new Error(`Failed to find user`));
|
||||
|
||||
const embed = {
|
||||
footer: {
|
||||
text: user.id
|
||||
},
|
||||
author: {
|
||||
name: user.tag + (entry.anon ? ' (ANONYMOUS REPLY)' : ''),
|
||||
// eslint-disable-next-line camelcase
|
||||
icon_url: user.displayAvatarURL({ dynamic: true })
|
||||
},
|
||||
description: entry.content,
|
||||
color: mem?.highestRoleColor || 0,
|
||||
fields: [],
|
||||
timestamp: new Date(entry.timestamp)
|
||||
};
|
||||
|
||||
if (entry.attachments && entry.attachments.length) embed.fields.push({
|
||||
name: '__Attachments__',
|
||||
value: entry.attachments.join('\n').substring(0, 1000)
|
||||
});
|
||||
|
||||
await channel.send({ embed });
|
||||
|
||||
}
|
||||
|
||||
this.client.cache.channels[user.id] = channel.id;
|
||||
|
||||
}
|
||||
|
||||
// Ensure the right category
|
||||
//if (channel.parentID !== this.newMail.id)
|
||||
await channel.edit({ parentID: this.newMail.id, lockPermissions: true }).catch((err) => {
|
||||
this.client.logger.error(`Error during channel transition:\n${err.stack}`);
|
||||
});
|
||||
delete this.awaitingChannel[user.id];
|
||||
resolve(channel);
|
||||
|
||||
});
|
||||
|
||||
this.awaitingChannel[member.id] = promise;
|
||||
return promise;
|
||||
|
||||
}
|
||||
|
||||
async sendCannedResponse({ message, responseName, anon }) {
|
||||
|
||||
const content = this.getCanned(responseName);
|
||||
@ -306,6 +189,7 @@ class Modmail {
|
||||
|
||||
}
|
||||
|
||||
// Send reply from channel
|
||||
async sendResponse({ message, content, anon }) {
|
||||
|
||||
const { channel, member, author } = message;
|
||||
@ -314,7 +198,8 @@ class Modmail {
|
||||
msg: `This command only works in modmail channels.`
|
||||
};
|
||||
|
||||
const chCache = this.client.cache.channels;
|
||||
// Resolve target user from cache
|
||||
const chCache = this.cache.channels;
|
||||
const result = Object.entries(chCache).find(([, val]) => {
|
||||
return val === channel.id;
|
||||
});
|
||||
@ -324,19 +209,15 @@ class Modmail {
|
||||
msg: `This doesn't seem to be a valid modmail channel. Cache might be out of sync. **[MISSING TARGET]**`
|
||||
};
|
||||
|
||||
// Ensure target exists, this should never run into issues
|
||||
const [userId] = result;
|
||||
const targetUser = await this.getUser(userId);
|
||||
//const targetMember = await this.getMember(userId);
|
||||
|
||||
if (!targetUser) return {
|
||||
error: true,
|
||||
msg: `User seems to have left.\nReport this if the user is still present.`
|
||||
};
|
||||
|
||||
const history = await this.loadHistory(userId);
|
||||
history.push({ author: member.id, content, timestamp: Date.now(), isReply: true, anon });
|
||||
if (this.queue.includes(userId)) this.queue.splice(this.queue.indexOf(userId), 1);
|
||||
|
||||
const embed = {
|
||||
author: {
|
||||
name: anon ? `${this.mainServer.name.toUpperCase()} STAFF` : author.tag,
|
||||
@ -347,6 +228,7 @@ class Modmail {
|
||||
color: anon ? this.anonColor : member.highestRoleColor
|
||||
};
|
||||
|
||||
// Send to target user
|
||||
const sent = await targetUser.send({ embed }).catch((err) => {
|
||||
this.client.logger.warn(`Error during DMing user: ${err.message}`);
|
||||
return {
|
||||
@ -354,7 +236,7 @@ class Modmail {
|
||||
msg: `Failed to send message to target.`
|
||||
};
|
||||
});
|
||||
|
||||
// Should only error if user has DMs off or has left all mutual servers
|
||||
if (sent.error) return sent;
|
||||
|
||||
if (anon) embed.author = {
|
||||
@ -362,19 +244,13 @@ class Modmail {
|
||||
// eslint-disable-next-line camelcase
|
||||
icon_url: author.displayAvatarURL({ dynamic: true })
|
||||
};
|
||||
await channel.send({ embed }).catch((err) => {
|
||||
this.client.logger.error(`channel.send errored:\n${err.stack}\nContent: "${content}"`);
|
||||
});
|
||||
|
||||
if (this.readMail.children.size > 45) this.sweepChannels({ count: 5, force: true });
|
||||
await channel.edit({ parentID: this.readMail.id, lockPermissions: true }).catch((err) => {
|
||||
this.client.logger.error(`Error during channel transition:\n${err.stack}`);
|
||||
});
|
||||
await this.channels.send(targetUser, embed, { author: member.id, content, timestamp: Date.now(), isReply: true, anon });
|
||||
await message.delete().catch(this.client.logger.warn.bind(this.client.logger));
|
||||
if (!this.updatedThreads.includes(userId)) this.updatedThreads.push(userId);
|
||||
|
||||
}
|
||||
|
||||
// Send modmail with the modmail command
|
||||
async sendModmail({ message, content, anon, target }) {
|
||||
|
||||
const targetMember = await this.getMember(target.id);
|
||||
@ -383,16 +259,6 @@ class Modmail {
|
||||
msg: `Cannot find member`
|
||||
};
|
||||
|
||||
const history = await this.loadHistory(target.id)
|
||||
.catch((err) => {
|
||||
this.client.logger.error(`Error during loading of past mail:\n${err.stack}`);
|
||||
return { error: true };
|
||||
});
|
||||
if (history.error) return {
|
||||
error: true,
|
||||
msg: `Internal error, this has been logged.`
|
||||
};
|
||||
|
||||
const { author, member } = message;
|
||||
|
||||
const embed = {
|
||||
@ -405,6 +271,7 @@ class Modmail {
|
||||
color: anon ? this.anonColor : member.highestRoleColor
|
||||
};
|
||||
|
||||
// Dm the user
|
||||
const sent = await target.send({ embed }).catch((err) => {
|
||||
this.client.logger.warn(`Error during DMing user: ${err.message}`);
|
||||
return {
|
||||
@ -414,105 +281,32 @@ class Modmail {
|
||||
});
|
||||
if (sent.error) return sent;
|
||||
|
||||
// Inline response
|
||||
await message.channel.send('Delivered.').catch(this.client.logger.error.bind(this.client.logger));
|
||||
const channel = await this.loadChannel(targetMember, history).catch(this.client.logger.error.bind(this.client.logger));
|
||||
history.push({ author: member.id, content, timestamp: Date.now(), isReply: true, anon });
|
||||
if (this.queue.includes(target.id)) this.queue.splice(this.queue.indexOf(target.id), 1);
|
||||
if (!this.updatedThreads.includes(target.id)) this.updatedThreads.push(target.id);
|
||||
await channel.send({ embed }).catch(this.client.logger.error.bind(this.client.logger));
|
||||
await channel.edit({ parentID: this.readMail.id, lockPermissions: true }).catch(this.client.logger.error.bind(this.client.logger));
|
||||
|
||||
// Send to channel in server
|
||||
await this.channels.send(targetMember, embed, { author: member.id, content, timestamp: Date.now(), isReply: true, anon });
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param {object} { age, count, force } age: how long the channel has to be without activity to be deleted, count: how many channels to act on, force: whether to ignore answered status
|
||||
* @memberof Modmail
|
||||
*/
|
||||
async sweepChannels({ age, count, force = false } = {}) {
|
||||
async markread(message, args) {
|
||||
|
||||
this.client.logger.info(`Sweeping graveyard`);
|
||||
const now = Date.now();
|
||||
const graveyardChannels = this.graveyard.children.sort((a, b) => {
|
||||
if (!a.lastMessage) return -1;
|
||||
if (!b.lastMessage) return 1;
|
||||
return a.lastMessage.createdTimestamp - b.lastMessage.createdTimestamp;
|
||||
}).array();
|
||||
const { author } = message;
|
||||
|
||||
let channelCount = 0;
|
||||
if (!age) age = this.graveyardInactive * 60 * 1000; // 1 hour
|
||||
for (const channel of graveyardChannels) {
|
||||
|
||||
const { lastMessage } = channel;
|
||||
if (!lastMessage || now - lastMessage.createdTimestamp > age || count && channelCount <= count) {
|
||||
await channel.delete().then((ch) => {
|
||||
const chCache = this.client.cache.channels;
|
||||
const _cached = Object.entries(chCache).find(([, val]) => {
|
||||
return val === ch.id;
|
||||
});
|
||||
if (_cached) {
|
||||
const [userId] = _cached;
|
||||
delete chCache[userId];
|
||||
}
|
||||
}).catch((err) => {
|
||||
this.client.logger.error(`Failed to delete channel from graveyard during sweep:\n${err.stack}`);
|
||||
});
|
||||
channelCount++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.client.logger.info(`Swept ${channelCount} channels from graveyard, cleaning up answered...`);
|
||||
|
||||
const answered = this.readMail.children
|
||||
.filter((channel) => !channel.lastMessage || channel.lastMessage.createdTimestamp < Date.now() - this.readInactive * 60 * 1000 || force)
|
||||
.sort((a, b) => {
|
||||
if (!a.lastMessage) return -1;
|
||||
if (!b.lastMessage) return 1;
|
||||
return a.lastMessage.createdTimestamp - b.lastMessage.createdTimestamp;
|
||||
}).array();
|
||||
let chCount = this.graveyard.children.size;
|
||||
for (const ch of answered) {
|
||||
if (chCount < 50) {
|
||||
await ch.edit({ parentID: this.graveyard.id, lockPermissions: true }).catch((err) => {
|
||||
this.client.logger.error(`Failed to move channel to graveyard during sweep:\n${err.stack}`);
|
||||
});
|
||||
chCount++;
|
||||
} else break;
|
||||
}
|
||||
|
||||
this.client.logger.info(`Sweep done. Took ${Date.now() - now}ms`);
|
||||
|
||||
}
|
||||
|
||||
async overflow() { // Overflows new modmail category into read
|
||||
const channels = this.newMail.children.sort((a, b) => {
|
||||
if (!a.lastMessage) return -1;
|
||||
if (!b.lastMessage) return 1;
|
||||
return a.lastMessage.createdTimestamp - b.lastMessage.createdTimestamp;
|
||||
}).array();
|
||||
|
||||
if (this.readMail.children.size >= 45) await this.sweepChannels({ count: 5, force: true });
|
||||
|
||||
let counter = 0;
|
||||
for (const channel of channels) {
|
||||
await channel.edit({ parentID: this.readMail.id, lockPermissions: true });
|
||||
counter++;
|
||||
if (counter === 5) break;
|
||||
}
|
||||
}
|
||||
|
||||
async markread(message) {
|
||||
|
||||
const { channel, author } = message;
|
||||
|
||||
if (!this.categories.includes(channel.parentID)) return {
|
||||
if (!this.categories.includes(message.channel.parentID) && !args.length) return {
|
||||
error: true,
|
||||
msg: `This command only works in modmail channels.`
|
||||
msg: `This command only works in modmail channels without arguments.`
|
||||
};
|
||||
|
||||
const chCache = this.client.cache.channels;
|
||||
// Eventually support marking several threads read at the same time
|
||||
const [id] = args;
|
||||
let channel = null;
|
||||
const _user = await this.client.resolveUser(id, true);
|
||||
if (!args.length) ({ channel } = message);
|
||||
else if (this.cache.channels[_user.id]) channel = this.client.channels.resolve(this.cache.channels[_user.id]);
|
||||
else channel = await this.client.resolveChannel(id);
|
||||
|
||||
const chCache = this.cache.channels;
|
||||
const result = Object.entries(chCache).find(([, val]) => {
|
||||
return val === channel.id;
|
||||
});
|
||||
@ -523,21 +317,9 @@ class Modmail {
|
||||
};
|
||||
|
||||
const [userId] = result;
|
||||
const history = await this.loadHistory(userId)
|
||||
.catch((err) => {
|
||||
this.client.logger.error(`Error during loading of past mail:\n${err.stack}`);
|
||||
return { error: true };
|
||||
});
|
||||
if (history.error) return {
|
||||
error: true,
|
||||
msg: `Internal error, this has been logged.`
|
||||
};
|
||||
history.push({ author: author.id, timestamp: Date.now(), markread: true }); // To keep track of read state
|
||||
if (this.queue.includes(userId)) this.queue.splice(this.queue.indexOf(userId), 1);
|
||||
|
||||
await channel.edit({ parentID: this.readMail.id, lockPermissions: true });
|
||||
if (!this.updatedThreads.includes(author.id)) this.updatedThreads.push(userId);
|
||||
return `Done`;
|
||||
const response = await this.channels.markread(userId, channel, author);
|
||||
if (response.error) return response;
|
||||
return 'Done';
|
||||
|
||||
}
|
||||
|
||||
@ -559,48 +341,6 @@ class Modmail {
|
||||
|
||||
}
|
||||
|
||||
loadHistory(userId) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
if (this.mmcache[userId]) return resolve(this.mmcache[userId]);
|
||||
|
||||
const path = `./modmail_cache/${userId}.json`;
|
||||
if (!fs.existsSync(path)) {
|
||||
this.mmcache[userId] = [];
|
||||
return resolve(this.mmcache[userId]);
|
||||
}
|
||||
|
||||
fs.readFile(path, { encoding: 'utf-8' }, (err, data) => {
|
||||
if (err) reject(err);
|
||||
const parsed = JSON.parse(data);
|
||||
this.mmcache[userId] = parsed;
|
||||
resolve(parsed);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
saveHistory() {
|
||||
|
||||
if (!this.updatedThreads.length) return;
|
||||
const toSave = [...this.updatedThreads];
|
||||
this.updatedThreads = [];
|
||||
this.client.logger.debug(`Saving modmail data`);
|
||||
if (!fs.existsSync('./modmail_cache')) fs.mkdirSync('./modmail_cache');
|
||||
|
||||
for (const id of toSave) {
|
||||
const path = `./modmail_cache/${id}.json`;
|
||||
try {
|
||||
fs.writeFileSync(path, JSON.stringify(this.mmcache[id]));
|
||||
} catch (err) {
|
||||
this.client.logger.error(`Error during saving of history\n${id}\n${JSON.stringify(this.mmcache)}\n${err.stack}`);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getCanned(name) {
|
||||
return this.replies[name.toLowerCase()];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user