2024-11-14 03:51:08 +00:00
|
|
|
import { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
|
|
import type { Request, Response } from "express";
|
2024-12-11 03:27:43 +00:00
|
|
|
import { inviteCodes, updates } from "../db/schema.js";
|
|
|
|
import { count, desc, eq } from "drizzle-orm";
|
2024-11-14 03:51:08 +00:00
|
|
|
import fs from "node:fs/promises";
|
|
|
|
|
2024-12-25 23:44:29 +00:00
|
|
|
export enum UserStatus {
|
2025-01-28 04:34:46 +00:00
|
|
|
MODERATOR = 0b0001,
|
|
|
|
BANNED = 0b0010,
|
|
|
|
TRUSTED = 0b0100,
|
|
|
|
GUEST = 0b1000
|
2024-12-26 21:24:04 +00:00
|
|
|
}
|
2024-12-25 23:44:29 +00:00
|
|
|
|
2024-11-17 19:16:27 +00:00
|
|
|
const nonceChars =
|
2024-12-26 21:24:04 +00:00
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-_";
|
2024-11-17 19:16:27 +00:00
|
|
|
let nonce: string;
|
|
|
|
export function setNonce() {
|
2024-12-26 21:24:04 +00:00
|
|
|
nonce = "";
|
|
|
|
for (let i = 0; i < 32; i++)
|
|
|
|
nonce += nonceChars[Math.floor(Math.random() * nonceChars.length)];
|
|
|
|
return nonce;
|
2024-11-17 19:16:27 +00:00
|
|
|
}
|
|
|
|
export function getNonce() {
|
2024-12-26 21:24:04 +00:00
|
|
|
if (!nonce) throw new Error("Nonce doesn't exist");
|
|
|
|
return nonce;
|
2024-11-17 19:16:27 +00:00
|
|
|
}
|
|
|
|
|
2024-11-14 03:51:08 +00:00
|
|
|
let moods: string[], moodsSorted: string[];
|
|
|
|
export async function getMoods() {
|
2024-12-26 21:24:04 +00:00
|
|
|
if (!moods)
|
|
|
|
moods = (await fs.readFile("./static/moods.txt"))
|
|
|
|
.toString("utf-8")
|
|
|
|
.split(";");
|
|
|
|
if (!moodsSorted) moodsSorted = Array.from(moods).sort();
|
|
|
|
return { moods, moodsSorted };
|
2024-11-14 03:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export async function render(
|
2024-12-26 21:24:04 +00:00
|
|
|
db: NodePgDatabase,
|
|
|
|
page: string,
|
|
|
|
title: string,
|
|
|
|
res: Response,
|
|
|
|
req: Request,
|
|
|
|
stuff?: Object
|
2024-11-14 03:51:08 +00:00
|
|
|
) {
|
2024-12-26 21:24:04 +00:00
|
|
|
//? 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];
|
|
|
|
}
|
2024-11-14 03:51:08 +00:00
|
|
|
|
2024-12-26 21:24:04 +00:00
|
|
|
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);
|
2024-11-14 03:51:08 +00:00
|
|
|
}
|
2024-12-11 03:27:43 +00:00
|
|
|
|
2024-12-26 21:24:04 +00:00
|
|
|
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;
|
2024-12-11 03:27:43 +00:00
|
|
|
}
|
|
|
|
|
2024-12-26 21:24:04 +00:00
|
|
|
//@ts-expect-error
|
|
|
|
await db.insert(inviteCodes).values({
|
|
|
|
token,
|
|
|
|
user: user || undefined,
|
|
|
|
granted: new Date(Date.now()),
|
|
|
|
expires,
|
|
|
|
confers
|
|
|
|
});
|
|
|
|
return token;
|
2024-12-11 03:27:43 +00:00
|
|
|
}
|
2025-01-23 01:34:25 +00:00
|
|
|
|
|
|
|
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 });
|
|
|
|
}
|
2025-01-29 03:52:18 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|