1
0
Fork 0
mirror of https://git.sr.ht/~roxwize/mipilin synced 2025-01-31 02:53:36 +00:00
mipilin/routes/util.ts

152 lines
4.4 KiB
TypeScript
Raw Permalink Normal View History

import { NodePgDatabase } from "drizzle-orm/node-postgres";
import type { Request, Response } from "express";
import { inviteCodes, updates } from "../db/schema.js";
import { count, desc, eq } from "drizzle-orm";
import fs from "node:fs/promises";
export enum UserStatus {
MODERATOR = 0b0001,
BANNED = 0b0010,
TRUSTED = 0b0100,
GUEST = 0b1000
}
const nonceChars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-_";
let nonce: string;
export function setNonce() {
nonce = "";
for (let i = 0; i < 32; i++)
nonce += nonceChars[Math.floor(Math.random() * nonceChars.length)];
return nonce;
}
export function getNonce() {
if (!nonce) throw new Error("Nonce doesn't exist");
return nonce;
}
let moods: string[], moodsSorted: string[];
export async function getMoods() {
if (!moods)
moods = (await fs.readFile("./static/moods.txt"))
.toString("utf-8")
.split(";");
if (!moodsSorted) moodsSorted = Array.from(moods).sort();
return { moods, moodsSorted };
}
export async function render(
db: NodePgDatabase,
page: string,
title: string,
res: Response,
req: Request,
stuff?: Object
) {
//? maybe you should cache this and save the current mood to the session until it's changed
const { moods } = await getMoods();
let currentMood: string;
if (req.session["loggedIn"]) {
const update = (
await db
.select({ mood: updates.mood })
.from(updates)
.where(eq(updates.user, req.session["uid"]))
.orderBy(desc(updates.date))
.limit(1)
)[0];
currentMood = moods[update?.mood];
}
const o = {
title,
session: req.session,
flashes: req.flash(),
moods,
currentMood,
nonce
};
res.render(page, { ...o, ...stuff });
}
export async function render404(
db: NodePgDatabase,
res: Response,
req: Request
) {
res.statusCode = 404;
render(db, "404", "not found", res, req);
}
const inviteCodeChars = "abcdefghijklmnopqrstuvwxyz0123456789";
export async function createInviteCode(
db: NodePgDatabase,
user: number,
expires: Date,
confers = 0
) {
let existingToken = 1,
token: string;
while (existingToken) {
token = user.toString().padStart(4, "0") + "-";
for (let i = 0; i < 17; i++) {
if ((i + 1) % 6 === 0) {
token += "-";
continue;
}
token +=
inviteCodeChars[
Math.floor(Math.random() * inviteCodeChars.length)
];
}
existingToken = (
await db
.select({ value: count() })
.from(inviteCodes)
.where(eq(inviteCodes.token, token))
)[0].value;
}
//@ts-expect-error
await db.insert(inviteCodes).values({
token,
user: user || undefined,
granted: new Date(Date.now()),
expires,
confers
});
return token;
}
export function journalMoodString(mood: number) {
switch (mood) {
case -2:
return "much worse";
case -1:
return "worse";
default:
case 0:
return "about the same";
case 1:
return "better";
case 2:
return "much better";
}
}
export function confirm(
db: NodePgDatabase,
res: Response,
req: Request
) {
render(db, "confirm", "Confirm action", res, req, { body: req.body, url: req.url });
}
const emailRegex = /^([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22))*\x40([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d))*$/i;
const urlRegex = /https?:\/\/(?:www\.)?(?:[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b)*(?:\/[\/\d\w\.-]*)*(?:[\?])*(?:.+)*/i;
export function validateEmail(email: string) {
return emailRegex.test(email);
}
export function validateUrl(url: string) {
return urlRegex.test(url);
}