import hljs from "highlight.js";
import { format } from "prettier";
import Database from "better-sqlite3";
import { verifyComment } from "../shush/shush.js";
import grimm from "./grimm.js";
import md5 from "./md5.js";
import rubric from "./rubric.js";
import pugTheme from "./pug-highlight.js";
const db = new Database("./db/site.db");
db.pragma("journal_mode = DELETE");
hljs.registerLanguage("pug", pugTheme);
rubric.langs.html.els.heading = (node, opt, lang) => {
const parsed = lang.parse(node.text, opt);
const headerSlug = grimm.slugify(parsed, { html: true });
return `\n<h${node.level}${
opt.hyperlinkHeadings && node.level > 1 ? ` id="${headerSlug}"` : ""
}>${
opt.hyperlinkHeadings && node.level > 1 && !parsed.includes("<a ")
? `<a href="#${headerSlug}">${parsed}</a>`
: parsed
}</h${node.level}>\n`;
};
rubric.langs.html.els.pre = (node, opt, lang) => {
if (!opt.highlightCode) {
return `\n<pre><code>${lang.escape(node.text)}</code></pre>\n`;
}
let highlit;
if (node.language) {
highlit = hljs.highlight(node.text, {
language: node.language
});
} else {
highlit = hljs.highlightAuto(node.text);
}
return `\n<pre><code class="hljs language-${highlit.language}">${highlit.value}</code></pre>\n`;
};
const getRubricFilters = rbc => ({
rubric: text => {
return rbc.parse(text);
},
"rubric-comment": (text, options = {}) => {
let parsed;
try {
parsed = rbc.parse(text, "html", rbc.options.comments);
} catch (e) {
parsed = `<i>Formatting error</i>: <pre>${e}</pre>`;
}
return parsed;
},
"rubric-unsafe": (text, options = {}) => {
let parsed;
try {
parsed = rbc.parse(text, "html", rbc.options.risky);
} catch (e) {
parsed = `<i>Formatting error</i>: <pre>${e}</pre>`;
}
return options.afterwards ? options.afterwards(parsed) : parsed;
},
"rubric-inline": (text, options = {}) => {
let parsed;
try {
parsed = rbc.parse(text, "html", rbc.options.inlineRisky);
} catch (e) {
parsed = `<i>Formatting error</i>: <pre>${e}</pre>`;
}
return options.afterwards ? options.afterwards(parsed) : parsed;
}
});
const highlightFilter = {
highlight: (text, options) => {
let highlit;
if (options.lang) {
highlit = hljs.highlight(text, {
language: options.lang
});
} else {
highlit = hljs.highlightAuto(text);
}
return `<code class="hljs language-${highlit.language}">${highlit.value}</code>`;
}
};
const auth = permission => {
if (permission) {
return (req, res, next) => {
if (req?.user) {
req.user.prefs = db
.prepare(`Select * From user_preferences Where userID = ?`)
.get(req.user.userID);
}
if (req?.user?.permissions === permission) {
return next();
}
return next(createError(403));
};
} else {
return (req, res, next) => {
if (req?.user) {
req.user.prefs = db
.prepare(`Select * From user_preferences Where userID = ?`)
.get(req.user.userID);
}
if (req.isAuthenticated()) {
return next();
}
return next(createError(403));
};
}
};
const base32 = int => {
const digits = "0123456789abcdefghjkmnpqrstvwxyz";
let thirtyTwo = "";
let quotient = int;
while (quotient > 0) {
thirtyTwo = `${digits[quotient % 32]}${thirtyTwo}`;
quotient = Math.floor(quotient / 32);
}
return thirtyTwo.padStart(8, "0");
};
const comparePages = (a, b) => {
const isOriginal = x =>
"slug" in x && "translates" in x && x.slug == x.translates;
const localeSort = x => grimm.dict?.[x.lang]?.meta?.sort ?? x.lang;
if (isOriginal(a) > isOriginal(b) || localeSort(a) < localeSort(b)) {
return -1;
}
if (isOriginal(a) < isOriginal(b) || localeSort(a) > localeSort(b)) {
return 1;
}
return 0;
};
const getComments = fullSlug =>
db
.prepare(
`Select * From comments
Where page_id = ? And planet = 'earth' And shown = 1`
)
.all(fullSlug)
.map(cmt => ({
id: cmt.id,
pageId: fullSlug,
name: cmt.name,
hash: {
cmt: cmt.hashcode,
tripcode: cmt.hashcode
? base32(parseInt(cmt.hashcode.slice(0, 10), 16))
: null,
avatar: cmt.hashcode ? cmt.hashcode[0] : md5(cmt.name)[0]
},
website: cmt.website
? cmt.website.includes("//")
? cmt.website
: `//${cmt.website}`
: null,
content: cmt.content,
submitDate: cmt["submit_date"].match(/[-+][0-9]{2}:|Z/)
? cmt["submit_date"].replace(" ", "T")
: `${cmt["submit_date"].replace(" ", "T")}Z`,
country: cmt.country,
lang: cmt.lang,
planet: cmt.planet,
verified: verifyComment(cmt)
}));
const prettyRender = (res, next, url, data) =>
res.render(url, data, (err, html) => {
if (err) {
return next(err);
}
let sent;
try {
sent = format(html, {
useTabs: true,
tabWidth: 4,
bracketSameLine: true,
trailingComma: "none",
arrowParens: "avoid",
parser: "html",
printWidth: 128
});
} catch {
sent = html;
}
return res.send(sent);
});
const rootFolder = "/home/atossa/server/satyrsforest";
export {
rubric,
getRubricFilters,
highlightFilter,
auth,
base32,
comparePages,
getComments,
prettyRender,
rootFolder,
md5
};