feat: add CASL authorization and AI configuration

This commit is contained in:
2026-07-11 14:25:34 +08:00
parent 8f0991a51f
commit 1e1c476bc3
59 changed files with 7733 additions and 120 deletions

View File

@@ -26,8 +26,14 @@ import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { OperationLogsService } from '../operation-logs/operation-logs.service';
import { extractRequestInfo } from '../common/request-utils';
import { RequirePermission } from '../auth/decorators/permission.decorator';
import { AuthorizationService, CaslAction, SubjectName } from '../authorization';
import type { AuthenticatedUser } from '../authorization';
import * as ExcelJS from 'exceljs';
interface AuthenticatedRequest {
user: AuthenticatedUser;
}
@UseGuards(JwtAuthGuard)
@Controller('students')
export class StudentsController {
@@ -35,13 +41,14 @@ export class StudentsController {
private service: StudentsService,
private logService: OperationLogsService,
@InjectRepository(Organization) private organizationRepo: Repository<Organization>,
private authz: AuthorizationService,
) {}
private canManageAllStudents(user: { isSuperAdmin?: boolean; permissions?: string[] }): boolean {
private canManageAllStudents(req: AuthenticatedRequest): boolean {
return (
user.isSuperAdmin === true ||
user.permissions?.includes('student:edit') === true ||
user.permissions?.includes('class:edit') === true
this.authz.can(req, CaslAction.Manage, SubjectName.Student) ||
// Legacy: class:edit grants broad student access for teacher scoping
this.authz.can(req, CaslAction.Update, SubjectName.Class)
);
}
@@ -52,11 +59,11 @@ export class StudentsController {
@Query('status') status: string | undefined,
@Query('includeArchived') includeArchived: string | undefined,
@Query('organizationId') organizationId: string | undefined,
@Request() req: { user: { id: number; isSuperAdmin?: boolean; permissions?: string[] } },
@Request() req: AuthenticatedRequest,
) {
const classIds = await this.service.getAccessibleClassIds(
req.user.id,
this.canManageAllStudents(req.user),
this.canManageAllStudents(req),
);
return this.service.findAll(
{
@@ -78,7 +85,7 @@ export class StudentsController {
) {
const classIds = await this.service.getAccessibleClassIds(
req.user.id,
this.canManageAllStudents(req.user),
this.canManageAllStudents(req),
);
const students = await this.service.findAll(
{ includeArchived: includeArchived === 'true' },