mirror of
https://git.sr.ht/~roxwize/mipilin
synced 2025-03-04 01:52:05 +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(),
|
title: varchar({ length: 64 }).default("").notNull(),
|
||||||
entry: varchar({ length: 4096 }).default("").notNull(),
|
entry: varchar({ length: 4096 }).default("").notNull(),
|
||||||
visibility: integer().default(1).notNull(),
|
visibility: integer().default(1).notNull(),
|
||||||
date: timestamp().notNull()
|
date: timestamp().notNull(),
|
||||||
|
updated: timestamp()
|
||||||
});
|
});
|
||||||
|
|
||||||
export const journalComments = pgTable("journal_comments", {
|
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,
|
"when": 1737088748932,
|
||||||
"tag": "0003_closed_alex_power",
|
"tag": "0003_closed_alex_power",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 4,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1740852098874,
|
||||||
|
"tag": "0004_lyrical_photon",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -8,7 +8,7 @@ import {
|
||||||
updates,
|
updates,
|
||||||
users
|
users
|
||||||
} from "../db/schema.js";
|
} 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 dayjs from "dayjs";
|
||||||
import {
|
import {
|
||||||
confirm,
|
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
|
// user invite codes
|
||||||
const codes = (
|
const codes = (
|
||||||
await db
|
await db
|
||||||
|
@ -126,10 +167,13 @@ export default async function (app: Express, db: NodePgDatabase) {
|
||||||
moodsSorted,
|
moodsSorted,
|
||||||
moodHistory,
|
moodHistory,
|
||||||
recentUpdates,
|
recentUpdates,
|
||||||
|
recentJournalUpdates,
|
||||||
codes,
|
codes,
|
||||||
codesUsed,
|
codesUsed,
|
||||||
followed,
|
followed,
|
||||||
isTrusted: req.session["status"] & (UserStatus.MODERATOR | UserStatus.TRUSTED),
|
isTrusted:
|
||||||
|
req.session["status"] &
|
||||||
|
(UserStatus.MODERATOR | UserStatus.TRUSTED),
|
||||||
feed: []
|
feed: []
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -140,9 +184,19 @@ export default async function (app: Express, db: NodePgDatabase) {
|
||||||
}
|
}
|
||||||
// make sure the user isnt updating too fast
|
// make sure the user isnt updating too fast
|
||||||
//! TODO: also do this for journal entries
|
//! 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) {
|
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") || "/");
|
res.redirect(req.get("Referrer") || "/");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -183,8 +237,18 @@ export default async function (app: Express, db: NodePgDatabase) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user } = (await db.select({user: updates.user}).from(updates).where(eq(updates.id, u)).limit(1))[0];
|
const { user } = (
|
||||||
if (!user || (user !== req.session["uid"] && !(req.session["status"] & UserStatus.MODERATOR))) {
|
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);
|
render404(db, res, req);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -222,6 +286,7 @@ export default async function (app: Express, db: NodePgDatabase) {
|
||||||
moodString?: string;
|
moodString?: string;
|
||||||
date: Date;
|
date: Date;
|
||||||
visibility: number;
|
visibility: number;
|
||||||
|
updated: Date;
|
||||||
} = (
|
} = (
|
||||||
await db
|
await db
|
||||||
.select({
|
.select({
|
||||||
|
@ -232,7 +297,8 @@ export default async function (app: Express, db: NodePgDatabase) {
|
||||||
content: journalEntries.entry,
|
content: journalEntries.entry,
|
||||||
moodChange: journalEntries.moodChange,
|
moodChange: journalEntries.moodChange,
|
||||||
date: journalEntries.date,
|
date: journalEntries.date,
|
||||||
visibility: journalEntries.visibility
|
visibility: journalEntries.visibility,
|
||||||
|
updated: journalEntries.updated
|
||||||
})
|
})
|
||||||
.from(journalEntries)
|
.from(journalEntries)
|
||||||
.where(eq(journalEntries.id, id))
|
.where(eq(journalEntries.id, id))
|
||||||
|
@ -263,10 +329,12 @@ export default async function (app: Express, db: NodePgDatabase) {
|
||||||
: entry.content;
|
: entry.content;
|
||||||
|
|
||||||
const entryTimestamp = dayjs(entry.date).fromNow();
|
const entryTimestamp = dayjs(entry.date).fromNow();
|
||||||
|
const updatedTimestamp = dayjs(entry.updated).fromNow();
|
||||||
const isSelf = entry.uid === req.session["uid"];
|
const isSelf = entry.uid === req.session["uid"];
|
||||||
render(db, "journal_view", entry.title, res, req, {
|
render(db, "journal_view", entry.title, res, req, {
|
||||||
entry,
|
entry,
|
||||||
entryTimestamp,
|
entryTimestamp,
|
||||||
|
updatedTimestamp,
|
||||||
isSelf,
|
isSelf,
|
||||||
isMod
|
isMod
|
||||||
});
|
});
|
||||||
|
@ -282,7 +350,11 @@ export default async function (app: Express, db: NodePgDatabase) {
|
||||||
const entry = (
|
const entry = (
|
||||||
await db
|
await db
|
||||||
.select({
|
.select({
|
||||||
uid: journalEntries.user
|
uid: journalEntries.user,
|
||||||
|
title: journalEntries.title,
|
||||||
|
entry: journalEntries.entry,
|
||||||
|
visibility: journalEntries.visibility,
|
||||||
|
mood: journalEntries.moodChange
|
||||||
})
|
})
|
||||||
.from(journalEntries)
|
.from(journalEntries)
|
||||||
.where(eq(journalEntries.id, id))
|
.where(eq(journalEntries.id, id))
|
||||||
|
@ -308,7 +380,62 @@ export default async function (app: Express, db: NodePgDatabase) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.body.action === "edit") {
|
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") {
|
} else if (req.body.action === "delete") {
|
||||||
if (!confirm(db, res, req, `/journal/${req.params.id}`)) {
|
if (!confirm(db, res, req, `/journal/${req.params.id}`)) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -76,3 +76,26 @@ input.ovm-input:checked+label > img {
|
||||||
label.ovm-input:last-child > img {
|
label.ovm-input:last-child > img {
|
||||||
border-right-width: 1px;
|
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;
|
width: 66ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border-color: rgba(0, 0, 0, 0.3)
|
||||||
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Gohufont 14";
|
font-family: "Gohufont 14";
|
||||||
src: url("/fonts/gohufont-14.ttf") format("truetype"),
|
src: url("/fonts/gohufont-14.ttf") format("truetype"),
|
||||||
|
|
|
@ -17,7 +17,7 @@ mixin feed(feed, hideUser)
|
||||||
button.button-link(title="Delete this update") x
|
button.button-link(title="Delete this update") x
|
||||||
.feed-update-date(title=update.date.toLocaleString())= update.relativeDate
|
.feed-update-date(title=update.date.toLocaleString())= update.relativeDate
|
||||||
else
|
else
|
||||||
span [no updates]
|
span [no mood updates]
|
||||||
|
|
||||||
mixin invite_code_expiration(code)
|
mixin invite_code_expiration(code)
|
||||||
- const timestamp = code.expires.getTime()
|
- const timestamp = code.expires.getTime()
|
||||||
|
@ -27,3 +27,37 @@ mixin invite_code_expiration(code)
|
||||||
td.error EXPIRED
|
td.error EXPIRED
|
||||||
else
|
else
|
||||||
td= code.expiresString
|
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
|
button(type="submit") Update
|
||||||
|
|
||||||
h1#feed(style="margin-top:0.5em;") Feed
|
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)
|
+feed(recentUpdates)
|
||||||
|
|
||||||
h1#invite-codes(style="margin-top:1em;") Invite codes
|
h1#invite-codes(style="margin-top:1em;") Invite codes
|
||||||
|
|
|
@ -1,52 +1,43 @@
|
||||||
extends site.pug
|
extends site.pug
|
||||||
|
include _util.pug
|
||||||
|
|
||||||
block head
|
block head
|
||||||
link(rel="stylesheet", href="/css/dashboard.css")
|
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)
|
script(type="module", src="https://cdn.jsdelivr.net/npm/chart.js@4.4.6/dist/chart.umd.min.js", nonce=nonce)
|
||||||
|
|
||||||
block content
|
block content
|
||||||
|
if edit
|
||||||
|
h1 Edit #{entry.title}
|
||||||
|
else
|
||||||
h1 Your Journal
|
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 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.
|
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")
|
|
||||||
|
form#journal-update(action=edit ? `/journal/${id}/edit` : "/journal/update", method="post")
|
||||||
|
if edit
|
||||||
|
input(type="hidden", name="action", value="edit", readonly)
|
||||||
.input
|
.input
|
||||||
span Overall mood change (how do you feel compared to yesterday?)
|
span Overall mood change (how do you feel compared to yesterday?)
|
||||||
#ovm
|
+ovm(entry)
|
||||||
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")
|
|
||||||
.input
|
.input
|
||||||
label(for="title") Title
|
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
|
.input
|
||||||
label(for="description") Journal entry for today
|
label(for="description") Journal entry for today
|
||||||
textarea(name="description", id="description", placeholder="max 4096 chars", maxlength="4096", cols="60", rows="12")
|
textarea(name="description", id="description", placeholder="max 4096 chars", maxlength="4096", cols="60", rows="12")
|
||||||
|
if edit
|
||||||
|
| #{entry.entry}
|
||||||
.input
|
.input
|
||||||
span Visibility
|
span Visibility
|
||||||
|
- const v = entry?.visibility ?? 1
|
||||||
div#visibility-control
|
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
|
label(for="visibility-public") Public
|
||||||
br
|
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
|
label(for="visibility-private") Private
|
||||||
br
|
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
|
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
|
a(href=`/users/${entry.uname}`)= entry.uname
|
||||||
|
|
|
|
||||||
span(title=entry.date.toLocaleString()) #{entryTimestamp}
|
span(title=entry.date.toLocaleString()) #{entryTimestamp}
|
||||||
|
if entry.updated
|
||||||
|
span(title=entry.updated.toLocaleString()) (last updated #{updatedTimestamp})
|
||||||
br
|
br
|
||||||
br
|
br
|
||||||
div
|
div
|
||||||
| Mood:
|
| Mood:
|
||||||
strong= entry.moodString
|
strong= entry.moodString
|
||||||
br
|
br
|
||||||
|
//- I dont know why i made this unsafe but its probably for some markdown thing i was planning on doing
|
||||||
div!= entry.content
|
div!= entry.content
|
||||||
|
|
|
@ -39,7 +39,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
|
| 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
|
#page
|
||||||
block page
|
block page
|
||||||
#content
|
#content
|
||||||
|
|
|
@ -35,15 +35,7 @@ block content
|
||||||
for entry of userJournalEntries
|
for entry of userJournalEntries
|
||||||
li
|
li
|
||||||
a(href=`/journal/${entry.id}`)= entry.title
|
a(href=`/journal/${entry.id}`)= entry.title
|
||||||
span.subtle(title=entry.date.toLocaleString())
|
+journal_entry_suffix(entry)
|
||||||
| (#{entry.relativeDate}
|
|
||||||
if entry.visibility !== 1
|
|
||||||
| ,
|
|
||||||
if entry.visibility === 0
|
|
||||||
| private
|
|
||||||
if entry.visibility === 2
|
|
||||||
| mood-only
|
|
||||||
| )
|
|
||||||
else
|
else
|
||||||
div [no entries]
|
div [no entries]
|
||||||
br
|
br
|
||||||
|
|
Loading…
Add table
Reference in a new issue