v3: follows, notifications, invite-only registration, unread markers

This commit is contained in:
khannurien
2026-03-21 18:42:47 +00:00
parent 7c098e7c4c
commit 608c6bc6a8
55 changed files with 4743 additions and 884 deletions

View File

@@ -9,8 +9,15 @@ import { db, isUserRow, userApiToRow, userRowToApi } from "../model/db.ts";
import { hashPassword } from "../lib/jwt.ts";
const USER_SELECT =
`SELECT u.id, u.username, u.password_hash, u.is_admin, u.created_at, u.avatar_mime, u.invited_by,
i.username as invited_by_username
FROM users u
LEFT JOIN users i ON i.id = u.invited_by`;
export async function createUser(
request: RegisterUserRequest,
inviterId: string | null,
): Promise<User> {
const userId = crypto.randomUUID();
const createdAt = new Date();
@@ -30,14 +37,15 @@ export async function createUser(
const passwordHash = await hashPassword(request.password);
db.prepare(
`INSERT INTO users (id, username, password_hash, is_admin, created_at)
VALUES (?, ?, ?, ?, ?);`,
`INSERT INTO users (id, username, password_hash, is_admin, created_at, invited_by)
VALUES (?, ?, ?, ?, ?, ?);`,
).run(
userId,
request.username,
passwordHash,
0,
createdAt.toISOString(),
inviterId,
);
return {
@@ -51,8 +59,7 @@ export async function createUser(
export function getUserById(userId: string): User {
const userRow = db.prepare(
`SELECT id, username, password_hash, is_admin, created_at, avatar_mime
FROM users WHERE id = ?`,
`${USER_SELECT} WHERE u.id = ?`,
).get(userId);
if (!userRow || !isUserRow(userRow)) {
@@ -64,8 +71,7 @@ export function getUserById(userId: string): User {
export function getUserByUsername(username: string): User {
const userRow = db.prepare(
`SELECT id, username, password_hash, is_admin, created_at, avatar_mime
FROM users WHERE username = ?`,
`${USER_SELECT} WHERE u.username = ?`,
).get(username);
if (!userRow || !isUserRow(userRow)) {
@@ -77,7 +83,7 @@ export function getUserByUsername(username: string): User {
export function listUsers(): User[] {
const userRows = db.prepare(
`SELECT id, username, password_hash, is_admin, created_at, avatar_mime FROM users`,
`${USER_SELECT}`,
).all();
if (!userRows || !userRows.every(isUserRow)) {