From 028ba0f2f928608f03baa419ca9fcaaa4558f546 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Tue, 16 Jun 2026 11:05:56 -0600 Subject: [PATCH] feat: add creator --- server/db.ts | 33 +++++++++++++++++++++++++++++---- server/routes/books.ts | 7 ++++--- src/components/BookListPage.vue | 2 +- src/services/booksApi.ts | 1 + 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/server/db.ts b/server/db.ts index 86a30f5..e09d8a3 100644 --- a/server/db.ts +++ b/server/db.ts @@ -6,6 +6,7 @@ export interface BookSummary { name: string updatedAt: string lessonCount: number + createdBy: string } export interface BookRecord { @@ -26,6 +27,7 @@ interface BookRow { name: string data: string updated_at: string + created_by: string } type StoredTeachingBook = Omit & { @@ -67,7 +69,8 @@ const SCHEMA = ` name TEXT NOT NULL, data TEXT NOT NULL, created_at TEXT NOT NULL, - updated_at TEXT NOT NULL + updated_at TEXT NOT NULL, + created_by TEXT NOT NULL DEFAULT '' ); CREATE TABLE IF NOT EXISTS users ( @@ -124,6 +127,14 @@ function parseBookData(data: string): TeachingBook { return normalizeBookData(JSON.parse(data) as StoredTeachingBook).data } +function migrateBookOwnership(db: Database): void { + const admin = db + .query<{ id: string }, []>("SELECT id FROM users WHERE role = 'admin' LIMIT 1") + .get() + if (!admin) return + db.run("UPDATE books SET created_by = ? WHERE created_by = ''", [admin.id]) +} + function migrateStoredBooks(db: Database): void { const rows = db.query<{ id: string; data: string }, []>('SELECT id, data FROM books').all() @@ -139,13 +150,25 @@ export function openDb(path: string): Database { const db = new Database(path) db.run('PRAGMA foreign_keys = ON') db.run(SCHEMA) + try { + db.run("ALTER TABLE books ADD COLUMN created_by TEXT NOT NULL DEFAULT ''") + } catch { + // column already exists + } migrateStoredBooks(db) + migrateBookOwnership(db) return db } export function listBooks(db: Database): BookSummary[] { const rows = db - .query('SELECT id, name, data, updated_at FROM books ORDER BY updated_at DESC') + .query( + `SELECT b.id, b.name, b.data, b.updated_at, b.created_by, + COALESCE(u.username, '') AS creator_username + FROM books b + LEFT JOIN users u ON b.created_by = u.id + ORDER BY b.updated_at DESC`, + ) .all() return rows.map((row) => ({ @@ -153,21 +176,23 @@ export function listBooks(db: Database): BookSummary[] { name: row.name, updatedAt: row.updated_at, lessonCount: parseBookData(row.data).designs.length, + createdBy: row.creator_username, })) } -export function createBook(db: Database, name: string): BookRecord { +export function createBook(db: Database, name: string, userId = ''): BookRecord { const id = crypto.randomUUID() const now = new Date().toISOString() const data = createEmptyBook() data.updatedAt = now - db.run('INSERT INTO books (id, name, data, created_at, updated_at) VALUES (?, ?, ?, ?, ?)', [ + db.run('INSERT INTO books (id, name, data, created_at, updated_at, created_by) VALUES (?, ?, ?, ?, ?, ?)', [ id, name, JSON.stringify(data), now, now, + userId, ]) return { id, name, updatedAt: now, data } diff --git a/server/routes/books.ts b/server/routes/books.ts index e00742d..cf9e15c 100644 --- a/server/routes/books.ts +++ b/server/routes/books.ts @@ -2,9 +2,10 @@ import type { Database } from 'bun:sqlite' import { Hono } from 'hono' import type { TeachingBook } from '../../shared/domain/teachingDesign' import { createBook, deleteBook, getBook, listBooks, renameBook, saveBookData } from '../db' +import type { AuthVariables } from '../middleware/bearerAuth' -export function createBooksRouter(db: Database): Hono { - const app = new Hono() +export function createBooksRouter(db: Database): Hono<{ Variables: AuthVariables }> { + const app = new Hono<{ Variables: AuthVariables }>() app.get('/', (c) => { return c.json(listBooks(db)) @@ -18,7 +19,7 @@ export function createBooksRouter(db: Database): Hono { return c.json({ error: '请提供整本名称。' }, 400) } - return c.json(createBook(db, name.trim())) + return c.json(createBook(db, name.trim(), c.get('userId'))) }) app.get('/:id', (c) => { diff --git a/src/components/BookListPage.vue b/src/components/BookListPage.vue index 0e70342..20936f8 100644 --- a/src/components/BookListPage.vue +++ b/src/components/BookListPage.vue @@ -156,7 +156,7 @@ async function removeBook(book: BookSummary): Promise {