refactor(actions): 组 A 模块迁移至 invalidateFor(users/school/textbooks/questions/course-plans/standards/scheduling/audit/onboarding/invitation-codes/proctoring/i18n)
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
"use server"
|
||||
|
||||
import { cookies } from "next/headers"
|
||||
import { revalidatePath } from "next/cache"
|
||||
|
||||
import {
|
||||
LOCALE_COOKIE,
|
||||
@@ -9,6 +8,7 @@ import {
|
||||
type Locale,
|
||||
isLocale,
|
||||
} from "@/shared/i18n/locale"
|
||||
import { invalidateFor } from "@/shared/lib/cache"
|
||||
|
||||
/**
|
||||
* 切换语言:写入 cookie + 触发页面刷新。
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
* 设计说明:
|
||||
* - 不使用 URL 路由段,避免破坏现有路由组结构
|
||||
* - cookie 持久化用户偏好,SSR 时由 i18n/request.ts 读取
|
||||
* - revalidatePath 确保所有页面用新 locale 重新渲染
|
||||
* - invalidateFor 确保所有页面用新 locale 重新渲染
|
||||
*/
|
||||
export async function setLocaleAction(locale: string): Promise<{ success: boolean }> {
|
||||
if (!isLocale(locale)) {
|
||||
@@ -27,6 +27,6 @@ export async function setLocaleAction(locale: string): Promise<{ success: boolea
|
||||
cookieStore.set(LOCALE_COOKIE, locale as Locale, LOCALE_COOKIE_OPTIONS)
|
||||
|
||||
// 刷新所有页面,让 SSR 用新 locale 重新渲染
|
||||
revalidatePath("/", "layout")
|
||||
await invalidateFor("i18n.setLocale")
|
||||
return { success: true }
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
import { PermissionDeniedError, requirePermission } from "@/shared/lib/auth-guard"
|
||||
import { Permissions } from "@/shared/types/permissions"
|
||||
import type { ActionState } from "@/shared/types/action-state"
|
||||
import { invalidateFor } from "@/shared/lib/cache"
|
||||
import { trackEvent } from "@/shared/lib/track-event"
|
||||
import { getSession } from "@/shared/lib/session"
|
||||
|
||||
@@ -180,7 +180,7 @@ export async function saveAuditRetentionConfigAction(
|
||||
},
|
||||
})
|
||||
|
||||
revalidatePath("/admin/audit-logs/overview")
|
||||
await invalidateFor("audit.saveRetentionConfig")
|
||||
return { success: true, data: config }
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
|
||||
@@ -215,8 +215,7 @@ export async function purgeAuditLogsAction(
|
||||
},
|
||||
})
|
||||
|
||||
revalidatePath("/admin/audit-logs/overview")
|
||||
revalidatePath("/admin/audit-logs")
|
||||
await invalidateFor("audit.purge")
|
||||
return { success: true, data: result }
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
import { requirePermission } from "@/shared/lib/auth-guard"
|
||||
import { Permissions } from "@/shared/types/permissions"
|
||||
import type { ActionState } from "@/shared/types/action-state"
|
||||
import { invalidateFor } from "@/shared/lib/cache"
|
||||
import { handleActionError } from "@/shared/lib/action-utils"
|
||||
import type { DataScope } from "@/shared/types/permissions"
|
||||
|
||||
@@ -90,19 +90,6 @@ function resolveScope(
|
||||
return { userId: ctx.userId, isAdmin: false }
|
||||
}
|
||||
|
||||
const revalidatePlanPaths = (id?: string): void => {
|
||||
revalidatePath("/admin/course-plans")
|
||||
revalidatePath("/teacher/course-plans")
|
||||
revalidatePath("/parent/course-plans")
|
||||
revalidatePath("/student/course-plans")
|
||||
if (id) {
|
||||
revalidatePath(`/admin/course-plans/${id}`)
|
||||
revalidatePath(`/teacher/course-plans/${id}`)
|
||||
revalidatePath(`/parent/course-plans/${id}`)
|
||||
revalidatePath(`/student/course-plans/${id}`)
|
||||
}
|
||||
}
|
||||
|
||||
export async function createCoursePlanAction(
|
||||
prevState: ActionState<string> | null,
|
||||
formData: FormData
|
||||
@@ -134,7 +121,7 @@ export async function createCoursePlanAction(
|
||||
}
|
||||
|
||||
const id = await createCoursePlan(parsed.data, ctx.userId)
|
||||
revalidatePlanPaths(id)
|
||||
await invalidateFor("course-plans.create", { id })
|
||||
return { success: true, message: "Course plan created", data: id }
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
@@ -179,7 +166,7 @@ export async function updateCoursePlanAction(
|
||||
}
|
||||
|
||||
await updateCoursePlan(id, parsed.data)
|
||||
revalidatePlanPaths(id)
|
||||
await invalidateFor("course-plans.update", { id })
|
||||
return { success: true, message: "Course plan updated", data: id }
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
@@ -198,7 +185,7 @@ export async function deleteCoursePlanAction(
|
||||
if (!existing) return { success: false, message: "Course plan not found" }
|
||||
|
||||
await deleteCoursePlan(id)
|
||||
revalidatePlanPaths()
|
||||
await invalidateFor("course-plans.delete")
|
||||
return { success: true, message: "Course plan deleted" }
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
@@ -279,7 +266,7 @@ export async function createCoursePlanItemAction(
|
||||
if (!existing) return { success: false, message: "Course plan not found" }
|
||||
|
||||
const itemId = await createCoursePlanItem(parsed.data)
|
||||
revalidatePlanPaths(parsed.data.planId)
|
||||
await invalidateFor("course-plans.item.create", { id: parsed.data.planId })
|
||||
return { success: true, message: "Week plan added", data: itemId }
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
@@ -319,7 +306,7 @@ export async function updateCoursePlanItemAction(
|
||||
}
|
||||
|
||||
await updateCoursePlanItem(id, parsed.data)
|
||||
revalidatePlanPaths()
|
||||
await invalidateFor("course-plans.item.update")
|
||||
return { success: true, message: "Week plan updated", data: id }
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
@@ -332,7 +319,7 @@ export async function deleteCoursePlanItemAction(
|
||||
try {
|
||||
await requirePermission(Permissions.COURSE_PLAN_MANAGE)
|
||||
await deleteCoursePlanItem(id)
|
||||
revalidatePlanPaths()
|
||||
await invalidateFor("course-plans.item.delete")
|
||||
return { success: true, message: "Week plan deleted" }
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
@@ -349,7 +336,7 @@ export async function toggleCoursePlanItemCompletedAction(
|
||||
isCompleted: completed,
|
||||
completedAt: completed ? new Date().toISOString().slice(0, 10) : null,
|
||||
})
|
||||
revalidatePlanPaths()
|
||||
await invalidateFor("course-plans.item.toggleCompleted")
|
||||
return {
|
||||
success: true,
|
||||
message: completed ? "Marked as completed" : "Marked as incomplete",
|
||||
@@ -379,7 +366,7 @@ export async function reorderCoursePlanItemsAction(
|
||||
if (!existing) return { success: false, message: "Course plan not found" }
|
||||
|
||||
await reorderCoursePlanItems(parsed.data.planId, parsed.data.items)
|
||||
revalidatePlanPaths(parsed.data.planId)
|
||||
await invalidateFor("course-plans.item.reorder", { id: parsed.data.planId })
|
||||
return { success: true, message: "Order saved", data: parsed.data.planId }
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
@@ -402,7 +389,7 @@ export async function bulkToggleItemsAction(
|
||||
}
|
||||
|
||||
const count = await bulkUpdateItemCompleted(parsed.data.itemIds, parsed.data.completed)
|
||||
revalidatePlanPaths()
|
||||
await invalidateFor("course-plans.item.bulkToggle")
|
||||
return { success: true, message: "Bulk updated", data: count }
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
@@ -430,7 +417,7 @@ export async function copyCoursePlanAction(
|
||||
if (!existing) return { success: false, message: "Course plan not found" }
|
||||
|
||||
const ids = await copyCoursePlanToClasses(parsed.data.sourcePlanId, parsed.data.targetClassIds)
|
||||
revalidatePlanPaths()
|
||||
await invalidateFor("course-plans.copy")
|
||||
return { success: true, message: "Copied", data: ids }
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
|
||||
import type { ActionState } from "@/shared/types/action-state"
|
||||
import { requirePermission } from "@/shared/lib/auth-guard"
|
||||
import { Permissions } from "@/shared/types/permissions"
|
||||
import { invalidateFor } from "@/shared/lib/cache"
|
||||
import { trackEvent } from "@/shared/lib/track-event"
|
||||
|
||||
import {
|
||||
@@ -63,7 +62,7 @@ export async function generateInvitationCodesAction(
|
||||
},
|
||||
})
|
||||
|
||||
revalidatePath("/admin/invitation-codes")
|
||||
await invalidateFor("invitation-codes.generate")
|
||||
|
||||
return { success: true, data: result }
|
||||
} catch (error) {
|
||||
@@ -121,7 +120,7 @@ export async function deleteInvitationCodeAction(
|
||||
targetId: codeId,
|
||||
})
|
||||
|
||||
revalidatePath("/admin/invitation-codes")
|
||||
await invalidateFor("invitation-codes.delete")
|
||||
return { success: true, data: null }
|
||||
} catch (error) {
|
||||
const message =
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
import { eq } from "drizzle-orm"
|
||||
|
||||
import type { ActionState } from "@/shared/types/action-state"
|
||||
import { requireAuth } from "@/shared/lib/auth-guard"
|
||||
import { invalidateFor } from "@/shared/lib/cache"
|
||||
import { logAudit } from "@/shared/lib/audit-logger"
|
||||
import { resolveDefaultPath } from "@/shared/lib/route-resolver"
|
||||
import {
|
||||
@@ -243,7 +243,7 @@ export async function completeOnboardingAction(
|
||||
status: failures.length === 0 ? "success" : "failure",
|
||||
})
|
||||
|
||||
revalidatePath("/onboarding")
|
||||
await invalidateFor("onboarding.complete")
|
||||
|
||||
// 若有局部失败,返回成功但附带失败列表(P1-2)
|
||||
if (failures.length > 0) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
import type { ActionState } from "@/shared/types/action-state"
|
||||
import { requirePermission } from "@/shared/lib/auth-guard"
|
||||
import { invalidateFor } from "@/shared/lib/cache"
|
||||
import { handleActionError } from "@/shared/lib/action-utils"
|
||||
import { Permissions } from "@/shared/types/permissions"
|
||||
import { z } from "zod"
|
||||
@@ -85,7 +85,7 @@ export async function recordProctoringEventAction(
|
||||
eventDetail: parsed.data.eventDetail,
|
||||
})
|
||||
|
||||
revalidatePath(`/teacher/exams/${parsed.data.examId}/proctoring`)
|
||||
await invalidateFor("proctoring.recordEvent", { examId: parsed.data.examId })
|
||||
|
||||
return successState({ id: event.id }, "Event recorded")
|
||||
} catch (error) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Permissions } from "@/shared/types/permissions"
|
||||
import { CreateQuestionSchema } from "./schema"
|
||||
import type { CreateQuestionInput } from "./schema"
|
||||
import type { ActionState } from "@/shared/types/action-state"
|
||||
import { revalidatePath } from "next/cache"
|
||||
import { invalidateFor } from "@/shared/lib/cache"
|
||||
import { z } from "zod"
|
||||
import {
|
||||
createQuestionWithRelations,
|
||||
@@ -68,8 +68,7 @@ export async function createQuestionAction(
|
||||
|
||||
trackQuestionCreated(questionId, input.type, input.difficulty)
|
||||
|
||||
revalidatePath("/teacher/questions")
|
||||
revalidatePath("/admin/questions")
|
||||
await invalidateFor("questions.create")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
@@ -117,8 +116,7 @@ export async function updateQuestionAction(
|
||||
|
||||
trackQuestionUpdated(id, updateData.type, updateData.difficulty)
|
||||
|
||||
revalidatePath("/teacher/questions")
|
||||
revalidatePath("/admin/questions")
|
||||
await invalidateFor("questions.update")
|
||||
|
||||
return { success: true, message: "Question updated successfully", data: id }
|
||||
} catch (e) {
|
||||
@@ -143,8 +141,7 @@ export async function deleteQuestionAction(
|
||||
|
||||
trackQuestionDeleted(questionId)
|
||||
|
||||
revalidatePath("/teacher/questions")
|
||||
revalidatePath("/admin/questions")
|
||||
await invalidateFor("questions.delete")
|
||||
|
||||
return { success: true, message: "Question deleted successfully", data: questionId }
|
||||
} catch (e) {
|
||||
@@ -190,8 +187,7 @@ export async function deleteQuestionsBatchAction(
|
||||
trackQuestionDeleted(id)
|
||||
}
|
||||
|
||||
revalidatePath("/teacher/questions")
|
||||
revalidatePath("/admin/questions")
|
||||
await invalidateFor("questions.deleteBatch")
|
||||
|
||||
return { success: true, message: "Batch delete completed", data: { deleted: deletedCount } }
|
||||
} catch (e) {
|
||||
@@ -369,8 +365,7 @@ export async function importQuestionsAction(
|
||||
trackQuestionCreated(createdIds[i], item.type, item.difficulty)
|
||||
}
|
||||
|
||||
revalidatePath("/teacher/questions")
|
||||
revalidatePath("/admin/questions")
|
||||
await invalidateFor("questions.import")
|
||||
|
||||
return { success: true, message: "Import completed", data: { imported: createdIds.length } }
|
||||
} catch (e) {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
|
||||
import { requirePermission, PermissionDeniedError } from "@/shared/lib/auth-guard"
|
||||
import { Permissions } from "@/shared/types/permissions"
|
||||
import type { ActionState } from "@/shared/types/action-state"
|
||||
import { invalidateFor } from "@/shared/lib/cache"
|
||||
|
||||
import { getUserNamesByIds } from "@/modules/users/data-access"
|
||||
|
||||
@@ -61,7 +60,7 @@ export async function saveSchedulingRulesAction(
|
||||
}
|
||||
|
||||
const id = await upsertSchedulingRules(parsed.data)
|
||||
revalidatePath("/admin/scheduling/rules")
|
||||
await invalidateFor("scheduling.saveRules")
|
||||
return { success: true, message: "Scheduling rules saved", data: id }
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
|
||||
@@ -167,8 +166,7 @@ export async function applyAutoScheduleAction(
|
||||
}))
|
||||
)
|
||||
|
||||
revalidatePath("/admin/scheduling/auto")
|
||||
revalidatePath("/teacher/classes/schedule")
|
||||
await invalidateFor("scheduling.autoSchedule")
|
||||
return { success: true, message: `Applied ${schedules.length} schedule items`, data: schedules.length }
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
|
||||
@@ -205,8 +203,7 @@ export async function requestScheduleChangeAction(
|
||||
}
|
||||
|
||||
const id = await createScheduleChange(parsed.data, ctx.userId)
|
||||
revalidatePath("/teacher/schedule-changes")
|
||||
revalidatePath("/admin/scheduling/changes")
|
||||
await invalidateFor("scheduling.requestChange")
|
||||
return { success: true, message: "Schedule change request submitted", data: id }
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
|
||||
@@ -221,8 +218,7 @@ export async function approveScheduleChangeAction(changeId: string): Promise<Act
|
||||
if (!changeId) return { success: false, message: "Missing change id" }
|
||||
|
||||
await updateScheduleChangeStatus(changeId, "approved", ctx.userId)
|
||||
revalidatePath("/admin/scheduling/changes")
|
||||
revalidatePath("/teacher/schedule-changes")
|
||||
await invalidateFor("scheduling.approveChange")
|
||||
return { success: true, message: "Schedule change approved" }
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
|
||||
@@ -240,8 +236,7 @@ export async function rejectScheduleChangeAction(
|
||||
if (!changeId) return { success: false, message: "Missing change id" }
|
||||
|
||||
await updateScheduleChangeStatus(changeId, "rejected", ctx.userId)
|
||||
revalidatePath("/admin/scheduling/changes")
|
||||
revalidatePath("/teacher/schedule-changes")
|
||||
await invalidateFor("scheduling.rejectChange")
|
||||
return { success: true, message: reason ? `Rejected: ${reason}` : "Schedule change rejected" }
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
import { after } from "next/server"
|
||||
import { createId } from "@paralleldrive/cuid2"
|
||||
|
||||
import type { ActionState } from "@/shared/types/action-state"
|
||||
import { invalidateFor } from "@/shared/lib/cache"
|
||||
import { requirePermission, PermissionDeniedError } from "@/shared/lib/auth-guard"
|
||||
import { Permissions } from "@/shared/types/permissions"
|
||||
import { logAudit } from "@/shared/lib/audit-logger"
|
||||
@@ -54,7 +54,7 @@ export async function createDepartmentAction(
|
||||
})
|
||||
)
|
||||
|
||||
revalidatePath("/admin/school/departments")
|
||||
await invalidateFor("school.department.create")
|
||||
return { success: true, message: "Department created" }
|
||||
} catch (error) {
|
||||
if (error instanceof PermissionDeniedError) return { success: false, message: error.message }
|
||||
@@ -93,7 +93,7 @@ export async function updateDepartmentAction(
|
||||
})
|
||||
)
|
||||
|
||||
revalidatePath("/admin/school/departments")
|
||||
await invalidateFor("school.department.update")
|
||||
return { success: true, message: "Department updated" }
|
||||
} catch (error) {
|
||||
if (error instanceof PermissionDeniedError) return { success: false, message: error.message }
|
||||
@@ -114,7 +114,7 @@ export async function deleteDepartmentAction(departmentId: string): Promise<Acti
|
||||
targetType: "department",
|
||||
})
|
||||
)
|
||||
revalidatePath("/admin/school/departments")
|
||||
await invalidateFor("school.department.delete")
|
||||
return { success: true, message: "Department deleted" }
|
||||
} catch (error) {
|
||||
if (error instanceof PermissionDeniedError) return { success: false, message: error.message }
|
||||
@@ -156,7 +156,7 @@ export async function createAcademicYearAction(
|
||||
})
|
||||
)
|
||||
|
||||
revalidatePath("/admin/school/academic-year")
|
||||
await invalidateFor("school.academicYear.create")
|
||||
return { success: true, message: "Academic year created" }
|
||||
} catch (error) {
|
||||
if (error instanceof PermissionDeniedError) return { success: false, message: error.message }
|
||||
@@ -199,7 +199,7 @@ export async function updateAcademicYearAction(
|
||||
})
|
||||
)
|
||||
|
||||
revalidatePath("/admin/school/academic-year")
|
||||
await invalidateFor("school.academicYear.update")
|
||||
return { success: true, message: "Academic year updated" }
|
||||
} catch (error) {
|
||||
if (error instanceof PermissionDeniedError) return { success: false, message: error.message }
|
||||
@@ -212,7 +212,7 @@ export async function deleteAcademicYearAction(academicYearId: string): Promise<
|
||||
try {
|
||||
await requirePermission(Permissions.SCHOOL_MANAGE)
|
||||
await deleteAcademicYear(academicYearId)
|
||||
revalidatePath("/admin/school/academic-year")
|
||||
await invalidateFor("school.academicYear.delete")
|
||||
return { success: true, message: "Academic year deleted" }
|
||||
} catch (error) {
|
||||
if (error instanceof PermissionDeniedError) return { success: false, message: error.message }
|
||||
@@ -245,7 +245,7 @@ export async function createSchoolAction(
|
||||
logAudit({ action: "school.create", module: "school", targetType: "school", detail: { name: parsed.data.name } })
|
||||
)
|
||||
|
||||
revalidatePath("/admin/school/schools")
|
||||
await invalidateFor("school.school.create")
|
||||
return { success: true, message: "School created" }
|
||||
} catch (error) {
|
||||
if (error instanceof PermissionDeniedError) return { success: false, message: error.message }
|
||||
@@ -284,7 +284,7 @@ export async function updateSchoolAction(
|
||||
})
|
||||
)
|
||||
|
||||
revalidatePath("/admin/school/schools")
|
||||
await invalidateFor("school.school.update")
|
||||
return { success: true, message: "School updated" }
|
||||
} catch (error) {
|
||||
if (error instanceof PermissionDeniedError) return { success: false, message: error.message }
|
||||
@@ -302,8 +302,7 @@ export async function deleteSchoolAction(schoolId: string): Promise<ActionState<
|
||||
logAudit({ action: "school.delete", module: "school", targetId: schoolId, targetType: "school" })
|
||||
)
|
||||
|
||||
revalidatePath("/admin/school/schools")
|
||||
revalidatePath("/admin/school/grades")
|
||||
await invalidateFor("school.school.delete")
|
||||
return { success: true, message: "School deleted" }
|
||||
} catch (error) {
|
||||
if (error instanceof PermissionDeniedError) return { success: false, message: error.message }
|
||||
@@ -347,7 +346,7 @@ export async function createGradeAction(
|
||||
})
|
||||
)
|
||||
|
||||
revalidatePath("/admin/school/grades")
|
||||
await invalidateFor("school.grade.create")
|
||||
return { success: true, message: "Grade created" }
|
||||
} catch (error) {
|
||||
if (error instanceof PermissionDeniedError) return { success: false, message: error.message }
|
||||
@@ -392,7 +391,7 @@ export async function updateGradeAction(
|
||||
})
|
||||
)
|
||||
|
||||
revalidatePath("/admin/school/grades")
|
||||
await invalidateFor("school.grade.update")
|
||||
return { success: true, message: "Grade updated" }
|
||||
} catch (error) {
|
||||
if (error instanceof PermissionDeniedError) return { success: false, message: error.message }
|
||||
@@ -413,7 +412,7 @@ export async function deleteGradeAction(gradeId: string): Promise<ActionState<st
|
||||
targetType: "grade",
|
||||
})
|
||||
)
|
||||
revalidatePath("/admin/school/grades")
|
||||
await invalidateFor("school.grade.delete")
|
||||
return { success: true, message: "Grade deleted" }
|
||||
} catch (error) {
|
||||
if (error instanceof PermissionDeniedError) return { success: false, message: error.message }
|
||||
@@ -447,7 +446,7 @@ export async function promoteGradesAction(
|
||||
})
|
||||
)
|
||||
|
||||
revalidatePath("/admin/school/grades")
|
||||
await invalidateFor("school.grade.promote")
|
||||
return { success: true, message: `Promoted ${result.promoted} grades` }
|
||||
} catch (error) {
|
||||
if (error instanceof PermissionDeniedError) return { success: false, message: error.message }
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"use server";
|
||||
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { invalidateFor } from "@/shared/lib/cache";
|
||||
import {
|
||||
createStandardSchema,
|
||||
updateStandardSchema,
|
||||
@@ -99,7 +99,7 @@ export async function createStandardAction(
|
||||
return { success: false, message: t("error.unauthorized") };
|
||||
}
|
||||
const standard = await createStandard(parseResult.data, auth.userId);
|
||||
revalidatePath("/admin/standards");
|
||||
await invalidateFor("standards.create");
|
||||
return { success: true, data: { standard } };
|
||||
} catch (e) {
|
||||
return handleActionError(e);
|
||||
@@ -123,7 +123,7 @@ export async function updateStandardAction(
|
||||
if (!updated) {
|
||||
return { success: false, message: t("error.notFound") };
|
||||
}
|
||||
revalidatePath("/admin/standards");
|
||||
await invalidateFor("standards.update");
|
||||
return { success: true, data: { standard: updated } };
|
||||
} catch (e) {
|
||||
return handleActionError(e);
|
||||
@@ -137,7 +137,7 @@ export async function deactivateStandardAction(id: string): Promise<ActionState<
|
||||
try {
|
||||
await requirePermission(Permissions.STANDARD_MANAGE);
|
||||
await deactivateStandard(id);
|
||||
revalidatePath("/admin/standards");
|
||||
await invalidateFor("standards.deactivate");
|
||||
return { success: true, data: null };
|
||||
} catch (e) {
|
||||
return handleActionError(e);
|
||||
@@ -197,7 +197,7 @@ export async function linkPlanToStandardAction(
|
||||
parseResult.data.relationType,
|
||||
auth.userId,
|
||||
);
|
||||
revalidatePath(`/teacher/lesson-plans/${parseResult.data.planId}/edit`);
|
||||
await invalidateFor("standards.linkPlan", { planId: parseResult.data.planId });
|
||||
return { success: true, data: { link } };
|
||||
} catch (e) {
|
||||
return handleActionError(e);
|
||||
@@ -214,7 +214,7 @@ export async function unlinkPlanFromStandardAction(
|
||||
try {
|
||||
await requirePermission(Permissions.STANDARD_LINK);
|
||||
await unlinkPlanFromStandard(planId, standardId);
|
||||
revalidatePath(`/teacher/lesson-plans/${planId}/edit`);
|
||||
await invalidateFor("standards.unlinkPlan", { planId });
|
||||
return { success: true, data: null };
|
||||
} catch (e) {
|
||||
return handleActionError(e);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { requirePermission } from "@/shared/lib/auth-guard";
|
||||
import { Permissions } from "@/shared/types/permissions";
|
||||
import type { ActionState } from "@/shared/types/action-state";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { invalidateFor } from "@/shared/lib/cache";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { getCurrentStudentUser } from "@/modules/users/data-access";
|
||||
import { getGradeNameById } from "@/modules/school/data-access";
|
||||
@@ -66,7 +66,7 @@ export async function reorderChaptersAction(
|
||||
return { success: false, message: t("chapterNotBelong") };
|
||||
}
|
||||
await reorderChapters(chapterId, newIndex, parentId);
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
await invalidateFor("textbooks.chapter.reorder", { textbookId });
|
||||
return { success: true, message: t("chaptersReordered") };
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
@@ -96,7 +96,7 @@ export async function createTextbookAction(
|
||||
try {
|
||||
await requirePermission(Permissions.TEXTBOOK_CREATE);
|
||||
await createTextbook(parsed.data);
|
||||
revalidatePath("/teacher/textbooks");
|
||||
await invalidateFor("textbooks.create");
|
||||
return {
|
||||
success: true,
|
||||
message: t("createSuccess"),
|
||||
@@ -131,7 +131,7 @@ export async function updateTextbookAction(
|
||||
try {
|
||||
await requirePermission(Permissions.TEXTBOOK_UPDATE);
|
||||
await updateTextbook(parsed.data);
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
await invalidateFor("textbooks.update", { id: textbookId });
|
||||
return {
|
||||
success: true,
|
||||
message: t("updateSuccess"),
|
||||
@@ -148,7 +148,7 @@ export async function deleteTextbookAction(
|
||||
const t = await getTranslations("textbooks.action");
|
||||
await requirePermission(Permissions.TEXTBOOK_DELETE);
|
||||
await deleteTextbook(textbookId);
|
||||
revalidatePath("/teacher/textbooks");
|
||||
await invalidateFor("textbooks.delete");
|
||||
return {
|
||||
success: true,
|
||||
message: t("deleteSuccess"),
|
||||
@@ -183,7 +183,7 @@ export async function createChapterAction(
|
||||
try {
|
||||
await requirePermission(Permissions.TEXTBOOK_CREATE);
|
||||
await createChapter(parsed.data);
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
await invalidateFor("textbooks.chapter.create", { textbookId });
|
||||
return { success: true, message: t("chapterCreateSuccess") };
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
@@ -217,7 +217,7 @@ export async function updateChapterContentAction(
|
||||
return { success: false, message: t("chapterNotBelong") };
|
||||
}
|
||||
await updateChapterContent(parsed.data);
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
await invalidateFor("textbooks.chapter.update", { textbookId });
|
||||
return { success: true, message: t("contentUpdateSuccess") };
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
@@ -237,7 +237,7 @@ export async function deleteChapterAction(
|
||||
return { success: false, message: t("chapterNotBelong") };
|
||||
}
|
||||
await deleteChapter(chapterId);
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
await invalidateFor("textbooks.chapter.delete", { textbookId });
|
||||
return { success: true, message: t("chapterDeleteSuccess") };
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
@@ -274,7 +274,7 @@ export async function createKnowledgePointAction(
|
||||
return { success: false, message: t("chapterNotBelong") };
|
||||
}
|
||||
await createKnowledgePoint(parsed.data);
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
await invalidateFor("textbooks.knowledgePoint.create", { textbookId });
|
||||
return { success: true, message: t("kpCreateSuccess") };
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
@@ -294,7 +294,7 @@ export async function deleteKnowledgePointAction(
|
||||
return { success: false, message: t("kpNotBelong") };
|
||||
}
|
||||
await deleteKnowledgePoint(kpId);
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
await invalidateFor("textbooks.knowledgePoint.delete", { textbookId });
|
||||
return { success: true, message: t("kpDeleteSuccess") };
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
@@ -331,7 +331,7 @@ export async function updateKnowledgePointAction(
|
||||
return { success: false, message: t("kpNotBelong") };
|
||||
}
|
||||
await updateKnowledgePoint(parsed.data);
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
await invalidateFor("textbooks.knowledgePoint.update", { textbookId });
|
||||
return { success: true, message: t("kpUpdateSuccess") };
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
@@ -490,7 +490,7 @@ export async function createPrerequisiteAction(
|
||||
}
|
||||
|
||||
await createPrerequisite(parsed.data);
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
await invalidateFor("textbooks.prerequisite.create", { textbookId });
|
||||
return { success: true, message: t("prerequisiteCreated") };
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
@@ -536,7 +536,7 @@ export async function deletePrerequisiteAction(
|
||||
}
|
||||
|
||||
await deletePrerequisite(parsed.data);
|
||||
revalidatePath(`/teacher/textbooks/${textbookId}`);
|
||||
await invalidateFor("textbooks.prerequisite.delete", { textbookId });
|
||||
return { success: true, message: t("prerequisiteDeleted") };
|
||||
} catch (e) {
|
||||
return handleActionError(e)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
import { z } from "zod"
|
||||
|
||||
import { invalidateFor } from "@/shared/lib/cache"
|
||||
import { requirePermission, PermissionDeniedError } from "@/shared/lib/auth-guard"
|
||||
import { Permissions } from "@/shared/types/permissions"
|
||||
import type { ActionState } from "@/shared/types/action-state"
|
||||
@@ -54,8 +54,7 @@ export async function updateUserProfile(
|
||||
|
||||
await updateUserProfileById(ctx.userId, parsed.data)
|
||||
|
||||
revalidatePath("/profile")
|
||||
revalidatePath("/settings")
|
||||
await invalidateFor("users.update")
|
||||
|
||||
return { success: true, message: "Profile updated successfully" }
|
||||
} catch (e) {
|
||||
@@ -127,7 +126,7 @@ export async function importUsersAction(
|
||||
}
|
||||
|
||||
const result = await batchImportUsers(validation.valid)
|
||||
revalidatePath("/admin/users/import")
|
||||
await invalidateFor("users.import")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
@@ -180,7 +179,7 @@ export async function deleteUserAction(
|
||||
try {
|
||||
await requirePermission(Permissions.USER_MANAGE)
|
||||
await deleteUserById(userId)
|
||||
revalidatePath("/admin/users")
|
||||
await invalidateFor("users.delete")
|
||||
return { success: true, message: "用户已删除" }
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) {
|
||||
|
||||
Reference in New Issue
Block a user