refactor: RBAC权限系统重构 + UI组件拆分 + 测试修复 + 架构文档
Some checks failed
CI / build-deploy (push) Has been cancelled
Some checks failed
CI / build-deploy (push) Has been cancelled
- RBAC: 新增30个权限点、DataScope行级权限、requirePermission守卫,所有57+ Server Action接入权限校验 - UI拆分: exam-form(1623行→11文件)、textbook-reader(744行→7文件),均降至300行以内 - 测试: 新增5个单元测试文件(19用例),修复4个集成测试文件(38用例全部通过) - 架构文档: 新增架构影响地图(004/005)、标准功能清单(006)、差距审计报告(007) - 项目规则: 架构图优先规则,改码必同步图 - 安全: rehype-sanitize净化、AES加密API Key、权限路由守卫 - 无障碍: skip-link、aria-label、prefers-reduced-motion - 性能: next/font优化、next/image、代码分割
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
"use server";
|
||||
|
||||
import { requirePermission, PermissionDeniedError } from "@/shared/lib/auth-guard";
|
||||
import { Permissions } from "@/shared/types/permissions";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import {
|
||||
createTextbook,
|
||||
@@ -24,10 +26,14 @@ export async function reorderChaptersAction(
|
||||
textbookId: string
|
||||
): Promise<ActionState> {
|
||||
try {
|
||||
await requirePermission(Permissions.TEXTBOOK_UPDATE);
|
||||
await reorderChapters(chapterId, newIndex, parentId);
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
return { success: true, message: "Chapters reordered successfully" };
|
||||
} catch {
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) {
|
||||
return { success: false, message: e.message };
|
||||
}
|
||||
return { success: false, message: "Failed to reorder chapters" };
|
||||
}
|
||||
}
|
||||
@@ -60,13 +66,17 @@ export async function createTextbookAction(
|
||||
}
|
||||
|
||||
try {
|
||||
await requirePermission(Permissions.TEXTBOOK_CREATE);
|
||||
await createTextbook(rawData);
|
||||
revalidatePath("/teacher/textbooks");
|
||||
return {
|
||||
success: true,
|
||||
message: "Textbook created successfully.",
|
||||
};
|
||||
} catch {
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) {
|
||||
return { success: false, message: e.message };
|
||||
}
|
||||
return {
|
||||
success: false,
|
||||
message: "Failed to create textbook.",
|
||||
@@ -95,13 +105,17 @@ export async function updateTextbookAction(
|
||||
}
|
||||
|
||||
try {
|
||||
await requirePermission(Permissions.TEXTBOOK_UPDATE);
|
||||
await updateTextbook(rawData);
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
return {
|
||||
success: true,
|
||||
message: "Textbook updated successfully.",
|
||||
};
|
||||
} catch {
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) {
|
||||
return { success: false, message: e.message };
|
||||
}
|
||||
return {
|
||||
success: false,
|
||||
message: "Failed to update textbook.",
|
||||
@@ -113,13 +127,17 @@ export async function deleteTextbookAction(
|
||||
textbookId: string
|
||||
): Promise<ActionState> {
|
||||
try {
|
||||
await requirePermission(Permissions.TEXTBOOK_DELETE);
|
||||
await deleteTextbook(textbookId);
|
||||
revalidatePath("/teacher/textbooks");
|
||||
return {
|
||||
success: true,
|
||||
message: "Textbook deleted successfully.",
|
||||
};
|
||||
} catch {
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) {
|
||||
return { success: false, message: e.message };
|
||||
}
|
||||
return {
|
||||
success: false,
|
||||
message: "Failed to delete textbook.",
|
||||
@@ -138,6 +156,7 @@ export async function createChapterAction(
|
||||
if (!title) return { success: false, message: "Title is required" };
|
||||
|
||||
try {
|
||||
await requirePermission(Permissions.TEXTBOOK_CREATE);
|
||||
await createChapter({
|
||||
textbookId,
|
||||
title,
|
||||
@@ -146,7 +165,10 @@ export async function createChapterAction(
|
||||
});
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
return { success: true, message: "Chapter created successfully" };
|
||||
} catch {
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) {
|
||||
return { success: false, message: e.message };
|
||||
}
|
||||
return { success: false, message: "Failed to create chapter" };
|
||||
}
|
||||
}
|
||||
@@ -157,10 +179,14 @@ export async function updateChapterContentAction(
|
||||
textbookId: string
|
||||
): Promise<ActionState> {
|
||||
try {
|
||||
await requirePermission(Permissions.TEXTBOOK_UPDATE);
|
||||
await updateChapterContent({ chapterId, content });
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
return { success: true, message: "Content updated successfully" };
|
||||
} catch {
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) {
|
||||
return { success: false, message: e.message };
|
||||
}
|
||||
return { success: false, message: "Failed to update content" };
|
||||
}
|
||||
}
|
||||
@@ -170,10 +196,14 @@ export async function deleteChapterAction(
|
||||
textbookId: string
|
||||
): Promise<ActionState> {
|
||||
try {
|
||||
await requirePermission(Permissions.TEXTBOOK_DELETE);
|
||||
await deleteChapter(chapterId);
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
return { success: true, message: "Chapter deleted successfully" };
|
||||
} catch {
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) {
|
||||
return { success: false, message: e.message };
|
||||
}
|
||||
return { success: false, message: "Failed to delete chapter" };
|
||||
}
|
||||
}
|
||||
@@ -191,10 +221,14 @@ export async function createKnowledgePointAction(
|
||||
if (!name) return { success: false, message: "Name is required" };
|
||||
|
||||
try {
|
||||
await requirePermission(Permissions.TEXTBOOK_CREATE);
|
||||
await createKnowledgePoint({ name, description, anchorText, chapterId });
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
return { success: true, message: "Knowledge point created successfully" };
|
||||
} catch {
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) {
|
||||
return { success: false, message: e.message };
|
||||
}
|
||||
return { success: false, message: "Failed to create knowledge point" };
|
||||
}
|
||||
}
|
||||
@@ -204,10 +238,14 @@ export async function deleteKnowledgePointAction(
|
||||
textbookId: string
|
||||
): Promise<ActionState> {
|
||||
try {
|
||||
await requirePermission(Permissions.TEXTBOOK_DELETE);
|
||||
await deleteKnowledgePoint(kpId);
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
return { success: true, message: "Knowledge point deleted successfully" };
|
||||
} catch {
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) {
|
||||
return { success: false, message: e.message };
|
||||
}
|
||||
return { success: false, message: "Failed to delete knowledge point" };
|
||||
}
|
||||
}
|
||||
@@ -225,10 +263,14 @@ export async function updateKnowledgePointAction(
|
||||
if (!name) return { success: false, message: "Name is required" };
|
||||
|
||||
try {
|
||||
await requirePermission(Permissions.TEXTBOOK_UPDATE);
|
||||
await updateKnowledgePoint({ id: kpId, name, description, anchorText });
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
return { success: true, message: "Knowledge point updated successfully" };
|
||||
} catch {
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) {
|
||||
return { success: false, message: e.message };
|
||||
}
|
||||
return { success: false, message: "Failed to update knowledge point" };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user