const {MessageFlags} = require("@projectdysnomia/dysnomia").Constants; const events = require("../lib/events.js"); const {hasFlag} = require("../lib/guildSettings.js"); const REGEX_GITHUB = /(?:\s|^)https?:\/\/(www\.)?github\.com\/.+?\/.+?\/blob\/([a-zA-Z0-9-_.#/]*)/g; const REGEX_GITLAB = /(?:\s|^)https?:\/\/.+?\/.+?\/.+?\/-\/blob\/([a-zA-Z0-9-_.#/]*)/g; const REGEX_GITEA = /(?:\s|^)https?:\/\/.+?\/.+?\/.+?\/src\/branch\/([a-zA-Z0-9-_.#/]*)/g; function unindent(str) { str = str.replace(/\t/g, " "); const minIndent = str .match(/^ *(?=\S)/gm) ?.reduce((prev, curr) => Math.min(prev, curr.length), Infinity) ?? 0; if (!minIndent) return str; return str.replace(new RegExp(`^ {${minIndent}}`, "gm"), ""); } async function processFile(link) { const res = await fetch(link); if (!res.ok) return ""; const file = await res.text(); const lines = file.replace(/\r/g, "").split("\n"); const fileName = link.substring( link.lastIndexOf("/") + 1, link.indexOf("#") == -1 ? link.length : link.indexOf("#") ); const fileType = fileName.lastIndexOf(".") == -1 ? "" : fileName.substring(fileName.lastIndexOf(".") + 1); const lineStr = link.match(/#L\d+(-L?\d+)?/)?.[0]; let startLine, endLine; let entireFile = false; if (lineStr) { const [start, end] = lineStr.match(/\d+/g); if (!end) { startLine = endLine = start; } else { startLine = start; endLine = end; } } else { entireFile = true; startLine = 0; endLine = lines.length; } const whichLines = entireFile ? "" : startLine == endLine ? "Line " + startLine : "Lines " + startLine + "-" + endLine; const targetLines = ( entireFile ? lines.length > 30 ? lines.slice(0, 30) : lines : lines.slice(startLine - 1, endLine) ).join("\n"); return `**${fileName}: **${whichLines}\n\`\`\`${fileType}\n${unindent( targetLines )}${ entireFile && lines.length > 30 ? `\n... (${lines.length - 30} lines left)` : "" }\n\`\`\``; } events.add("messageCreate", "codePreviews", async function (msg) { if (msg.author.id == hf.bot.user.id) return; if (!msg.guildID) return; if (!(await hasFlag(msg.guildID, "codePreviews"))) return; const files = []; const githubLinks = msg.content.match(REGEX_GITHUB); const gitlabLinks = msg.content.match(REGEX_GITLAB); const giteaLinks = msg.content.match(REGEX_GITEA); if (githubLinks?.length) { for (const link of githubLinks) { files.push(await processFile(link.replace("/blob/", "/raw/"))); } } if (gitlabLinks?.length) { for (const link of gitlabLinks) { files.push(await processFile(link.replace("/blob/", "/raw/"))); } } if (giteaLinks?.length) { for (const link of giteaLinks) { files.push(await processFile(link.replace("/src/", "/raw/"))); } } let out = ""; const allFiles = files.join("\n").trim(); if (allFiles !== "" && allFiles.length <= 2000) { await msg.edit({flags: MessageFlags.SUPPRESS_EMBEDS}).catch(() => {}); } for (let i = 0; i < files.length; i++) { const file = files[i]; if (file === "") continue; if (out.length + file.length > 2000) { await msg.channel.createMessage({ content: out, allowedMentions: { repliedUser: false, }, messageReference: { messageID: msg.id, }, }); out = file; } else { out += "\n" + file; out = out.trim(); } if (i == files.length - 1 && out.length <= 2000) { await msg.channel.createMessage({ content: out, allowedMentions: { repliedUser: false, }, messageReference: { messageID: msg.id, }, }); } } }); // TODO: maybe all command outputs should have this ability events.add( "messageReactionAdd", "codePreviews", async function (msg, reaction, reactor) { if (!msg.guildID) return; if (!(await hasFlag(msg.guildID, "codePreviews"))) return; if (reaction.name != "\u274c") return; let channel = msg.channel; if (!channel.name) { channel = hf.bot.getChannel(channel.id); } if (!msg.messageReference) { msg = await channel.getMessage(msg.id); } if (!msg.messageReference) return; const ref = await channel.getMessage(msg.messageReference.messageID); if (!ref) return; if ( ref.author.id != reactor.id || !channel.permissionsOf(reactor.id).has("manageMessages") ) return; if ( !REGEX_GITHUB.test(ref.content) && !REGEX_GITLAB.test(ref.content) && !REGEX_GITEA.test(ref.content) ) return; await msg.delete("Author requested code preview deletion"); } );