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