mirror of
https://git.sr.ht/~roxwize/mipilin
synced 2025-03-03 17:42:06 +00:00
Today is Journal Day
Signed-off-by: roxwize <rae@roxwize.xyz>
This commit is contained in:
parent
f7e44cddca
commit
927193c102
14 changed files with 742 additions and 55 deletions
|
@ -35,7 +35,8 @@ export const journalEntries = pgTable("journal_entries", {
|
|||
title: varchar({ length: 64 }).default("").notNull(),
|
||||
entry: varchar({ length: 4096 }).default("").notNull(),
|
||||
visibility: integer().default(1).notNull(),
|
||||
date: timestamp().notNull()
|
||||
date: timestamp().notNull(),
|
||||
updated: timestamp()
|
||||
});
|
||||
|
||||
export const journalComments = pgTable("journal_comments", {
|
||||
|
|
1
drizzle/0004_lyrical_photon.sql
Normal file
1
drizzle/0004_lyrical_photon.sql
Normal file
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "journal_entries" ADD COLUMN "updated" timestamp;
|
502
drizzle/meta/0004_snapshot.json
Normal file
502
drizzle/meta/0004_snapshot.json
Normal file
|
@ -0,0 +1,502 @@
|
|||
{
|
||||
"id": "5131d53f-2980-420b-889d-999a3ab9fa3e",
|
||||
"prevId": "0c1bcfed-899c-4ec9-9a7d-c987aa50dfb8",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
"public.follows": {
|
||||
"name": "follows",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"follower_id": {
|
||||
"name": "follower_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"follows_user_id_users_id_fk": {
|
||||
"name": "follows_user_id_users_id_fk",
|
||||
"tableFrom": "follows",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"follows_follower_id_users_id_fk": {
|
||||
"name": "follows_follower_id_users_id_fk",
|
||||
"tableFrom": "follows",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"follower_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"follows_user_id_follower_id_pk": {
|
||||
"name": "follows_user_id_follower_id_pk",
|
||||
"columns": [
|
||||
"user_id",
|
||||
"follower_id"
|
||||
]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.invite_codes": {
|
||||
"name": "invite_codes",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"token": {
|
||||
"name": "token",
|
||||
"type": "varchar(22)",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"granted": {
|
||||
"name": "granted",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"expires": {
|
||||
"name": "expires",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "'1970-01-01 00:00:00.000'"
|
||||
},
|
||||
"confers": {
|
||||
"name": "confers",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"invite_codes_user_id_users_id_fk": {
|
||||
"name": "invite_codes_user_id_users_id_fk",
|
||||
"tableFrom": "invite_codes",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.journal_comments": {
|
||||
"name": "journal_comments",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"identity": {
|
||||
"type": "always",
|
||||
"name": "journal_comments_id_seq",
|
||||
"schema": "public",
|
||||
"increment": "1",
|
||||
"startWith": "1",
|
||||
"minValue": "1",
|
||||
"maxValue": "2147483647",
|
||||
"cache": "1",
|
||||
"cycle": false
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"name": "user",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"entry": {
|
||||
"name": "entry",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"content": {
|
||||
"name": "content",
|
||||
"type": "varchar(512)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"date": {
|
||||
"name": "date",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"journal_comments_user_users_id_fk": {
|
||||
"name": "journal_comments_user_users_id_fk",
|
||||
"tableFrom": "journal_comments",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"journal_comments_entry_journal_entries_id_fk": {
|
||||
"name": "journal_comments_entry_journal_entries_id_fk",
|
||||
"tableFrom": "journal_comments",
|
||||
"tableTo": "journal_entries",
|
||||
"columnsFrom": [
|
||||
"entry"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.journal_entries": {
|
||||
"name": "journal_entries",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"identity": {
|
||||
"type": "always",
|
||||
"name": "journal_entries_id_seq",
|
||||
"schema": "public",
|
||||
"increment": "1",
|
||||
"startWith": "1",
|
||||
"minValue": "1",
|
||||
"maxValue": "2147483647",
|
||||
"cache": "1",
|
||||
"cycle": false
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"name": "user",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"mood-change": {
|
||||
"name": "mood-change",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"title": {
|
||||
"name": "title",
|
||||
"type": "varchar(64)",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"entry": {
|
||||
"name": "entry",
|
||||
"type": "varchar(4096)",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"visibility": {
|
||||
"name": "visibility",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 1
|
||||
},
|
||||
"date": {
|
||||
"name": "date",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"updated": {
|
||||
"name": "updated",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"journal_entries_user_users_id_fk": {
|
||||
"name": "journal_entries_user_users_id_fk",
|
||||
"tableFrom": "journal_entries",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.profiles": {
|
||||
"name": "profiles",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"user": {
|
||||
"name": "user",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"bio": {
|
||||
"name": "bio",
|
||||
"type": "varchar(1024)",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"website": {
|
||||
"name": "website",
|
||||
"type": "varchar",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"profiles_user_users_id_fk": {
|
||||
"name": "profiles_user_users_id_fk",
|
||||
"tableFrom": "profiles",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.updates": {
|
||||
"name": "updates",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"identity": {
|
||||
"type": "always",
|
||||
"name": "updates_id_seq",
|
||||
"schema": "public",
|
||||
"increment": "1",
|
||||
"startWith": "1",
|
||||
"minValue": "1",
|
||||
"maxValue": "2147483647",
|
||||
"cache": "1",
|
||||
"cycle": false
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"name": "user",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"mood": {
|
||||
"name": "mood",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "varchar(512)",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"date": {
|
||||
"name": "date",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"updates_user_users_id_fk": {
|
||||
"name": "updates_user_users_id_fk",
|
||||
"tableFrom": "updates",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.users": {
|
||||
"name": "users",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"identity": {
|
||||
"type": "always",
|
||||
"name": "users_id_seq",
|
||||
"schema": "public",
|
||||
"increment": "1",
|
||||
"startWith": "1",
|
||||
"minValue": "1",
|
||||
"maxValue": "2147483647",
|
||||
"cache": "1",
|
||||
"cycle": false
|
||||
}
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "varchar",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "varchar(26)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"pass": {
|
||||
"name": "pass",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"registered": {
|
||||
"name": "registered",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"users_email_unique": {
|
||||
"name": "users_email_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"email"
|
||||
]
|
||||
},
|
||||
"users_name_unique": {
|
||||
"name": "users_name_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"name"
|
||||
]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
}
|
||||
},
|
||||
"enums": {},
|
||||
"schemas": {},
|
||||
"sequences": {},
|
||||
"roles": {},
|
||||
"policies": {},
|
||||
"views": {},
|
||||
"_meta": {
|
||||
"columns": {},
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
|
@ -29,6 +29,13 @@
|
|||
"when": 1737088748932,
|
||||
"tag": "0003_closed_alex_power",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 4,
|
||||
"version": "7",
|
||||
"when": 1740852098874,
|
||||
"tag": "0004_lyrical_photon",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -8,7 +8,7 @@ import {
|
|||
updates,
|
||||
users
|
||||
} from "../db/schema.js";
|
||||
import { and, count, desc, eq, sql } from "drizzle-orm";
|
||||
import { and, count, desc, eq, ne, sql } from "drizzle-orm";
|
||||
import dayjs from "dayjs";
|
||||
import {
|
||||
confirm,
|
||||
|
@ -83,6 +83,47 @@ export default async function (app: Express, db: NodePgDatabase) {
|
|||
};
|
||||
});
|
||||
|
||||
// recent journal entries
|
||||
const recentJournalUpdates = (
|
||||
await db
|
||||
.select({
|
||||
id: journalEntries.id,
|
||||
user: users.name,
|
||||
title: journalEntries.title,
|
||||
date: journalEntries.date,
|
||||
visibility: journalEntries.visibility
|
||||
})
|
||||
.from(journalEntries)
|
||||
.where(
|
||||
users.id === req.session["uid"] ||
|
||||
req.session["status"] & UserStatus.MODERATOR
|
||||
? eq(journalEntries.user, users.id)
|
||||
: and(
|
||||
eq(journalEntries.user, users.id),
|
||||
ne(journalEntries.visibility, 0)
|
||||
)
|
||||
)
|
||||
.innerJoin(
|
||||
follows,
|
||||
and(
|
||||
eq(follows.userId, journalEntries.user),
|
||||
eq(follows.followerId, req.session["uid"])
|
||||
)
|
||||
)
|
||||
.leftJoin(users, eq(journalEntries.user, users.id))
|
||||
.orderBy(desc(journalEntries.date))
|
||||
.limit(9)
|
||||
).map((e) => {
|
||||
return {
|
||||
id: e.id,
|
||||
user: e.user,
|
||||
title: e.title,
|
||||
date: e.date,
|
||||
visibility: e.visibility,
|
||||
relativeDate: now.to(e.date)
|
||||
};
|
||||
});
|
||||
|
||||
// user invite codes
|
||||
const codes = (
|
||||
await db
|
||||
|
@ -126,10 +167,13 @@ export default async function (app: Express, db: NodePgDatabase) {
|
|||
moodsSorted,
|
||||
moodHistory,
|
||||
recentUpdates,
|
||||
recentJournalUpdates,
|
||||
codes,
|
||||
codesUsed,
|
||||
followed,
|
||||
isTrusted: req.session["status"] & (UserStatus.MODERATOR | UserStatus.TRUSTED),
|
||||
isTrusted:
|
||||
req.session["status"] &
|
||||
(UserStatus.MODERATOR | UserStatus.TRUSTED),
|
||||
feed: []
|
||||
});
|
||||
});
|
||||
|
@ -140,9 +184,19 @@ export default async function (app: Express, db: NodePgDatabase) {
|
|||
}
|
||||
// make sure the user isnt updating too fast
|
||||
//! TODO: also do this for journal entries
|
||||
const lastUpdate = (await db.select({ date: updates.date }).from(updates).where(eq(updates.user, req.session["uid"])).orderBy(desc(updates.date)).limit(1))?.[0];
|
||||
const lastUpdate = (
|
||||
await db
|
||||
.select({ date: updates.date })
|
||||
.from(updates)
|
||||
.where(eq(updates.user, req.session["uid"]))
|
||||
.orderBy(desc(updates.date))
|
||||
.limit(1)
|
||||
)?.[0];
|
||||
if (Date.now() < lastUpdate?.date?.getTime() + 10 * 1000) {
|
||||
req.flash("error", "You're updating your mood too fast! Wait ten seconds between updates.");
|
||||
req.flash(
|
||||
"error",
|
||||
"You're updating your mood too fast! Wait ten seconds between updates."
|
||||
);
|
||||
res.redirect(req.get("Referrer") || "/");
|
||||
return;
|
||||
}
|
||||
|
@ -183,8 +237,18 @@ export default async function (app: Express, db: NodePgDatabase) {
|
|||
return;
|
||||
}
|
||||
|
||||
const { user } = (await db.select({user: updates.user}).from(updates).where(eq(updates.id, u)).limit(1))[0];
|
||||
if (!user || (user !== req.session["uid"] && !(req.session["status"] & UserStatus.MODERATOR))) {
|
||||
const { user } = (
|
||||
await db
|
||||
.select({ user: updates.user })
|
||||
.from(updates)
|
||||
.where(eq(updates.id, u))
|
||||
.limit(1)
|
||||
)[0];
|
||||
if (
|
||||
!user ||
|
||||
(user !== req.session["uid"] &&
|
||||
!(req.session["status"] & UserStatus.MODERATOR))
|
||||
) {
|
||||
render404(db, res, req);
|
||||
return;
|
||||
}
|
||||
|
@ -222,6 +286,7 @@ export default async function (app: Express, db: NodePgDatabase) {
|
|||
moodString?: string;
|
||||
date: Date;
|
||||
visibility: number;
|
||||
updated: Date;
|
||||
} = (
|
||||
await db
|
||||
.select({
|
||||
|
@ -232,7 +297,8 @@ export default async function (app: Express, db: NodePgDatabase) {
|
|||
content: journalEntries.entry,
|
||||
moodChange: journalEntries.moodChange,
|
||||
date: journalEntries.date,
|
||||
visibility: journalEntries.visibility
|
||||
visibility: journalEntries.visibility,
|
||||
updated: journalEntries.updated
|
||||
})
|
||||
.from(journalEntries)
|
||||
.where(eq(journalEntries.id, id))
|
||||
|
@ -263,10 +329,12 @@ export default async function (app: Express, db: NodePgDatabase) {
|
|||
: entry.content;
|
||||
|
||||
const entryTimestamp = dayjs(entry.date).fromNow();
|
||||
const updatedTimestamp = dayjs(entry.updated).fromNow();
|
||||
const isSelf = entry.uid === req.session["uid"];
|
||||
render(db, "journal_view", entry.title, res, req, {
|
||||
entry,
|
||||
entryTimestamp,
|
||||
updatedTimestamp,
|
||||
isSelf,
|
||||
isMod
|
||||
});
|
||||
|
@ -282,7 +350,11 @@ export default async function (app: Express, db: NodePgDatabase) {
|
|||
const entry = (
|
||||
await db
|
||||
.select({
|
||||
uid: journalEntries.user
|
||||
uid: journalEntries.user,
|
||||
title: journalEntries.title,
|
||||
entry: journalEntries.entry,
|
||||
visibility: journalEntries.visibility,
|
||||
mood: journalEntries.moodChange
|
||||
})
|
||||
.from(journalEntries)
|
||||
.where(eq(journalEntries.id, id))
|
||||
|
@ -308,7 +380,62 @@ export default async function (app: Express, db: NodePgDatabase) {
|
|||
}
|
||||
|
||||
if (req.body.action === "edit") {
|
||||
// TODO!!
|
||||
if (
|
||||
req.body.title ||
|
||||
req.body.description ||
|
||||
req.body.moodDelta ||
|
||||
req.body.visiblity
|
||||
) {
|
||||
if (!req.session["loggedIn"]) {
|
||||
res.redirect("/login");
|
||||
return;
|
||||
}
|
||||
if (req.body.title.length > 64) {
|
||||
req.flash("error", "Title too long!");
|
||||
res.redirect("/journal");
|
||||
return;
|
||||
}
|
||||
if (req.body.description.length > 4096) {
|
||||
req.flash("error", "Entry too long!");
|
||||
res.redirect("/journal");
|
||||
return;
|
||||
}
|
||||
|
||||
const moodChange = parseInt(req.body.moodDelta);
|
||||
const visibility = parseInt(req.body.visibility);
|
||||
if (isNaN(moodChange) || isNaN(visibility)) {
|
||||
req.flash(
|
||||
"error",
|
||||
"One of the values was improperly specified."
|
||||
);
|
||||
res.redirect(`/journal/${req.params.id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
await db
|
||||
.update(journalEntries)
|
||||
.set({
|
||||
//@ts-expect-error
|
||||
title: req.body.title,
|
||||
entry: req.body.description
|
||||
.replaceAll("&", "&")
|
||||
.replaceAll("<", "<")
|
||||
.replaceAll(">", ">")
|
||||
.replaceAll("\n", "<br>"),
|
||||
moodChange: req.body.moodDelta,
|
||||
visibility: req.body.visibility,
|
||||
updated: new Date(Date.now())
|
||||
})
|
||||
.where(eq(journalEntries.id, id));
|
||||
|
||||
res.redirect(`/journal/${req.params.id}`);
|
||||
return;
|
||||
}
|
||||
render(db, "journal", `edit ${entry.title}`, res, req, {
|
||||
entry,
|
||||
id,
|
||||
edit: true
|
||||
});
|
||||
} else if (req.body.action === "delete") {
|
||||
if (!confirm(db, res, req, `/journal/${req.params.id}`)) {
|
||||
return;
|
||||
|
|
|
@ -76,3 +76,26 @@ input.ovm-input:checked+label > img {
|
|||
label.ovm-input:last-child > img {
|
||||
border-right-width: 1px;
|
||||
}
|
||||
|
||||
.feed-journal-entries {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
/* list-style: none;
|
||||
padding-inline: 0;
|
||||
column-count: 3;
|
||||
margin-top: 0; */
|
||||
}
|
||||
|
||||
.feed-journal-entry {
|
||||
margin: 4px 0;
|
||||
padding: 8px;
|
||||
break-inside: avoid-column;
|
||||
}
|
||||
|
||||
.feed-journal-entry:nth-child(6n+4), .feed-journal-entry:nth-child(6n+5), .feed-journal-entry:nth-child(6n+6) {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.feed-journal-entry:hover {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
|
|
@ -247,6 +247,10 @@ tr:hover td {
|
|||
width: 66ch;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-color: rgba(0, 0, 0, 0.3)
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Gohufont 14";
|
||||
src: url("/fonts/gohufont-14.ttf") format("truetype"),
|
||||
|
|
|
@ -17,7 +17,7 @@ mixin feed(feed, hideUser)
|
|||
button.button-link(title="Delete this update") x
|
||||
.feed-update-date(title=update.date.toLocaleString())= update.relativeDate
|
||||
else
|
||||
span [no updates]
|
||||
span [no mood updates]
|
||||
|
||||
mixin invite_code_expiration(code)
|
||||
- const timestamp = code.expires.getTime()
|
||||
|
@ -27,3 +27,37 @@ mixin invite_code_expiration(code)
|
|||
td.error EXPIRED
|
||||
else
|
||||
td= code.expiresString
|
||||
|
||||
mixin journal_entry_suffix(entry)
|
||||
span.subtle(title=entry.date.toLocaleString())
|
||||
| (#{entry.relativeDate}
|
||||
if entry.visibility !== 1
|
||||
| ,
|
||||
if entry.visibility === 0
|
||||
| private
|
||||
if entry.visibility === 2
|
||||
| mood-only
|
||||
| )
|
||||
|
||||
mixin ovm(entry)
|
||||
- const e = entry?.mood
|
||||
#ovm
|
||||
input.ovm-input(type="radio", name="moodDelta", id="moodDelta-mb", value="2", required checked=(e === 2))
|
||||
label.ovm-input(for="moodDelta-mb", title="Much better")
|
||||
img(src="/img/upup.svg", alt="Much better")
|
||||
|
||||
input.ovm-input(type="radio", name="moodDelta", id="moodDelta-b", value="1", required checked=(e === 1))
|
||||
label.ovm-input(for="moodDelta-b", title="Better")
|
||||
img(src="/img/up.svg", alt="Better")
|
||||
|
||||
input.ovm-input(type="radio", name="moodDelta", id="moodDelta-nc", value="0", required checked=(!entry || e === 0))
|
||||
label.ovm-input(for="moodDelta-nc", title="About the same")
|
||||
img(src="/img/line.svg", alt="About the same")
|
||||
|
||||
input.ovm-input(type="radio", name="moodDelta", id="moodDelta-w", value="-1", required checked=(e === -1))
|
||||
label.ovm-input(for="moodDelta-w", title="Worse")
|
||||
img(src="/img/down.svg", alt="Worse")
|
||||
|
||||
input.ovm-input(type="radio", name="moodDelta", id="moodDelta-mw", value="-2", required checked=(e === -2))
|
||||
label.ovm-input(for="moodDelta-mw", title="Much worse")
|
||||
img(src="/img/downdown.svg", alt="Much worse")
|
||||
|
|
|
@ -48,6 +48,13 @@ block content
|
|||
button(type="submit") Update
|
||||
|
||||
h1#feed(style="margin-top:0.5em;") Feed
|
||||
if recentJournalUpdates.length > 0
|
||||
.feed-journal-entries
|
||||
for entry of recentJournalUpdates
|
||||
.feed-journal-entry
|
||||
a(href=`/journal/${entry.id}`)= entry.title
|
||||
+journal_entry_suffix(entry, session.user === entry.user)
|
||||
hr
|
||||
+feed(recentUpdates)
|
||||
|
||||
h1#invite-codes(style="margin-top:1em;") Invite codes
|
||||
|
|
|
@ -1,52 +1,43 @@
|
|||
extends site.pug
|
||||
include _util.pug
|
||||
|
||||
block head
|
||||
link(rel="stylesheet", href="/css/dashboard.css")
|
||||
script(type="module", src="https://cdn.jsdelivr.net/npm/chart.js@4.4.6/dist/chart.umd.min.js", nonce=nonce)
|
||||
|
||||
block content
|
||||
h1 Your Journal
|
||||
p This is where you can log your overall mood every day, and get a glimpse at how your life is going so far!
|
||||
p In the near future there will be a magnificient graph that will let you visualize your past entries and your mood trends. You must tay stuned.
|
||||
form#journal-update(action="/journal/update", method="post")
|
||||
if edit
|
||||
h1 Edit #{entry.title}
|
||||
else
|
||||
h1 Your Journal
|
||||
p This is where you can log your overall mood every day, and get a glimpse at how your life is going so far!
|
||||
p In the near future there will be a magnificient graph that will let you visualize your past entries and your mood trends. You must tay stuned.
|
||||
|
||||
form#journal-update(action=edit ? `/journal/${id}/edit` : "/journal/update", method="post")
|
||||
if edit
|
||||
input(type="hidden", name="action", value="edit", readonly)
|
||||
.input
|
||||
span Overall mood change (how do you feel compared to yesterday?)
|
||||
#ovm
|
||||
input.ovm-input(type="radio", name="moodDelta", id="moodDelta-mb", value="2", required)
|
||||
label.ovm-input(for="moodDelta-mb", title="Much better")
|
||||
img(src="/img/upup.svg", alt="Much better")
|
||||
|
||||
input.ovm-input(type="radio", name="moodDelta", id="moodDelta-b", value="1", required)
|
||||
label.ovm-input(for="moodDelta-b", title="Better")
|
||||
img(src="/img/up.svg", alt="Better")
|
||||
|
||||
input.ovm-input(type="radio", name="moodDelta", id="moodDelta-nc", value="0", required checked)
|
||||
label.ovm-input(for="moodDelta-nc", title="About the same")
|
||||
img(src="/img/line.svg", alt="About the same")
|
||||
|
||||
input.ovm-input(type="radio", name="moodDelta", id="moodDelta-w", value="-1", required)
|
||||
label.ovm-input(for="moodDelta-w", title="Worse")
|
||||
img(src="/img/down.svg", alt="Worse")
|
||||
|
||||
input.ovm-input(type="radio", name="moodDelta", id="moodDelta-mw", value="-2", required)
|
||||
label.ovm-input(for="moodDelta-mw", title="Much worse")
|
||||
img(src="/img/downdown.svg", alt="Much worse")
|
||||
+ovm(entry)
|
||||
.input
|
||||
label(for="title") Title
|
||||
input(type="text", name="title", id="title", placeholder="max 64 chars", maxlength="64")
|
||||
input(type="text", name="title", id="title", placeholder="max 64 chars", maxlength="64", value=edit ? entry.title : "")
|
||||
.input
|
||||
label(for="description") Journal entry for today
|
||||
textarea(name="description", id="description", placeholder="max 4096 chars", maxlength="4096", cols="60", rows="12")
|
||||
if edit
|
||||
| #{entry.entry}
|
||||
.input
|
||||
span Visibility
|
||||
- const v = entry?.visibility ?? 1
|
||||
div#visibility-control
|
||||
input(type="radio", name="visibility", id="visibility-public", value="1", checked)
|
||||
input(type="radio", name="visibility", id="visibility-public", value="1", checked=(v === 1))
|
||||
label(for="visibility-public") Public
|
||||
br
|
||||
input(type="radio", name="visibility", id="visibility-private", value="0")
|
||||
input(type="radio", name="visibility", id="visibility-private", value="0", checked=(v === 0))
|
||||
label(for="visibility-private") Private
|
||||
br
|
||||
input(type="radio", name="visibility", id="visibility-moodChange-only", value="2")
|
||||
input(type="radio", name="visibility", id="visibility-moodChange-only", value="2", checked=(v === 2))
|
||||
label(for="visibility-moodChange-only") Mood only
|
||||
|
||||
button(type="submit") Submit
|
||||
button(type="submit")= edit ? "Edit" : "Submit"
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
extends site.pug
|
||||
|
||||
block content
|
||||
p God i fucking hate myself
|
||||
textarea(name="description", id="description", placeholder="max 4096 chars", maxlength="4096", cols="60", rows="12")
|
|
@ -14,10 +14,13 @@ block content
|
|||
a(href=`/users/${entry.uname}`)= entry.uname
|
||||
|
|
||||
span(title=entry.date.toLocaleString()) #{entryTimestamp}
|
||||
if entry.updated
|
||||
span(title=entry.updated.toLocaleString()) (last updated #{updatedTimestamp})
|
||||
br
|
||||
br
|
||||
div
|
||||
| Mood:
|
||||
strong= entry.moodString
|
||||
br
|
||||
//- I dont know why i made this unsafe but its probably for some markdown thing i was planning on doing
|
||||
div!= entry.content
|
||||
|
|
|
@ -39,7 +39,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
|
||||
| 01 03 25: A word from Rae Mipilin herself: Listen to Patricia Taxxon PLEASE / The beta is still a thing that is happening! If something fucks up plz let me know! <3
|
||||
#page
|
||||
block page
|
||||
#content
|
||||
|
|
|
@ -35,15 +35,7 @@ block content
|
|||
for entry of userJournalEntries
|
||||
li
|
||||
a(href=`/journal/${entry.id}`)= entry.title
|
||||
span.subtle(title=entry.date.toLocaleString())
|
||||
| (#{entry.relativeDate}
|
||||
if entry.visibility !== 1
|
||||
| ,
|
||||
if entry.visibility === 0
|
||||
| private
|
||||
if entry.visibility === 2
|
||||
| mood-only
|
||||
| )
|
||||
+journal_entry_suffix(entry)
|
||||
else
|
||||
div [no entries]
|
||||
br
|
||||
|
|
Loading…
Add table
Reference in a new issue