fix: align permission navigation and page access
This commit is contained in:
@@ -56,6 +56,16 @@ export class SchedulesController {
|
||||
);
|
||||
}
|
||||
|
||||
@Get('lookups')
|
||||
@RequirePermission('schedule:view')
|
||||
async getLookups(@Request() req: { user: RequestUser }) {
|
||||
const classIds = await this.service.getAccessibleClassIds(
|
||||
req.user.id,
|
||||
this.canManageAllSchedules(req),
|
||||
);
|
||||
return this.service.getLookups(classIds);
|
||||
}
|
||||
|
||||
@Get()
|
||||
@RequirePermission('schedule:view')
|
||||
async findAll(@Query() query: QueryScheduleDto, @Request() req: { user: RequestUser }) {
|
||||
|
||||
31
apps/server/src/schedules/schedules.lookups.spec.ts
Normal file
31
apps/server/src/schedules/schedules.lookups.spec.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { SchedulesService } from './schedules.service';
|
||||
|
||||
describe('SchedulesService permission-scoped lookups', () => {
|
||||
it('returns scoped classes and minimal classrooms for schedule viewers', async () => {
|
||||
const classRepo = {
|
||||
find: jest.fn().mockResolvedValue([{ id: 3, name: '三班', code: 'C3' }]),
|
||||
};
|
||||
const scheduleRepo = {
|
||||
createQueryBuilder: jest.fn().mockReturnValue({
|
||||
select: jest.fn().mockReturnThis(),
|
||||
addSelect: jest.fn().mockReturnThis(),
|
||||
innerJoin: jest.fn().mockReturnThis(),
|
||||
distinct: jest.fn().mockReturnThis(),
|
||||
orderBy: jest.fn().mockReturnThis(),
|
||||
addOrderBy: jest.fn().mockReturnThis(),
|
||||
getRawMany: jest.fn().mockResolvedValue([{ classroomId: 5, classroomName: '教室5', classroomBuilding: 'A' }]),
|
||||
}),
|
||||
};
|
||||
const service = new SchedulesService(
|
||||
scheduleRepo as never,
|
||||
classRepo as never,
|
||||
{} as never,
|
||||
{} as never,
|
||||
);
|
||||
|
||||
await expect(service.getLookups([3])).resolves.toEqual({
|
||||
classes: [{ id: 3, name: '三班', code: 'C3' }],
|
||||
classrooms: [{ id: 5, name: '教室5', building: 'A' }],
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
BadRequestException,
|
||||
} from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { In, Repository } from 'typeorm';
|
||||
import { ClassSchedule, Class, ClassroomRental, ClassTeacher } from '../entities';
|
||||
|
||||
import {
|
||||
@@ -33,6 +33,41 @@ export class SchedulesService {
|
||||
return [...new Set(assignments.map((assignment) => assignment.classId))];
|
||||
}
|
||||
|
||||
async getLookups(accessibleClassIds?: number[]) {
|
||||
const classes = accessibleClassIds
|
||||
? accessibleClassIds.length > 0
|
||||
? await this.classRepo.find({
|
||||
where: { id: In(accessibleClassIds) },
|
||||
select: ['id', 'name', 'code'],
|
||||
order: { name: 'ASC' },
|
||||
})
|
||||
: []
|
||||
: await this.classRepo.find({
|
||||
select: ['id', 'name', 'code'],
|
||||
order: { name: 'ASC' },
|
||||
});
|
||||
|
||||
const classroomRows = await this.scheduleRepo
|
||||
.createQueryBuilder('schedule')
|
||||
.select('classroom.id', 'classroomId')
|
||||
.addSelect('classroom.name', 'classroomName')
|
||||
.addSelect('classroom.building', 'classroomBuilding')
|
||||
.innerJoin('schedule.classroom', 'classroom')
|
||||
.distinct(true)
|
||||
.orderBy('classroom.building', 'ASC')
|
||||
.addOrderBy('classroom.name', 'ASC')
|
||||
.getRawMany();
|
||||
|
||||
return {
|
||||
classes,
|
||||
classrooms: classroomRows.map((row) => ({
|
||||
id: Number(row.classroomId),
|
||||
name: String(row.classroomName ?? ''),
|
||||
building: String(row.classroomBuilding ?? ''),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
async findAll(query: QueryScheduleDto, accessibleClassIds?: number[]) {
|
||||
const qb = this.scheduleRepo.createQueryBuilder('cs');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user