mirror of
https://git.sr.ht/~roxwize/mipilin
synced 2025-01-31 02:53:36 +00:00
admining
Signed-off-by: roxwize <rae@roxwize.xyz>
This commit is contained in:
parent
65c29b0564
commit
ccc894dc33
10 changed files with 111 additions and 41 deletions
7
main.ts
7
main.ts
|
@ -59,7 +59,12 @@ object-src 'none'; base-uri 'none';"
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
app.use((req, res, 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();
|
return next();
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,13 @@ import {
|
||||||
users
|
users
|
||||||
} from "../db/schema.js";
|
} from "../db/schema.js";
|
||||||
import { and, desc, eq, ne } from "drizzle-orm";
|
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 { PgColumn } from "drizzle-orm/pg-core";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
@ -84,9 +90,13 @@ export default async function (app: Express, db: NodePgDatabase) {
|
||||||
})
|
})
|
||||||
.from(journalEntries)
|
.from(journalEntries)
|
||||||
.where(
|
.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)
|
? 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))
|
.orderBy(desc(journalEntries.date))
|
||||||
.limit(5)
|
.limit(5)
|
||||||
|
@ -139,11 +149,6 @@ export default async function (app: Express, db: NodePgDatabase) {
|
||||||
res.redirect("/login");
|
res.redirect("/login");
|
||||||
return;
|
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 } = (
|
const { uname } = (
|
||||||
await db
|
await db
|
||||||
.select({ uname: users.name })
|
.select({ uname: users.name })
|
||||||
|
@ -154,20 +159,50 @@ export default async function (app: Express, db: NodePgDatabase) {
|
||||||
(uname || "") !== req.session["user"] &&
|
(uname || "") !== req.session["user"] &&
|
||||||
!(req.session["status"] & UserStatus.MODERATOR)
|
!(req.session["status"] & UserStatus.MODERATOR)
|
||||||
) {
|
) {
|
||||||
res.redirect(req.get("Referrer") || "/");
|
render404(db, res, req);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await db
|
if (req.query.param && (req.session["status"] & UserStatus.MODERATOR)) {
|
||||||
.update(profiles)
|
switch (req.query.param) {
|
||||||
.set({
|
case "status":
|
||||||
// @ts-expect-error
|
if (!req.query.status) {
|
||||||
bio: req.body.bio,
|
req.flash("error", "No status parameter specified.");
|
||||||
website: req.body.website
|
res.redirect(req.get("Referrer") || "/");
|
||||||
})
|
return;
|
||||||
.where(eq(profiles.user, req.session["uid"]));
|
}
|
||||||
req.flash("success", "Profile updated!");
|
await db.update(users).set({
|
||||||
res.redirect("/dashboard");
|
// @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) => {
|
app.post("/users/:user/follow", async (req, res) => {
|
||||||
if (!req.session["loggedIn"]) {
|
if (!req.session["loggedIn"]) {
|
||||||
|
|
20
static/js/admin.js
Normal file
20
static/js/admin.js
Normal file
|
@ -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));
|
||||||
|
});
|
||||||
|
});
|
|
@ -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]
|
|
|
@ -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)
|
mixin invite_code_expiration(code)
|
||||||
- const timestamp = code.expires.getTime()
|
- const timestamp = code.expires.getTime()
|
||||||
if timestamp === 0
|
if timestamp === 0
|
||||||
|
|
|
@ -5,7 +5,10 @@ block content
|
||||||
h1 Admin Panel
|
h1 Admin Panel
|
||||||
p Don't Be Evil
|
p Don't Be Evil
|
||||||
h2 Users
|
h2 Users
|
||||||
table
|
p
|
||||||
|
| Selected:
|
||||||
|
strong#user-selected [none]
|
||||||
|
table#users
|
||||||
tbody
|
tbody
|
||||||
tr
|
tr
|
||||||
th UID
|
th UID
|
||||||
|
@ -17,7 +20,13 @@ block content
|
||||||
td
|
td
|
||||||
a(href=`/users/${user.uname}`)= user.uname
|
a(href=`/users/${user.uname}`)= user.uname
|
||||||
td= user.status.toString(2).padStart(4, "0")
|
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.
|
p Well Rae. You've made quite a The Closed Beta.
|
||||||
form(action="/codes/delete", method="post")
|
form(action="/codes/delete", method="post")
|
||||||
table
|
table
|
||||||
|
@ -41,3 +50,4 @@ block content
|
||||||
form(action="/codes/create", method="post")
|
form(action="/codes/create", method="post")
|
||||||
input(type="datetime-local", name="expiration")
|
input(type="datetime-local", name="expiration")
|
||||||
button(type="submit") Create
|
button(type="submit") Create
|
||||||
|
script(src="/js/admin.js", nonce=nonce)
|
||||||
|
|
|
@ -39,7 +39,7 @@ block content
|
||||||
| /
|
| /
|
||||||
a(href="#invite-codes") Invite codes
|
a(href="#invite-codes") Invite codes
|
||||||
p This is where you "MIPILIN"! That is all you need to know!!!
|
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);")
|
form#dashboard-update-form(action="/update/mood", method="post", onsubmit="disable(this);")
|
||||||
select(name="mood", required)
|
select(name="mood", required)
|
||||||
//- Maybe put the index of the mood in the value of the option element
|
//- Maybe put the index of the mood in the value of the option element
|
||||||
|
@ -50,7 +50,6 @@ block content
|
||||||
button(type="submit") Update
|
button(type="submit") Update
|
||||||
|
|
||||||
h1#feed(style="margin-top:0.5em;") Feed
|
h1#feed(style="margin-top:0.5em;") Feed
|
||||||
include _feed.pug
|
|
||||||
+feed(recentUpdates)
|
+feed(recentUpdates)
|
||||||
|
|
||||||
h1#invite-codes(style="margin-top:1em;") Invite codes
|
h1#invite-codes(style="margin-top:1em;") Invite codes
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
extends site.pug
|
extends site.pug
|
||||||
|
include _util.pug
|
||||||
|
|
||||||
block head
|
block head
|
||||||
style
|
style
|
||||||
|
@ -46,5 +47,4 @@ block content
|
||||||
| .
|
| .
|
||||||
h1 Global Feed
|
h1 Global Feed
|
||||||
p Look at how all these people are doing!!!
|
p Look at how all these people are doing!!!
|
||||||
include _feed.pug
|
|
||||||
+feed(feedUpdates)
|
+feed(feedUpdates)
|
||||||
|
|
|
@ -35,7 +35,7 @@ html(lang="en")
|
||||||
| You should log in! It's FUN!!
|
| You should log in! It's FUN!!
|
||||||
span#ticker-marquee
|
span#ticker-marquee
|
||||||
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
|
#page
|
||||||
block page
|
block page
|
||||||
#content
|
#content
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
extends site.pug
|
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)
|
//- 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
|
block content
|
||||||
|
@ -47,5 +48,4 @@ block content
|
||||||
div [no entries]
|
div [no entries]
|
||||||
br
|
br
|
||||||
h2 Recent mood updates
|
h2 Recent mood updates
|
||||||
include _feed.pug
|
|
||||||
+feed(userMoodFeed, true)
|
+feed(userMoodFeed, true)
|
||||||
|
|
Loading…
Reference in a new issue