Major refactor about done

master
Miikka Virtanen 2017-02-10 06:36:47 +02:00
parent 6d33e7adb4
commit 6a13724c6a
10 changed files with 224 additions and 87 deletions

2
.nvmrc
View File

@ -1 +1 @@
6.9.1 7.5.0

View File

@ -1,14 +1,26 @@
const Eris = require('eris');
const fs = require('fs'); const fs = require('fs');
const https = require('https'); const https = require('https');
const config = require('../config'); const config = require('../config');
const utils = require('./utils'); const utils = require('./utils');
const attachmentDir = config.attachmentDir || `${__dirname}/attachments`; const attachmentDir = config.attachmentDir || `${__dirname}/../attachments`;
function getAttachmentPath(id) { /**
return `${attachmentDir}/${id}`; * Returns the filesystem path for the given attachment id
* @param {String} attachmentId
* @returns {String}
*/
function getPath(attachmentId) {
return `${attachmentDir}/${attachmentId}`;
} }
/**
* Attempts to download and save the given attachement
* @param {Object} attachment
* @param {Number=0} tries
* @returns {Promise}
*/
function saveAttachment(attachment, tries = 0) { function saveAttachment(attachment, tries = 0) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (tries > 3) { if (tries > 3) {
@ -17,7 +29,7 @@ function saveAttachment(attachment, tries = 0) {
return; return;
} }
const filepath = getAttachmentPath(attachment.id); const filepath = getPath(attachment.id);
const writeStream = fs.createWriteStream(filepath); const writeStream = fs.createWriteStream(filepath);
https.get(attachment.url, (res) => { https.get(attachment.url, (res) => {
@ -34,19 +46,30 @@ function saveAttachment(attachment, tries = 0) {
}); });
} }
function saveAttachments(msg) { /**
* Attempts to download and save all attachments in the given message
* @param {Eris.Message} msg
* @returns {Promise}
*/
function saveAttachmentsInMessage(msg) {
if (! msg.attachments || msg.attachments.length === 0) return Promise.resolve(); if (! msg.attachments || msg.attachments.length === 0) return Promise.resolve();
return Promise.all(msg.attachments.map(saveAttachment)); return Promise.all(msg.attachments.map(saveAttachment));
} }
function getAttachmentUrl(id, desiredName) { /**
* Returns the self-hosted URL to the given attachment ID
* @param {String} attachmentId
* @param {String=null} desiredName Custom name for the attachment as a hint for the browser
* @returns {String}
*/
function getUrl(attachmentId, desiredName = null) {
if (desiredName == null) desiredName = 'file.bin'; if (desiredName == null) desiredName = 'file.bin';
return utils.getSelfUrl(`attachments/${id}/${desiredName}`); return utils.getSelfUrl(`attachments/${attachmentId}/${desiredName}`);
} }
module.exports = { module.exports = {
getAttachmentPath, getPath,
saveAttachment, saveAttachment,
saveAttachments, saveAttachmentsInMessage,
getAttachmentUrl, getUrl,
}; };

View File

@ -1,20 +1,35 @@
const jsonDb = require('./jsonDb'); const jsonDb = require('./jsonDb');
/**
* Checks whether userId is blocked
* @param {String} userId
* @returns {Promise<Boolean>}
*/
function isBlocked(userId) { function isBlocked(userId) {
return jsonDb.get('blocked').then(blocked => { return jsonDb.get('blocked', []).then(blocked => {
return blocked.indexOf(userId) !== -1; return blocked.indexOf(userId) !== -1;
}); });
} }
/**
* Blocks the given userId
* @param {String} userId
* @returns {Promise}
*/
function block(userId) { function block(userId) {
return jsonDb.get('blocked').then(blocked => { return jsonDb.get('blocked', []).then(blocked => {
blocked.push(userId); blocked.push(userId);
return jsonDb.save('blocked', blocked); return jsonDb.save('blocked', blocked);
}); });
} }
/**
* Unblocks the given userId
* @param {String} userId
* @returns {Promise}
*/
function unblock(userId) { function unblock(userId) {
return jsonDb.get('blocked').then(blocked => { return jsonDb.get('blocked', []).then(blocked => {
blocked.splice(blocked.indexOf(userId), 1); blocked.splice(blocked.indexOf(userId), 1);
return jsonDb.save('blocked', blocked); return jsonDb.save('blocked', blocked);
}); });

View File

@ -1,7 +1,8 @@
const Eris = require('eris'); const Eris = require('eris');
const fs = require('fs');
const moment = require('moment'); const moment = require('moment');
const Queue = require('./queue');
const config = require('../config'); const config = require('../config');
const Queue = require('./queue');
const utils = require('./utils'); const utils = require('./utils');
const blocked = require('./blocked'); const blocked = require('./blocked');
const threads = require('./threads'); const threads = require('./threads');
@ -23,6 +24,29 @@ bot.on('ready', () => {
console.log('Bot started, listening to DMs'); console.log('Bot started, listening to DMs');
}); });
function formatAttachment(attachment) {
let filesize = attachment.size || 0;
filesize /= 1024;
return attachments.getUrl(attachment.id, attachment.filename).then(attachmentUrl => {
return `**Attachment:** ${attachment.filename} (${filesize.toFixed(1)}KB)\n${attachmentUrl}`;
});
}
function formatUserDM(msg) {
let content = msg.content;
// Get a local URL for all attachments so we don't rely on discord's servers (which delete attachments when the channel/DM thread is deleted)
const attachmentFormatPromise = msg.attachments.map(formatAttachment);
return Promise.all(attachmentFormatPromise).then(formattedAttachments => {
formattedAttachments.forEach(str => {
content += `\n\n${str}`;
});
return content;
});
}
// "Bot was mentioned in #general-discussion" // "Bot was mentioned in #general-discussion"
bot.on('messageCreate', msg => { bot.on('messageCreate', msg => {
if (msg.author.id === bot.user.id) return; if (msg.author.id === bot.user.id) return;
@ -48,19 +72,20 @@ bot.on('messageCreate', (msg) => {
if (isBlocked) return; if (isBlocked) return;
// Download and save copies of attachments in the background // Download and save copies of attachments in the background
attachments.saveAttachments(msg); attachments.saveAttachmentsInMessage(msg);
let thread, logs; let thread, userLogs;
// Private message handling is queued so e.g. multiple message in quick succession don't result in multiple channels aren't created
messageQueue.add(() => { messageQueue.add(() => {
threads.getForUser(bot, msg.author) return threads.getForUser(bot, msg.author)
.then(userThread => { .then(userThread => {
thread = userThread; thread = userThread;
return logs.getLogsByUserId(msg.author.id); return logs.getLogsByUserId(msg.author.id);
}) })
.then(userLogs => { .then(foundUserLogs => {
logs = userLogs; userLogs = foundUserLogs;
return utils.formatUserDM(msg); return formatUserDM(msg);
}) })
.then(content => { .then(content => {
// If the thread does not exist and could not be created, send a warning about this to all mods so they can DM the user directly instead // If the thread does not exist and could not be created, send a warning about this to all mods so they can DM the user directly instead
@ -88,7 +113,7 @@ bot.on('messageCreate', (msg) => {
} }
// Ping mods of the new thread // Ping mods of the new thread
let creationNotificationMessage = `New modmail thread: <#${channel.id}>`; let creationNotificationMessage = `New modmail thread: <#${thread.channelId}>`;
if (config.pingCreationNotification) creationNotificationMessage = `@here ${creationNotificationMessage}`; if (config.pingCreationNotification) creationNotificationMessage = `@here ${creationNotificationMessage}`;
bot.createMessage(utils.getModmailGuild(bot).id, { bot.createMessage(utils.getModmailGuild(bot).id, {
@ -98,15 +123,15 @@ bot.on('messageCreate', (msg) => {
// Send an automatic reply to the user informing them of the successfully created modmail thread // Send an automatic reply to the user informing them of the successfully created modmail thread
msg.channel.createMessage("Thank you for your message! Our mod team will reply to you here as soon as possible.").then(null, (err) => { msg.channel.createMessage("Thank you for your message! Our mod team will reply to you here as soon as possible.").then(null, (err) => {
bot.createMessage(modMailGuild.id, { bot.createMessage(utils.getModmailGuild(bot).id, {
content: `There is an issue sending messages to ${msg.author.username}#${msg.author.discriminator} (id ${msg.author.id}); consider messaging manually` content: `There is an issue sending messages to ${msg.author.username}#${msg.author.discriminator} (id ${msg.author.id}); consider messaging manually`
}); });
}); });
} }
const timestamp = utils.getTimestamp(); const timestamp = utils.getTimestamp();
bot.createMessage(channel.id, `[${timestamp}] « **${msg.author.username}#${msg.author.discriminator}:** ${content}`); bot.createMessage(thread.channelId, `[${timestamp}] « **${msg.author.username}#${msg.author.discriminator}:** ${content}`);
}) });
}); });
}); });
}); });
@ -144,11 +169,10 @@ bot.registerCommand('reply', (msg, args) => {
threads.getByChannelId(msg.channel.id).then(thread => { threads.getByChannelId(msg.channel.id).then(thread => {
if (! thread) return; if (! thread) return;
attachments.saveAttachments(msg).then(() => { attachments.saveAttachmentsInMessage(msg).then(() => {
bot.getDMChannel(thread.userId).then(dmChannel => { bot.getDMChannel(thread.userId).then(dmChannel => {
const roleId = msg.member.roles[0]; const mainRole = utils.getMainRole(msg.member);
const role = (roleId ? (modMailGuild.roles.get(roleId) || {}).name : ''); const roleStr = (mainRole ? `(${mainRole.name}) ` : '');
const roleStr = (role ? `(${role}) ` : '');
let argMsg = args.join(' ').trim(); let argMsg = args.join(' ').trim();
let content = `**${roleStr}${msg.author.username}:** ${argMsg}`; let content = `**${roleStr}${msg.author.username}:** ${argMsg}`;
@ -157,7 +181,7 @@ bot.registerCommand('reply', (msg, args) => {
dmChannel.createMessage(content, file).then(() => { dmChannel.createMessage(content, file).then(() => {
if (attachmentUrl) content += `\n\n**Attachment:** ${attachmentUrl}`; if (attachmentUrl) content += `\n\n**Attachment:** ${attachmentUrl}`;
const timestamp = getTimestamp(); const timestamp = utils.getTimestamp();
msg.channel.createMessage(`[${timestamp}] » ${content}`); msg.channel.createMessage(`[${timestamp}] » ${content}`);
}, (err) => { }, (err) => {
if (err.resp && err.resp.statusCode === 403) { if (err.resp && err.resp.statusCode === 403) {
@ -174,10 +198,10 @@ bot.registerCommand('reply', (msg, args) => {
// If the reply has an attachment, relay it as is // If the reply has an attachment, relay it as is
if (msg.attachments.length > 0) { if (msg.attachments.length > 0) {
fs.readFile(attachments.getAttachmentPath(msg.attachments[0].id), (err, data) => { fs.readFile(attachments.getPath(msg.attachments[0].id), (err, data) => {
const file = {file: data, name: msg.attachments[0].filename}; const file = {file: data, name: msg.attachments[0].filename};
getAttachmentUrl(msg.attachments[0].id, msg.attachments[0].filename).then(attachmentUrl => { attachments.getUrl(msg.attachments[0].id, msg.attachments[0].filename).then(attachmentUrl => {
sendMessage(file, attachmentUrl); sendMessage(file, attachmentUrl);
}); });
}); });
@ -193,7 +217,7 @@ bot.registerCommandAlias('r', 'reply');
bot.registerCommand('close', (msg, args) => { bot.registerCommand('close', (msg, args) => {
if (! msg.channel.guild) return; if (! msg.channel.guild) return;
if (msg.channel.guild.id !== modMailGuild.id) return; if (msg.channel.guild.id !== utils.getModmailGuild(bot).id) return;
if (! msg.member.permission.has('manageRoles')) return; if (! msg.member.permission.has('manageRoles')) return;
threads.getByChannelId(msg.channel.id).then(thread => { threads.getByChannelId(msg.channel.id).then(thread => {
@ -208,7 +232,7 @@ bot.registerCommand('close', (msg, args) => {
logs.getNewLogFile(thread.userId).then(logFilename => { logs.getNewLogFile(thread.userId).then(logFilename => {
logs.saveLogFile(logFilename, log) logs.saveLogFile(logFilename, log)
.then(() => getLogFileUrl(logFilename)) .then(() => logs.getLogFileUrl(logFilename))
.then(url => { .then(url => {
const closeMessage = `Modmail thread with ${thread.username} (${thread.userId}) was closed by ${msg.author.mention} const closeMessage = `Modmail thread with ${thread.username} (${thread.userId}) was closed by ${msg.author.mention}
Logs: <${url}>`; Logs: <${url}>`;
@ -240,7 +264,7 @@ bot.registerCommand('block', (msg, args) => {
// Calling !block without args in a modmail thread blocks the user of that thread // Calling !block without args in a modmail thread blocks the user of that thread
threads.getByChannelId(msg.channel.id).then(thread => { threads.getByChannelId(msg.channel.id).then(thread => {
if (! thread) return; if (! thread) return;
block(userId); block(thread.userId);
}); });
} }
}); });
@ -264,7 +288,7 @@ bot.registerCommand('unblock', (msg, args) => {
// Calling !unblock without args in a modmail thread unblocks the user of that thread // Calling !unblock without args in a modmail thread unblocks the user of that thread
threads.getByChannelId(msg.channel.id).then(thread => { threads.getByChannelId(msg.channel.id).then(thread => {
if (! thread) return; if (! thread) return;
unblock(userId); unblock(thread.userId);
}); });
} }
}); });
@ -275,7 +299,7 @@ bot.registerCommand('logs', (msg, args) => {
if (! msg.member.permission.has('manageRoles')) return; if (! msg.member.permission.has('manageRoles')) return;
function getLogs(userId) { function getLogs(userId) {
getLogsWithUrlByUserId(userId).then(infos => { logs.getLogsWithUrlByUserId(userId).then(infos => {
let message = `**Log files for <@${userId}>:**\n`; let message = `**Log files for <@${userId}>:**\n`;
message += infos.map(info => { message += infos.map(info => {
@ -295,7 +319,7 @@ bot.registerCommand('logs', (msg, args) => {
// Calling !logs without args in a modmail thread returns the logs of the user of that thread // Calling !logs without args in a modmail thread returns the logs of the user of that thread
threads.getByChannelId(msg.channel.id).then(thread => { threads.getByChannelId(msg.channel.id).then(thread => {
if (! thread) return; if (! thread) return;
getLogs(userId); getLogs(thread.userId);
}); });
} }
}); });

View File

@ -1,12 +1,13 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const config = require('../config');
const dbDir = config.dbDir || `${__dirname}/db`; const dbDir = config.dbDir || `${__dirname}/../db`;
const databases = {}; const databases = {};
class JSONDB { class JSONDB {
constructor(path, def = {}, useCloneByDefault = true) { constructor(path, def = {}, useCloneByDefault = false) {
this.path = path; this.path = path;
this.useCloneByDefault = useCloneByDefault; this.useCloneByDefault = useCloneByDefault;

View File

@ -2,10 +2,25 @@ const fs = require('fs');
const crypto = require('crypto'); const crypto = require('crypto');
const moment = require('moment'); const moment = require('moment');
const config = require('../config'); const config = require('../config');
const utils = require('./utils');
const logDir = config.logDir || `${__dirname}/logs`; const logDir = config.logDir || `${__dirname}/../logs`;
const logFileFormatRegex = /^([0-9\-]+?)__([0-9]+?)__([0-9a-f]+?)\.txt$/; const logFileFormatRegex = /^([0-9\-]+?)__([0-9]+?)__([0-9a-f]+?)\.txt$/;
/**
* @typedef {Object} LogFileInfo
* @property {String} filename
* @property {String} date
* @property {String} userId
* @property {String} token
* @property {String=} url
*/
/**
* Returns information about the given logfile
* @param {String} logFilename
* @returns {LogFileInfo}
*/
function getLogFileInfo(logFilename) { function getLogFileInfo(logFilename) {
const match = logFilename.match(logFileFormatRegex); const match = logFilename.match(logFileFormatRegex);
if (! match) return null; if (! match) return null;
@ -20,15 +35,30 @@ function getLogFileInfo(logFilename) {
}; };
} }
/**
* Returns the filesystem path to the given logfile
* @param {String} logFilename
* @returns {String}
*/
function getLogFilePath(logFilename) { function getLogFilePath(logFilename) {
return `${logDir}/${logFilename}`; return `${logDir}/${logFilename}`;
} }
/**
* Returns the self-hosted URL to the given logfile
* @param {String} logFilename
* @returns {String}
*/
function getLogFileUrl(logFilename) { function getLogFileUrl(logFilename) {
const info = getLogFileInfo(logFilename); const info = getLogFileInfo(logFilename);
return utils.getSelfUrl(`logs/${info.token}`); return utils.getSelfUrl(`logs/${info.token}`);
} }
/**
* Returns a new, unique log file name for the given userId
* @param {String} userId
* @returns {Promise<String>}
*/
function getNewLogFile(userId) { function getNewLogFile(userId) {
return new Promise(resolve => { return new Promise(resolve => {
crypto.randomBytes(16, (err, buf) => { crypto.randomBytes(16, (err, buf) => {
@ -40,6 +70,11 @@ function getNewLogFile(userId) {
}); });
} }
/**
* Finds a log file name by its token
* @param {String} token
* @returns {Promise<String>}
*/
function findLogFile(token) { function findLogFile(token) {
return new Promise(resolve => { return new Promise(resolve => {
fs.readdir(logDir, (err, files) => { fs.readdir(logDir, (err, files) => {
@ -55,9 +90,16 @@ function findLogFile(token) {
}); });
} }
/**
* Returns all log file infos for the given userId
* @param {String} userId
* @returns {Promise<LogFileInfo[]>}
*/
function getLogsByUserId(userId) { function getLogsByUserId(userId) {
return new Promise(resolve => { return new Promise((resolve, reject) => {
fs.readdir(logDir, (err, files) => { fs.readdir(logDir, (err, files) => {
if (err) return reject(err);
const logfileInfos = files const logfileInfos = files
.map(file => getLogFileInfo(file)) .map(file => getLogFileInfo(file))
.filter(info => info && info.userId === userId); .filter(info => info && info.userId === userId);
@ -67,6 +109,11 @@ function getLogsByUserId(userId) {
}); });
} }
/**
* Returns all log file infos with URLs for the given userId
* @param {String} userId
* @returns {Promise<LogFileInfo[]>}
*/
function getLogsWithUrlByUserId(userId) { function getLogsWithUrlByUserId(userId) {
return getLogsByUserId(userId).then(infos => { return getLogsByUserId(userId).then(infos => {
const urlPromises = infos.map(info => { const urlPromises = infos.map(info => {
@ -88,6 +135,11 @@ function getLogsWithUrlByUserId(userId) {
}); });
} }
/**
* @param {String} logFilename
* @param {String} content
* @returns {Promise}
*/
function saveLogFile(logFilename, content) { function saveLogFile(logFilename, content) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fs.writeFile(getLogFilePath(logFilename), content, {encoding: 'utf8'}, err => { fs.writeFile(getLogFilePath(logFilename), content, {encoding: 'utf8'}, err => {
@ -105,4 +157,5 @@ module.exports = {
getLogsByUserId, getLogsByUserId,
getLogsWithUrlByUserId, getLogsWithUrlByUserId,
saveLogFile, saveLogFile,
getLogFileUrl,
}; };

View File

@ -16,10 +16,10 @@ const jsonDb = require('./jsonDb');
* @param {Eris.Client} bot * @param {Eris.Client} bot
* @param {Eris.User} user * @param {Eris.User} user
* @param {Boolean} allowCreate * @param {Boolean} allowCreate
* @returns {Promise<ThreadInfo>} * @returns {Promise<ModMailThread>}
*/ */
function getForUser(bot, user, allowCreate = true) { function getForUser(bot, user, allowCreate = true) {
return jsonDb.get('threads').then(threads => { return jsonDb.get('threads', []).then(threads => {
const thread = threads.find(t => t.userId === user.id); const thread = threads.find(t => t.userId === user.id);
if (thread) return thread; if (thread) return thread;
@ -41,12 +41,12 @@ function getForUser(bot, user, allowCreate = true) {
username: `${user.username}#${user.discriminator}`, username: `${user.username}#${user.discriminator}`,
}; };
const threads = jsonDb.get('threads'); return jsonDb.get('threads', []).then(threads => {
threads.push(thread); threads.push(thread);
jsonDb.save('threads', threads); jsonDb.save('threads', threads);
thread._wasCreated = true; return Object.assign({}, thread, {_wasCreated: true});
return thread; });
}, err => { }, err => {
console.error(`Error creating modmail channel for ${user.username}#${user.discriminator}!`); console.error(`Error creating modmail channel for ${user.username}#${user.discriminator}!`);
}); });
@ -55,17 +55,22 @@ function getForUser(bot, user, allowCreate = true) {
/** /**
* @param {String} channelId * @param {String} channelId
* @returns {Promise<ThreadInfo>} * @returns {Promise<ModMailThread>}
*/ */
function getByChannelId(channelId) { function getByChannelId(channelId) {
return jsonDb.get('threads').then(threads => { return jsonDb.get('threads', []).then(threads => {
return threads.find(t => t.userId === user.id); return threads.find(t => t.channelId === channelId);
}); });
} }
/**
* Deletes the modmail thread for the given channel id
* @param {String} channelId
* @returns {Promise}
*/
function close(channelId) { function close(channelId) {
return jsonDb.get('threads').then(threads => { return jsonDb.get('threads', []).then(threads => {
const thread = threads.find(t => t.userId === user.id); const thread = threads.find(t => t.channelId === channelId);
if (! thread) return; if (! thread) return;
threads.splice(threads.indexOf(thread), 1); threads.splice(threads.indexOf(thread), 1);

View File

@ -1,37 +1,22 @@
const Eris = require('eris');
const moment = require('moment'); const moment = require('moment');
const publicIp = require('public-ip'); const publicIp = require('public-ip');
const config = require('../config'); const config = require('../config');
const utils = require('./utils'); const utils = require('./utils');
let modMailGuild = null;
function getModmailGuild(bot) { function getModmailGuild(bot) {
return bot.guilds.find(g => g.id === config.mailGuildId); if (! modMailGuild) modMailGuild = bot.guilds.find(g => g.id === config.mailGuildId);
} return modMailGuild;
function formatAttachment(attachment) {
let filesize = attachment.size || 0;
filesize /= 1024;
return utils.getAttachmentUrl(attachment.id, attachment.filename).then(attachmentUrl => {
return `**Attachment:** ${attachment.filename} (${filesize.toFixed(1)}KB)\n${attachmentUrl}`;
});
}
function formatUserDM(msg) {
let content = msg.content;
// Get a local URL for all attachments so we don't rely on discord's servers (which delete attachments when the channel/DM thread is deleted)
const attachmentFormatPromise = msg.attachments.map(formatAttachment);
return Promise.all(attachmentFormatPromise).then(formattedAttachments => {
formattedAttachments.forEach(str => {
content += `\n\n${str}`;
});
return content;
});
} }
const userMentionRegex = /^<@\!?([0-9]+?)>$/; const userMentionRegex = /^<@\!?([0-9]+?)>$/;
/**
* Returns the user ID of the user mentioned in str, if any
* @param {String} str
* @returns {String|null}
*/
function getUserMention(str) { function getUserMention(str) {
str = str.trim(); str = str.trim();
@ -46,30 +31,56 @@ function getUserMention(str) {
return null; return null;
} }
/**
* Returns the current timestamp in an easily readable form
* @param {String|Date|undefined} date
* @returns {String}
*/
function getTimestamp(date) { function getTimestamp(date) {
return moment.utc(date).format('HH:mm'); return moment.utc(date).format('HH:mm');
} }
/**
* Disables link previews in the given string by wrapping links in < >
* @param {String} str
* @returns {String}
*/
function disableLinkPreviews(str) { function disableLinkPreviews(str) {
return str.replace(/(^|[^<])(https?:\/\/\S+)/ig, '$1<$2>'); return str.replace(/(^|[^<])(https?:\/\/\S+)/ig, '$1<$2>');
} }
function getSelfUrl(path) { /**
* Returns a URL to the bot's web server
* @param {String} path
* @returns {String}
*/
function getSelfUrl(path = '') {
if (config.url) { if (config.url) {
return Promise.resolve(`${config.url}/${path}`); return Promise.resolve(`${config.url}/${path}`);
} else { } else {
const port = config.port || 8890;
return publicIp.v4().then(ip => { return publicIp.v4().then(ip => {
return `http://${ip}:${logServerPort}/${path}`; return `http://${ip}:${port}/${path}`;
}); });
} }
} }
/**
* Returns the highest hoisted role of the given member
* @param {Eris.Member} member
* @returns {Eris.Role}
*/
function getMainRole(member) {
const roles = member.roles.map(id => member.guild.roles.get(id));
roles.sort((a, b) => a.position > b.position ? -1 : 1);
return roles.find(r => r.hoist);
}
module.exports = { module.exports = {
getModmailGuild, getModmailGuild,
formatAttachment,
formatUserDM,
getUserMention, getUserMention,
getTimestamp, getTimestamp,
disableLinkPreviews, disableLinkPreviews,
getSelfUrl, getSelfUrl,
getMainRole,
}; };

View File

@ -1,6 +1,10 @@
const http = require('http'); const http = require('http');
const mime = require('mime'); const mime = require('mime');
const url = require('url');
const fs = require('fs');
const config = require('../config'); const config = require('../config');
const logs = require('./logs');
const attachments = require('./attachments');
const port = config.port || 8890; const port = config.port || 8890;
@ -8,10 +12,10 @@ function serveLogs(res, pathParts) {
const token = pathParts[pathParts.length - 1]; const token = pathParts[pathParts.length - 1];
if (token.match(/^[0-9a-f]+$/) === null) return res.end(); if (token.match(/^[0-9a-f]+$/) === null) return res.end();
findLogFile(token).then(logfile => { logs.findLogFile(token).then(logFilename => {
if (logfile === null) return res.end(); if (logFilename === null) return res.end();
fs.readFile(getLogFilePath(logfile), {encoding: 'utf8'}, (err, data) => { fs.readFile(logs.getLogFilePath(logFilename), {encoding: 'utf8'}, (err, data) => {
if (err) { if (err) {
res.statusCode = 404; res.statusCode = 404;
res.end('Log not found'); res.end('Log not found');
@ -31,7 +35,7 @@ function serveAttachments(res, pathParts) {
if (id.match(/^[0-9]+$/) === null) return res.end(); if (id.match(/^[0-9]+$/) === null) return res.end();
if (desiredFilename.match(/^[0-9a-z\._-]+$/i) === null) return res.end(); if (desiredFilename.match(/^[0-9a-z\._-]+$/i) === null) return res.end();
const attachmentPath = getAttachmentPath(id); const attachmentPath = attachments.getPath(id);
fs.access(attachmentPath, (err) => { fs.access(attachmentPath, (err) => {
if (err) { if (err) {
res.statusCode = 404; res.statusCode = 404;
@ -59,7 +63,7 @@ function run() {
if (parsedUrl.path.startsWith('/attachments/')) serveAttachments(res, pathParts); if (parsedUrl.path.startsWith('/attachments/')) serveAttachments(res, pathParts);
}); });
server.listen(logServerPort); server.listen(port);
} }
module.exports = { module.exports = {

View File

@ -1,4 +1,5 @@
#!/bin/bash #!/bin/bash
git pull git pull
yarn
pm2 restart ModmailBot pm2 restart ModmailBot