File

src/module/student/student.controller.ts

Prefix

student

Index

Methods

Methods

Private Async checkUserCanExcuseOrThrow
checkUserCanExcuseOrThrow(undefined: CheckCanExcuseParams)

Checks if the given user is allowed to proceed with the request to change the attendance state with regard to the application settings.

Important: This does NOT check if the user is allowed in general (ie correct role, is tutor, ...). Those checks must still be performed by the corresponding route guard!

This checks if all the following conditions are met. If so an exception is thrown:

  • The application settings disallow non-admins to excuse a student.
  • The user making the request is not an admin.
  • The DTO would change the attendance state of a student to excused.
Parameters :
Name Type Optional
CheckCanExcuseParams No
Returns : Promise<void>
Async createManyStudents
createManyStudents(dto: CreateStudentsDTO)
Decorators :
@Post('/generate')
@UseGuards(HasRoleGuard, CreatedInOwnTutorialGuard)
@Roles(Role.ADMIN, Role.TUTOR)
@UsePipes(ValidationPipe)
Parameters :
Name Type Optional
dto CreateStudentsDTO No
Async createStudent
createStudent(dto: CreateStudentDTO)
Decorators :
@Post()
@UseGuards(HasRoleGuard, CreatedInOwnTutorialGuard)
@Roles(Role.ADMIN, Role.TUTOR)
@UsePipes(ValidationPipe)
Parameters :
Name Type Optional
dto CreateStudentDTO No
Returns : Promise<IStudent>
Async deleteStudent
deleteStudent(id: string)
Decorators :
@Delete('/:id')
@HttpCode(HttpStatus.NO_CONTENT)
@UseGuards(StudentGuard)
Parameters :
Name Type Optional
id string No
Returns : Promise<void>
Async getAllStudents
getAllStudents()
Decorators :
@Get()
@UseGuards(HasRoleGuard)
@Roles(Role.ADMIN, Role.EMPLOYEE)
Async getStudent
getStudent(id: string)
Decorators :
@Get('/:id')
@UseGuards(StudentGuard)
@AllowSubstitutes()
@AllowCorrectors()
Parameters :
Name Type Optional
id string No
Returns : Promise<IStudent>
Async updateAttendance
updateAttendance(id: string, dto: AttendanceDTO, request: ExpressRequest)
Decorators :
@Put('/:id/attendance')
@UseGuards(StudentGuard)
@Roles(Role.ADMIN, Role.EMPLOYEE)
@AllowSubstitutes()
@UsePipes(ValidationPipe)
Parameters :
Name Type Optional
id string No
dto AttendanceDTO No
request ExpressRequest No
Async updateCakeCount
updateCakeCount(id: string, dto: CakeCountDTO)
Decorators :
@Put('/:id/cakecount')
@HttpCode(HttpStatus.NO_CONTENT)
@UseGuards(StudentGuard)
@AllowSubstitutes()
@UsePipes(ValidationPipe)
Parameters :
Name Type Optional
id string No
dto CakeCountDTO No
Returns : Promise<void>
Async updatePresentationPoint
updatePresentationPoint(id: string, dto: PresentationPointsDTO)
Decorators :
@Put('/:id/presentation')
@HttpCode(HttpStatus.NO_CONTENT)
@UseGuards(StudentGuard)
@AllowSubstitutes()
@UsePipes(ValidationPipe)
Parameters :
Name Type Optional
id string No
dto PresentationPointsDTO No
Returns : Promise<void>
Async updateStudent
updateStudent(id: string, dto: CreateStudentDTO)
Decorators :
@Patch('/:id')
@UseGuards(StudentGuard)
@UsePipes(ValidationPipe)
Parameters :
Name Type Optional
id string No
dto CreateStudentDTO No
Returns : Promise<IStudent>
import {
    BadRequestException,
    Body,
    Controller,
    Delete,
    ForbiddenException,
    Get,
    HttpCode,
    HttpStatus,
    Param,
    Patch,
    Post,
    Put,
    Request,
    UseGuards,
    UsePipes,
    ValidationPipe,
} from '@nestjs/common';
import { Request as ExpressRequest } from 'express';
import { DateTime } from 'luxon';
import { AttendanceState, IAttendance } from 'shared/model/Attendance';
import { Role } from 'shared/model/Role';
import { IStudent } from 'shared/model/Student';
import { CreatedInOwnTutorialGuard } from '../../guards/created-in-own-tutorial.guard';
import { AllowCorrectors } from '../../guards/decorators/allowCorrectors.decorator';
import { AllowSubstitutes } from '../../guards/decorators/allowSubstitutes.decorator';
import { Roles } from '../../guards/decorators/roles.decorator';
import { HasRoleGuard } from '../../guards/has-role.guard';
import { StudentGuard } from '../../guards/student.guard';
import { SettingsService } from '../settings/settings.service';
import {
    AttendanceDTO,
    CakeCountDTO,
    CreateStudentDTO,
    CreateStudentsDTO,
    PresentationPointsDTO,
} from './student.dto';
import { StudentService } from './student.service';

