当然可以, 我们来对内容管理的三个方面进行优化: 草稿功能、版本控制和内容审核。这些优化将大大提升博客系统的用户体验和管理能力。让我们逐一实现这些功能:
- 草稿功能
首先, 我们需要更新数据库模式以支持草稿:
// src/db/schema.ts
import { sqliteTable, text, integer, boolean } from 'drizzle-orm/sqlite-core';
export const posts = sqliteTable('posts', {
id: integer('id').primaryKey(),
title: text('title').notNull(),
content: text('content').notNull(),
authorId: integer('author_id').notNull().references(() => users.id),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(sql`CURRENT_TIMESTAMP`),
updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull().default(sql`CURRENT_TIMESTAMP`),
isDraft: boolean('is_draft').notNull().default(true),
});然后, 更新文章创建和编辑的路由:
// src/index.ts
app.post('/api/post', async ({ body, getUser }) => {
const user = await getUser();
if (!user) {
return new Response('Unauthorized', { status: 401 });
}
const { title, content, isDraft } = body as { title: string; content: string; isDraft: boolean };
const newPost = await db.insert(posts).values({
title,
content,
authorId: user.id,
isDraft
}).returning().get();
return newPost;
});
app.put('/api/post/:id', async ({ params, body, getUser }) => {
const user = await getUser();
if (!user) {
return new Response('Unauthorized', { status: 401 });
}
const { title, content, isDraft } = body as { title: string; content: string; isDraft: boolean };
const updatedPost = await db.update(posts)
.set({ title, content, isDraft, updatedAt: new Date() })
.where(eq(posts.id, parseInt(params.id)))
.returning()
.get();
return updatedPost;
});
app.get('/api/drafts', async ({ getUser }) => {
const user = await getUser();
if (!user) {
return new Response('Unauthorized', { status: 401 });
}
const drafts = await db.select()
.from(posts)
.where(and(eq(posts.authorId, user.id), eq(posts.isDraft, true)))
.all();
return drafts;
});- 版本控制
为了实现版本控制, 我们需要创建一个新的表来存储文章的历史版本:
// src/db/schema.ts
export const postVersions = sqliteTable('post_versions', {
id: integer('id').primaryKey(),
postId: integer('post_id').notNull().references(() => posts.id),
title: text('title').notNull(),
content: text('content').notNull(),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(sql`CURRENT_TIMESTAMP`),
versionNumber: integer('version_number').notNull(),
});然后, 在更新文章时创建新的版本:
// src/index.ts
app.put('/api/post/:id', async ({ params, body, getUser }) => {
const user = await getUser();
if (!user) {
return new Response('Unauthorized', { status: 401 });
}
const { title, content, isDraft } = body as { title: string; content: string; isDraft: boolean };
// 开始事务
await db.transaction(async (tx) => {
// 更新文章
const updatedPost = await tx.update(posts)
.set({ title, content, isDraft, updatedAt: new Date() })
.where(eq(posts.id, parseInt(params.id)))
.returning()
.get();
// 获取最新的版本号
const latestVersion = await tx.select({ maxVersion: sql`max(${postVersions.versionNumber})` })
.from(postVersions)
.where(eq(postVersions.postId, updatedPost.id))
.get();
const newVersionNumber = (latestVersion?.maxVersion || 0) + 1;
// 创建新的版本
await tx.insert(postVersions).values({
postId: updatedPost.id,
title: updatedPost.title,
content: updatedPost.content,
versionNumber: newVersionNumber,
}).run();
return updatedPost;
});
});
// 获取文章的所有版本
app.get('/api/post/:id/versions', async ({ params, getUser }) => {
const user = await getUser();
if (!user) {
return new Response('Unauthorized', { status: 401 });
}
const versions = await db.select()
.from(postVersions)
.where(eq(postVersions.postId, parseInt(params.id)))
.orderBy(desc(postVersions.versionNumber))
.all();
return versions;
});
// 回滚到特定版本
app.post('/api/post/:id/rollback/:versionId', async ({ params, getUser }) => {
const user = await getUser();
if (!user) {
return new Response('Unauthorized', { status: 401 });
}
const version = await db.select()
.from(postVersions)
.where(eq(postVersions.id, parseInt(params.versionId)))
.get();
if (!version) {
return new Response('Version not found', { status: 404 });
}
const updatedPost = await db.update(posts)
.set({ title: version.title, content: version.content, updatedAt: new Date() })
.where(eq(posts.id, parseInt(params.id)))
.returning()
.get();
return updatedPost;
});- 内容审核
为评论添加审核功能:
// src/db/schema.ts
export const comments = sqliteTable('comments', {
id: integer('id').primaryKey(),
postId: integer('post_id').notNull().references(() => posts.id),
AuthorId: integer ('author_id'). References (() => users. Id),
content: text('content').notNull(),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(sql`CURRENT_TIMESTAMP`),
isApproved: boolean('is_approved').notNull().default(false),
});
// src/index.ts
app.post('/api/comment', async ({ body, getUser }) => {
Const user = await getUser ();
const { postId, content } = body as { postId: number, content: string };
const newComment = await db.insert(comments).values({
postId,
authorId: user?.id,
content,
isApproved: false, // 新评论默认未审核
}).returning().get();
// 如果配置了自动审核 (例如对已登录用户)
if (user) {
await db.update(comments)
.set({ isApproved: true })
.where(eq(comments.id, newComment.id))
.run();
} else {
// 发送通知给管理员,有新评论需要审核
// sendNotificationToAdmin(newComment);
}
return newComment;
});
// 获取评论 (仅显示已审核的评论)
app.get('/api/post/:id/comments', async ({ params }) => {
const approvedComments = await db.select()
.from(comments)
.where(and(eq(comments.postId, parseInt(params.id)), eq(comments.isApproved, true)))
.all();
return approvedComments;
});
// 审核评论 (仅管理员可用)
app.post('/api/comment/:id/approve', async ({ params, getUser }) => {
const user = await getUser();
if (!user || !user.isAdmin) {
return new Response('Unauthorized', { status: 401 });
}
const updatedComment = await db.update(comments)
.set({ isApproved: true })
.where(eq(comments.id, parseInt(params.id)))
.returning()
.get();
return updatedComment;
});这些优化为博客系统添加了以下功能:
- 草稿功能: 用户可以保存和编辑草稿, 在准备好之前不会发布。
- 版本控制: 每次文章更新都会创建新版本, 允许查看历史版本和回滚。
- 内容审核: 评论需要审核才能显示, 提高了内容质量和安全性。
要完善这些功能, 你还需要:
- 在前端实现相应的用户界面, 如草稿列表、版本历史查看器和评论管理界面。
- 实现更复杂的审核逻辑, 如基于关键词的自动审核或垃圾评论过滤。
- 添加管理员通知系统, 当有新的评论需要审核时通知管理员。
- 考虑实现文章的自动保存功能, 以防止意外丢失内容。
- 为版本控制添加差异比较功能, 方便用户查看不同版本间的变化。
这些功能将大大提升博客系统的用户体验和管理能力, 使其更加强大和灵活。随着系统的发展, 你可能还需要考虑性能优化, 如缓存常用查询结果或使用全文搜索引擎来提高搜索效率。