diff --git a/main.ts b/main.ts index a30f735..94f28cc 100644 --- a/main.ts +++ b/main.ts @@ -59,7 +59,12 @@ object-src 'none'; base-uri 'none';" return next(); }); app.use((req, res, next) => { - console.log(`${req.ip.padEnd(24)} ${req.method.padStart(8)} ${req.path}`); + let s = ""; + for (const [k, v] of Object.entries(req.query)) + s += `${k}=${v}&`; + s = s.slice(0, -1); + + console.log(`${req.ip.padEnd(24)} ${req.method.padStart(8)} ${req.path}${s ? "?" + s : ""}`); return next(); }) diff --git a/routes/users.ts b/routes/users.ts index d2e9163..f582481 100644 --- a/routes/users.ts +++ b/routes/users.ts @@ -8,7 +8,13 @@ import { users } from "../db/schema.js"; import { and, desc, eq, ne } from "drizzle-orm"; -import { getMoods, render, render404, UserStatus, validateUrl } from "./util.js"; +import { + getMoods, + render, + render404, + UserStatus, + validateUrl +} from "./util.js"; import { PgColumn } from "drizzle-orm/pg-core"; import dayjs from "dayjs"; @@ -84,9 +90,13 @@ export default async function (app: Express, db: NodePgDatabase) { }) .from(journalEntries) .where( - user.id === req.session["uid"] || req.session["status"] & UserStatus.MODERATOR + user.id === req.session["uid"] || + req.session["status"] & UserStatus.MODERATOR ? eq(journalEntries.user, user.id) - : and(eq(journalEntries.user, user.id), ne(journalEntries.visibility, 0)) + : and( + eq(journalEntries.user, user.id), + ne(journalEntries.visibility, 0) + ) ) .orderBy(desc(journalEntries.date)) .limit(5) @@ -139,11 +149,6 @@ export default async function (app: Express, db: NodePgDatabase) { res.redirect("/login"); return; } - if (!validateUrl(req.body.website)) { - req.flash("error", "The website URL provided is invalid or malformed."); - res.redirect(req.get("Referrer") || "/"); - return; - } const { uname } = ( await db .select({ uname: users.name }) @@ -154,20 +159,50 @@ export default async function (app: Express, db: NodePgDatabase) { (uname || "") !== req.session["user"] && !(req.session["status"] & UserStatus.MODERATOR) ) { - res.redirect(req.get("Referrer") || "/"); + render404(db, res, req); return; } - await db - .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"); + if (req.query.param && (req.session["status"] & UserStatus.MODERATOR)) { + switch (req.query.param) { + case "status": + if (!req.query.status) { + req.flash("error", "No status parameter specified."); + res.redirect(req.get("Referrer") || "/"); + return; + } + await db.update(users).set({ + // @ts-expect-error + status: parseInt(req.query.status) + }).where(eq(users.name, req.params.user)); + break; + default: + render404(db, res, req); + return; + } + } else { + if (!validateUrl(req.body.website)) { + req.flash( + "error", + "The website URL provided is invalid or malformed." + ); + res.redirect(req.get("Referrer") || "/"); + return; + } + await db + .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"); + return; + } + req.flash("success", "Updated"); + res.redirect(req.get("Referrer") || "/"); }); app.post("/users/:user/follow", async (req, res) => { if (!req.session["loggedIn"]) { diff --git a/static/js/admin.js b/static/js/admin.js new file mode 100644 index 0000000..798daec --- /dev/null +++ b/static/js/admin.js @@ -0,0 +1,20 @@ +const e_user_selected = document.getElementById("user-selected"); +let current; + +document.querySelectorAll("#users tr").forEach((el) => { + el.addEventListener("click", () => { + current = el.querySelector("td:nth-child(2)").textContent; + e_user_selected.textContent = current; + }); +}); + +document.querySelectorAll("button").forEach((el) => { + el.addEventListener("click", (ev) => { + if (!current) { + ev.preventDefault(); + return; + }; + const e = el.parentElement; + e.setAttribute("action", el.parentElement.dataset.url.replaceAll("{}", current)); + }); +}); diff --git a/views/_feed.pug b/views/_feed.pug deleted file mode 100644 index 46c0b63..0000000 --- a/views/_feed.pug +++ /dev/null @@ -1,14 +0,0 @@ -mixin feed(feed, hideUser) - if feed.length > 0 - #feed - for update of feed - .feed-update - div - a(href=`/users/${update.user}`) - if !hideUser - | #{update.user} - strong= update.mood - div= update.desc || "[no mood description provided]" - div(title=update.date.toLocaleString())= update.relativeDate - else - span [no updates] diff --git a/views/_util.pug b/views/_util.pug index f74e0d4..e8d31c6 100644 --- a/views/_util.pug +++ b/views/_util.pug @@ -1,3 +1,18 @@ +mixin feed(feed, hideUser) + if feed.length > 0 + #feed + for update of feed + .feed-update + div + a(href=`/users/${update.user}`) + if !hideUser + | #{update.user} + strong= update.mood + div= update.desc || "[no mood description provided]" + div(title=update.date.toLocaleString())= update.relativeDate + else + span [no updates] + mixin invite_code_expiration(code) - const timestamp = code.expires.getTime() if timestamp === 0 diff --git a/views/admin.pug b/views/admin.pug index cf2121b..f5e0dae 100644 --- a/views/admin.pug +++ b/views/admin.pug @@ -5,7 +5,10 @@ block content h1 Admin Panel p Don't Be Evil h2 Users - table + p + | Selected: + strong#user-selected [none] + table#users tbody tr th UID @@ -17,7 +20,13 @@ block content td a(href=`/users/${user.uname}`)= user.uname td= user.status.toString(2).padStart(4, "0") - h2 Invite codes + br + form(action="#", method="post", data-url="/users/{}/edit?param=status&status=4") + button#btn-trust Trust + button#btn-ban Ban + form(action="#", method="post", data-url="/users/{}/edit?param=status&status=0") + button#btn-reset Revoke all stati + h2(style="margin-top:1em;") Invite codes p Well Rae. You've made quite a The Closed Beta. form(action="/codes/delete", method="post") table @@ -41,3 +50,4 @@ block content form(action="/codes/create", method="post") input(type="datetime-local", name="expiration") button(type="submit") Create + script(src="/js/admin.js", nonce=nonce) diff --git a/views/dashboard.pug b/views/dashboard.pug index 8bc8911..667b6b4 100644 --- a/views/dashboard.pug +++ b/views/dashboard.pug @@ -39,7 +39,7 @@ block content | / a(href="#invite-codes") Invite codes p This is where you "MIPILIN"! That is all you need to know!!! - p If onlookers notice your actions and inquire about what you are doing, you MUST tell them that you are mipilining all over the place, and then PROMPTLY SCROLL DOWN AND GENERATE AN INVITE CODE SO THAT THEY CAN MIPILIN TOO. If you do not do this I will cry. + p If onlookers notice your actions and inquire about what you are doing, you MUST tell them that you are mipilining all over the place, and then PROMPTLY SCROLL DOWN AND GENERATE AN INVITE CODE SO THAT THEY CAN MIPILIN TOO. form#dashboard-update-form(action="/update/mood", method="post", onsubmit="disable(this);") select(name="mood", required) //- Maybe put the index of the mood in the value of the option element @@ -50,7 +50,6 @@ block content button(type="submit") Update h1#feed(style="margin-top:0.5em;") Feed - include _feed.pug +feed(recentUpdates) h1#invite-codes(style="margin-top:1em;") Invite codes diff --git a/views/index.pug b/views/index.pug index 296f700..1e016d9 100644 --- a/views/index.pug +++ b/views/index.pug @@ -1,4 +1,5 @@ extends site.pug +include _util.pug block head style @@ -46,5 +47,4 @@ block content | . h1 Global Feed p Look at how all these people are doing!!! - include _feed.pug +feed(feedUpdates) diff --git a/views/site.pug b/views/site.pug index 3a58ab7..a83df43 100644 --- a/views/site.pug +++ b/views/site.pug @@ -35,7 +35,7 @@ html(lang="en") | You should log in! It's FUN!! span#ticker-marquee marquee - | The beta is still a thing that is happening! If something fucks up plz let me know! <3 + | The beta is still a thing that is happening! If something fucks up plz let me know! <3 #page block page #content diff --git a/views/user.pug b/views/user.pug index 622b647..7ab33e7 100644 --- a/views/user.pug +++ b/views/user.pug @@ -1,4 +1,5 @@ extends site.pug +include _util.pug //- Display mood here but keep yourself dry (i.e. dont request user mood if the profile being viewed is the profile of the currently logged-in user) block content @@ -47,5 +48,4 @@ block content div [no entries] br h2 Recent mood updates - include _feed.pug +feed(userMoodFeed, true)