var fs = require('fs');
var minify = require('html-minifier').minify;
var escape = require('escape-html');
var md = require('markdown-it')({breaks: true, linkify: true});
var he = require('he'); // Encodes HTML attributes
// Minify at runtime to save data on slow connections, but still allow editing the unminified file easily
// Is that a bad idea?
// Templates for viewing the messages in a channel
const channel_template = minify(fs.readFileSync('pages/templates/channel.html', 'utf-8'));
const message_template = minify(fs.readFileSync('pages/templates/message/message.html', 'utf-8'));
const first_message_content_template = minify(fs.readFileSync('pages/templates/message/first_message_content.html', 'utf-8'));
const merged_message_content_template = minify(fs.readFileSync('pages/templates/message/merged_message_content.html', 'utf-8'));
const mention_template = minify(fs.readFileSync('pages/templates/message/mention.html', 'utf-8'));
const input_template = minify(fs.readFileSync('pages/templates/channel/input.html', 'utf-8'));
const input_disabled_template = minify(fs.readFileSync('pages/templates/channel/input_disabled.html', 'utf-8'));
const no_message_history_template = minify(fs.readFileSync('pages/templates/channel/no_message_history.html', 'utf-8'));
function strReplace(string, needle, replacement) {
return string.split(needle).join(replacement||"");
};
// https://stackoverflow.com/questions/1967119/why-does-javascript-replace-only-first-instance-when-using-replace
exports.processChannel = async function processChannel(bot, req, res, args, discordID) {
try {
response = "";
chnl = await bot.client.channels.fetch(args[2]);
} catch (err) {
chnl = undefined;
}
if (chnl) {
member = await chnl.guild.members.fetch(discordID);
user = member.user;
username = user.tag;
if (member.displayName != user.username) {
username = member.displayName + " (@" + user.tag + ")";
}
if (!member.permissionsIn(chnl).has("VIEW_CHANNEL", true)) {
res.write("You don't have permission to do that!");
res.end();
return;
}
if (!member.permissionsIn(chnl).has("READ_MESSAGE_HISTORY", true)) {
template = strReplace(channel_template, "{$SERVER_ID}", chnl.guild.id)
template = strReplace(template, "{$CHANNEL_ID}", chnl.id)
if (member.permissionsIn(chnl).has("SEND_MESSAGES", true)) {
final = strReplace(template, "{$INPUT}", input_template);
} else {
final = strReplace(template, "{$INPUT}", input_disabled_template);
}
final = strReplace(final, "{$MESSAGES}", no_message_history_template); // You do not have permission... message
res.write(final); //write a response to the client
res.end(); //end the response
return;
}
console.log("Processed valid channel request");
messages = await bot.getHistoryCached(chnl);
lastauthor = undefined;
lastmember = undefined;
lastdate = new Date('1995-12-17T03:24:00');
currentmessage = "";
islastmessage = false;
handlemessage = async function (item) { // Save the function to use later in the for loop and to process the last message
if (lastauthor) { // Only consider the last message if this is not the first
// If the last message is not going to be merged with this one, put it into the response
if (islastmessage || lastauthor.id != item.author.id || lastauthor.username != item.author.username || item.createdAt - lastdate > 420000) {
currentmessage = message_template.replace("{$MESSAGE_CONTENT}", currentmessage);
if (lastmember) { // Webhooks are not members!
currentmessage = currentmessage.replace("{$MESSAGE_AUTHOR}", escape(lastmember.displayName));
} else {
currentmessage = currentmessage.replace("{$MESSAGE_AUTHOR}", escape(lastauthor.username));
}
var url = lastauthor.avatarURL();
if (lastauthor.avatarURL && url && url.toString().startsWith("http")) { // Sometimes the URL is null or something else
currentmessage = currentmessage.replace("{$PROFILE_URL}", url);
}
currentmessage = strReplace(currentmessage, "{$MESSAGE_DATE}", lastdate.toLocaleTimeString('en-US') + " " + lastdate.toDateString());
currentmessage = strReplace(currentmessage, "{$TAG}", he.encode(JSON.stringify("@" + lastauthor.tag)));
response += currentmessage;
currentmessage = "";
}
}
if (!item) { // When processing the last message outside of the forEach item is undefined
return;
}
// messagetext = strReplace(escape(item.content), "\n", "
");
messagetext = /* strReplace( */ md.renderInline(item.content) /* , "\n", "
") */;
if (item.mentions) {
item.mentions.members.forEach(function(user) {
if (user) {
messagetext = strReplace(messagetext, "<@" + user.id.toString() + ">", mention_template.replace("{$USERNAME}", escape("@" + user.displayName)));
messagetext = strReplace(messagetext, "<@!" + user.id.toString() + ">", mention_template.replace("{$USERNAME}", escape("@" + user.displayName)));
}
});
}
// https://stackoverflow.com/questions/6323417/regex-to-extract-all-matches-from-string-using-regexp-exec
var regex = /<#([0-9]{18})>/g; // Regular expression to detect channel IDs
var m;
do {
m = regex.exec(messagetext);
if (m) {
try {
channel = await bot.client.channels.cache.get(m[1]);
} catch(err) {
console.log(err);
}
if (channel) {
messagetext = strReplace(messagetext, m[0], mention_template.replace("{$USERNAME}", escape("#" + channel.name)));
}
}
} while (m);
messagetext = strReplace(messagetext, "@everyone", mention_template.replace("{$USERNAME}", "@everyone"));
messagetext = strReplace(messagetext, "@here", mention_template.replace("{$USERNAME}", "@here"));
// If the last message is not going to be merged with this one, use the template for the first message, otherwise use the template for merged messages
if (!lastauthor || lastauthor.id != item.author.id || lastauthor.username != item.author.username || item.createdAt - lastdate > 420000) {
messagetext = first_message_content_template.replace("{$MESSAGE_TEXT}", messagetext);
} else {
messagetext = merged_message_content_template.replace("{$MESSAGE_TEXT}", messagetext);
}
lastauthor = item.author;
lastmember = item.member;
lastdate = item.createdAt;
currentmessage += messagetext;
}
for (const item of messages) {
await handlemessage(item);
}
// Handle the last message
// Uses the function in the foreach from earlier
islastmessage = true;
await handlemessage();
template = strReplace(channel_template, "{$SERVER_ID}", chnl.guild.id)
template = strReplace(template, "{$CHANNEL_ID}", chnl.id)
template = strReplace(template, "{$REFRESH_URL}", chnl.id + "?random=" + Math.random() + "#end")
if (member.permissionsIn(chnl).has("SEND_MESSAGES", true)) {
final = strReplace(template, "{$INPUT}", input_template);
} else {
final = strReplace(template, "{$INPUT}", input_disabled_template);
}
final = strReplace(final, "{$MESSAGES}", response);
res.writeHead(200, { "Content-Type": "text/html" });
res.write(final); //write a response to the client
res.end(); //end the response
} else {
res.writeHead(404, { "Content-Type": "text/html" });
res.write("Invalid channel!"); //write a response to the client
res.end(); //end the response
}
}