interface CheckCanExcuseParams {
    dto: AttendanceDTO;
    studentId: string;
    user?: Express.User;
}

@Controller('student')
export class StudentController {
    constructor(
        private readonly studentService: StudentService,
        private readonly settingsService: SettingsService
    ) {}

    @Get()
    @UseGuards(HasRoleGuard)
    @Roles(Role.ADMIN, Role.EMPLOYEE)
    async getAllStudents(): Promise<IStudent[]> {
        const students = await this.studentService.findAll();

        return students.map((user) => user.toDTO());
    }

    @Post()
    @UseGuards(HasRoleGuard, CreatedInOwnTutorialGuard)
    @Roles(Role.ADMIN, Role.TUTOR)
    @UsePipes(ValidationPipe)
    async createStudent(@Body() dto: CreateStudentDTO): Promise<IStudent> {
        return await this.studentService.create(dto);
    }

    @Post('/generate')
    @UseGuards(HasRoleGuard, CreatedInOwnTutorialGuard)
    @Roles(Role.ADMIN, Role.TUTOR)
    @UsePipes(ValidationPipe)
    async createManyStudents(@Body() dto: CreateStudentsDTO): Promise<IStudent[]> {
        return await this.studentService.createMany(dto);
    }

    @Get('/:id')
    @UseGuards(StudentGuard)
    @AllowSubstitutes()
    @AllowCorrectors()
    async getStudent(@Param('id') id: string): Promise<IStudent> {
        const student = await this.studentService.findById(id);

        return student.toDTO();
    }

    @Patch('/:id')
    @UseGuards(StudentGuard)
    @UsePipes(ValidationPipe)
    async updateStudent(@Param('id') id: string, @Body() dto: CreateStudentDTO): Promise<IStudent> {
        return await this.studentService.update(id, dto);
    }

    @Delete('/:id')
    @HttpCode(HttpStatus.NO_CONTENT)
    @UseGuards(StudentGuard)
    async deleteStudent(@Param('id') id: string): Promise<void> {
        await this.studentService.delete(id);
    }

    @Put('/:id/attendance')
    @UseGuards(StudentGuard)
    @Roles(Role.ADMIN, Role.EMPLOYEE)
    @AllowSubstitutes()
    @UsePipes(ValidationPipe)
    async updateAttendance(
        @Param('id') id: string,
        @Body() dto: AttendanceDTO,
        @Request() request: ExpressRequest
    ): Promise<IAttendance> {
        await this.checkUserCanExcuseOrThrow({
            dto,
            studentId: id,
            user: request.user,
        });

        return await this.studentService.setAttendance(id, dto);
    }

    @Put('/:id/presentation')
    @HttpCode(HttpStatus.NO_CONTENT)
    @UseGuards(StudentGuard)
    @AllowSubstitutes()
    @UsePipes(ValidationPipe)
    async updatePresentationPoint(
        @Param('id') id: string,
        @Body() dto: PresentationPointsDTO
    ): Promise<void> {
        await this.studentService.setPresentationPoints(id, dto);
    }

    @Put('/:id/cakecount')
    @HttpCode(HttpStatus.NO_CONTENT)
    @UseGuards(StudentGuard)
    @AllowSubstitutes()
    @UsePipes(ValidationPipe)
    async updateCakeCount(@Param('id') id: string, @Body() dto: CakeCountDTO): Promise<void> {
        await this.studentService.setCakeCount(id, dto);
    }

    /**
     * Checks if the given user is allowed to proceed with the request to change the attendance state with regard to the application settings.
     *
     * __Important__: This does __NOT__ check if the user is allowed in general (ie correct role, is tutor, ...). Those checks must still be performed by the corresponding route guard!
     *
     * This checks if all the following conditions are met. If so an exception is thrown:
     * - The application settings disallow non-admins to excuse a student.
     * - The user making the request is __not__ an admin.
     * - The DTO would change the attendance state of a student to `excused`.
     *
     * @param params Must contain the `studentId`, the `dto` of the request and the `user` making the request (optional).
     *
     * @throws `BadRequestException` - If the given `user` is not defined.
     * @throws `ForbiddenException` - If the `user` is not allowed to proceed with the request (see above).
     */
    private async checkUserCanExcuseOrThrow({
        user,
        dto,
        studentId,
    }: CheckCanExcuseParams): Promise<void> {
        if (!user) {
            throw new BadRequestException('No user available in request.');
        }

        const settings = await this.settingsService.getClientSettings();
        const student = await this.studentService.findById(studentId);
        const wouldChangeAttendance =
            student.getAttendance(DateTime.fromISO(dto.date))?.state !== dto.state;

        if (!wouldChangeAttendance) {
            return;
        }

        if (
            !settings.canTutorExcuseStudents &&
            !user.roles.includes(Role.ADMIN) &&
            dto.state === AttendanceState.EXCUSED
        ) {
            throw new ForbiddenException('User is not allowed to excuse a student.');
        }
    }
}

results matching ""

    No results matching ""