mirror of
https://git.sr.ht/~roxwize/mipilin
synced 2025-05-07 22:13:07 +00:00
this is the initial commit for my AWESOME website
Signed-off-by: roxwize <rae@roxwize.xyz>
This commit is contained in:
commit
e3c09d7f0d
42 changed files with 5710 additions and 0 deletions
124
routes/login.ts
Normal file
124
routes/login.ts
Normal file
|
@ -0,0 +1,124 @@
|
|||
import { Express } from "express";
|
||||
import bcrypt from "bcrypt";
|
||||
import { render } from "./util.js";
|
||||
import { NodePgDatabase } from "drizzle-orm/node-postgres";
|
||||
import { profiles, users } from "../db/schema.js";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
export default function(app: Express, db: NodePgDatabase) {
|
||||
app.get("/register", (req, res) => {
|
||||
if (req.session["loggedIn"]) {
|
||||
res.redirect("/");
|
||||
return;
|
||||
}
|
||||
render(db, "register", "Sign up", res, req);
|
||||
});
|
||||
app.post("/register", async (req, res) => {
|
||||
if (req.session["loggedIn"]) {
|
||||
res.redirect("/");
|
||||
return;
|
||||
}
|
||||
if (req.body.name.length < 3) {
|
||||
req.flash("error", "Username can't be shorter than 3 characters");
|
||||
res.redirect("/register");
|
||||
return;
|
||||
}
|
||||
if (req.body.name.length > 26) {
|
||||
req.flash("error", "Username can't be longer than 26 characters");
|
||||
res.redirect("/register");
|
||||
return;
|
||||
}
|
||||
if (!req.body.name.match(/[A-Z0-9_-]/i)) {
|
||||
req.flash(
|
||||
"error",
|
||||
"Username can only contain letters, numbers, underscores, hyphens, and periods!!"
|
||||
);
|
||||
res.redirect("/register");
|
||||
return;
|
||||
}
|
||||
if (!req.body.email || !req.body.pass) {
|
||||
req.flash("error", "Email or password not provided");
|
||||
res.redirect("/register");
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
(await db.select().from(users).where(eq(users.name, req.body.name)))
|
||||
.length > 0
|
||||
) {
|
||||
req.flash("error", "That username is taken MORON");
|
||||
res.redirect("/register");
|
||||
return;
|
||||
}
|
||||
//! ew
|
||||
if (
|
||||
(await db.select().from(users).where(eq(users.email, req.body.email)))
|
||||
.length > 0
|
||||
) {
|
||||
req.flash("error", "A user with that email already exists");
|
||||
res.redirect("/register");
|
||||
return;
|
||||
}
|
||||
|
||||
const hash = await bcrypt.hash(req.body.pass, 10);
|
||||
const { uid } = (
|
||||
await db
|
||||
.insert(users)
|
||||
.values({
|
||||
name: req.body.name,
|
||||
email: req.body.email, //! Not actually validating this like at all???
|
||||
pass: hash,
|
||||
registered: new Date(Date.now())
|
||||
})
|
||||
.returning({ uid: users.id })
|
||||
)[0];
|
||||
await db.insert(profiles).values({ user: uid });
|
||||
|
||||
req.session["loggedIn"] = true;
|
||||
req.session["user"] = req.body.name;
|
||||
req.session["uid"] = uid;
|
||||
req.flash(
|
||||
"success",
|
||||
"Welcome to mipilin. After two weeks in development, hopefully it will have been worth the wait. Please let me know what you think after you have had a chance to use the website. I can be reached at gaben@roxwize.xyz, and my favorite mood is hormonal. Thanks, and have fun!"
|
||||
);
|
||||
res.redirect("/");
|
||||
});
|
||||
|
||||
app.get("/login", async (req, res) => {
|
||||
if (req.session["loggedIn"]) {
|
||||
res.redirect("/");
|
||||
return;
|
||||
}
|
||||
render(db, "login", "Log in", res, req);
|
||||
});
|
||||
app.post("/login", async (req, res) => {
|
||||
if (req.session["loggedIn"]) {
|
||||
res.redirect("/");
|
||||
return;
|
||||
}
|
||||
const user = (
|
||||
await db.select().from(users).where(eq(users.name, req.body.name))
|
||||
)[0];
|
||||
if (!user) {
|
||||
req.flash("error", "The username or password is invalid! I'm sorry! :(");
|
||||
res.redirect("/login");
|
||||
return;
|
||||
}
|
||||
if (await bcrypt.compare(req.body.pass, user.pass)) {
|
||||
req.session["loggedIn"] = true;
|
||||
req.session["user"] = user.name;
|
||||
req.session["uid"] = user.id;
|
||||
req.flash("success", "You're logged in! Welcome back!!");
|
||||
res.redirect("/dashboard");
|
||||
} else {
|
||||
req.flash("error", "The username or password is invalid! I'm sorry! :(");
|
||||
res.redirect("/login");
|
||||
}
|
||||
});
|
||||
app.get("/logout", (req, res) => {
|
||||
req.session["loggedIn"] = false;
|
||||
delete req.session["user"];
|
||||
req.flash("info", "Good bye!");
|
||||
res.redirect("/");
|
||||
});
|
||||
}
|
153
routes/users.ts
Normal file
153
routes/users.ts
Normal file
|
@ -0,0 +1,153 @@
|
|||
import { NodePgDatabase } from "drizzle-orm/node-postgres";
|
||||
import { Express } from "express";
|
||||
import { follows, profiles, updates, users } from "../db/schema.js";
|
||||
import { and, desc, eq } from "drizzle-orm";
|
||||
import { getMoods, render } from "./util.js";
|
||||
import { PgColumn } from "drizzle-orm/pg-core";
|
||||
|
||||
export default async function (app: Express, db: NodePgDatabase) {
|
||||
const { moods } = await getMoods();
|
||||
app.get("/users/:user", async (req, res) => {
|
||||
const isSelf = req.params.user === req.session["user"];
|
||||
|
||||
const user = (
|
||||
await db
|
||||
.select({
|
||||
id: users.id,
|
||||
name: users.name,
|
||||
bio: profiles.bio,
|
||||
website: profiles.website
|
||||
})
|
||||
.from(users)
|
||||
.where(eq(users.name, req.params.user))
|
||||
.leftJoin(profiles, eq(profiles.user, users.id))
|
||||
)[0];
|
||||
if (!user) {
|
||||
req.flash("error", `User ${req.params.user} does not exist`);
|
||||
res.redirect("/");
|
||||
return;
|
||||
}
|
||||
|
||||
// follows
|
||||
const isFollowing = !!(
|
||||
await db
|
||||
.select()
|
||||
.from(follows)
|
||||
.where(
|
||||
and(
|
||||
eq(follows.followerId, req.session["uid"]),
|
||||
eq(follows.userId, user.id)
|
||||
)
|
||||
)
|
||||
.limit(1)
|
||||
)[0];
|
||||
|
||||
// mood
|
||||
let moodSelection: { [k: string]: PgColumn } = {
|
||||
desc: updates.description,
|
||||
date: updates.date
|
||||
};
|
||||
if (!isSelf) moodSelection.mood = updates.mood;
|
||||
const userMood: { [k: string]: string | number | Date } = (
|
||||
await db
|
||||
.select(moodSelection)
|
||||
.from(updates)
|
||||
.where(eq(updates.user, user.id))
|
||||
.orderBy(desc(updates.date))
|
||||
.limit(1)
|
||||
)[0];
|
||||
|
||||
if (!isSelf) {
|
||||
userMood.mood = moods[userMood.mood as number];
|
||||
}
|
||||
|
||||
render(db, "user", `${req.params.user}'s Profile`, res, req, {
|
||||
user,
|
||||
isSelf,
|
||||
userMood,
|
||||
isFollowing
|
||||
});
|
||||
});
|
||||
app.post("/users/:user/edit", async (req, res) => {
|
||||
if (!req.session["loggedIn"]) {
|
||||
res.redirect("/login");
|
||||
return;
|
||||
}
|
||||
const { uname, mod } = (
|
||||
await db
|
||||
.select({ uname: users.name, mod: users.moderator })
|
||||
.from(users)
|
||||
.where(eq(users.name, req.params.user))
|
||||
)[0];
|
||||
if ((uname || "") !== req.session["user"] && !mod) {
|
||||
res.redirect("back");
|
||||
return;
|
||||
}
|
||||
|
||||
await db //! no sanitization here either BROOOOOOO
|
||||
.update(profiles)
|
||||
.set({
|
||||
// @ts-expect-error
|
||||
bio: req.body.bio,
|
||||
website: req.body.website
|
||||
})
|
||||
.where(eq(profiles.user, req.session["uid"]));
|
||||
req.flash("success", "Profile updated!");
|
||||
res.redirect("/dashboard");
|
||||
});
|
||||
app.post("/users/:user/follow", async (req, res) => {
|
||||
if (!req.session["loggedIn"]) {
|
||||
res.redirect("/login");
|
||||
return;
|
||||
}
|
||||
if (req.session["user"] === req.params.user) {
|
||||
req.flash("error", "Can't Follow Yourself Dummy");
|
||||
res.redirect(`/users/${req.params.user}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const { uid } = (
|
||||
await db
|
||||
.select({ uid: users.id })
|
||||
.from(users)
|
||||
.where(eq(users.name, req.params.user))
|
||||
)[0];
|
||||
if (!uid) {
|
||||
req.flash(
|
||||
"error",
|
||||
"It looks like you're trying to follow a user that doesn't exist anymore."
|
||||
);
|
||||
res.redirect("/");
|
||||
return;
|
||||
}
|
||||
const isFollowing = !!(
|
||||
await db
|
||||
.select()
|
||||
.from(follows)
|
||||
.where(
|
||||
and(
|
||||
eq(follows.followerId, req.session["uid"]),
|
||||
eq(follows.userId, uid)
|
||||
)
|
||||
)
|
||||
.limit(1)
|
||||
)[0];
|
||||
if (isFollowing) {
|
||||
// unfollow
|
||||
await db
|
||||
.delete(follows)
|
||||
.where(
|
||||
and(
|
||||
eq(follows.followerId, req.session["uid"]),
|
||||
eq(follows.userId, uid)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
await db.insert(follows).values({
|
||||
userId: uid,
|
||||
followerId: req.session["uid"]
|
||||
});
|
||||
}
|
||||
res.redirect(`/users/${req.params.user}`);
|
||||
});
|
||||
}
|
48
routes/util.ts
Normal file
48
routes/util.ts
Normal file
|
@ -0,0 +1,48 @@
|
|||
import { NodePgDatabase } from "drizzle-orm/node-postgres";
|
||||
import type { Request, Response } from "express";
|
||||
import { updates } from "../db/schema.js";
|
||||
import { desc, eq } from "drizzle-orm";
|
||||
import fs from "node:fs/promises";
|
||||
|
||||
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
|
||||
};
|
||||
res.render(page, { ...o, ...stuff });
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue