feat(shared): add errors lib, question-content, and update permissions and UI
- Add errors lib for standardized error handling - Add question-content lib for question content processing - Update action-utils, ai/provider-config, auth-guard, permissions, types/permissions - Update UI sheet component - Update proxy middleware
This commit is contained in:
@@ -7,17 +7,12 @@ import {
|
||||
grades,
|
||||
parentStudentRelations,
|
||||
} from "@/shared/db/schema"
|
||||
import { eq, or } from "drizzle-orm"
|
||||
import { eq, inArray, or } from "drizzle-orm"
|
||||
import { getSession } from "@/shared/lib/session"
|
||||
import { PermissionDeniedError } from "@/shared/lib/errors"
|
||||
|
||||
export class PermissionDeniedError extends Error {
|
||||
constructor(permission: string) {
|
||||
super(
|
||||
`权限不足:需要 ${permission} 权限。请联系管理员授权或切换账号后重试。`
|
||||
)
|
||||
this.name = "PermissionDeniedError"
|
||||
}
|
||||
}
|
||||
// Re-export for backward compatibility (other modules still import from here)
|
||||
export { PermissionDeniedError } from "@/shared/lib/errors"
|
||||
|
||||
/**
|
||||
* Get the full authentication context for the current user.
|
||||
@@ -114,16 +109,26 @@ async function resolveDataScope(userId: string, roleNames: Role[]): Promise<Data
|
||||
}
|
||||
|
||||
// Student: can see data from their enrolled classes
|
||||
// Pre-resolve classIds here to avoid N+1 queries in data-access layer
|
||||
// Pre-resolve classIds and gradeIds here to avoid N+1 queries in data-access layer
|
||||
if (roleNames.includes("student")) {
|
||||
const enrolledClasses = await db
|
||||
.select({ classId: classEnrollments.classId })
|
||||
.select({ classId: classEnrollments.classId, gradeId: classes.gradeId })
|
||||
.from(classEnrollments)
|
||||
.innerJoin(classes, eq(classEnrollments.classId, classes.id))
|
||||
.where(eq(classEnrollments.studentId, userId))
|
||||
|
||||
const gradeIds = [
|
||||
...new Set(
|
||||
enrolledClasses
|
||||
.map((c) => c.gradeId)
|
||||
.filter((g): g is string => g !== null),
|
||||
),
|
||||
]
|
||||
|
||||
return {
|
||||
type: "class_members",
|
||||
classIds: enrolledClasses.map((c) => c.classId),
|
||||
gradeIds: gradeIds.length > 0 ? gradeIds : undefined,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +139,28 @@ async function resolveDataScope(userId: string, roleNames: Role[]): Promise<Data
|
||||
.from(parentStudentRelations)
|
||||
.where(eq(parentStudentRelations.parentId, userId))
|
||||
|
||||
return { type: "children", childrenIds: children.map((c) => c.studentId) }
|
||||
const childrenIds = children.map((c) => c.studentId)
|
||||
|
||||
// Pre-resolve gradeIds from children's enrolled classes
|
||||
let gradeIds: string[] | undefined
|
||||
if (childrenIds.length > 0) {
|
||||
const childrenClasses = await db
|
||||
.select({ gradeId: classes.gradeId })
|
||||
.from(classEnrollments)
|
||||
.innerJoin(classes, eq(classEnrollments.classId, classes.id))
|
||||
.where(inArray(classEnrollments.studentId, childrenIds))
|
||||
|
||||
const uniqueGradeIds = [
|
||||
...new Set(
|
||||
childrenClasses
|
||||
.map((c) => c.gradeId)
|
||||
.filter((g): g is string => g !== null),
|
||||
),
|
||||
]
|
||||
gradeIds = uniqueGradeIds.length > 0 ? uniqueGradeIds : undefined
|
||||
}
|
||||
|
||||
return { type: "children", childrenIds, gradeIds }
|
||||
}
|
||||
|
||||
// Fallback: only own data
|
||||
|
||||
Reference in New Issue
Block a user