Skip to content
Snippets Groups Projects
Select Git revision
  • 7d54ac3265475047ce17702993d14bdbaa015392
  • main default protected
  • jw_sonar
  • v6.0.0 protected
  • bedran_exercise-list
  • ask-user-to-delete-exercises-on-duplicates
  • update-dependencies
  • jw_sonar_backup
  • add_route_assignments
  • 6.0.0-dev
  • 5.0.1
  • 5.0.0
  • 4.1.0
  • 4.0.0
  • 3.5.3
  • 3.5.2
  • 3.5.1
  • 3.5.0
  • 3.4.2
  • 3.4.1
  • 3.4.0
  • 3.3.0
  • 3.2.0
  • 3.1.3
  • 3.1.2
  • 3.1.1
  • 3.1.0
  • 3.0.1
  • 3.0.0
29 results

AssignmentRoutes.ts

Blame
  • AssignmentRoutes.ts 12.23 KiB
    import { Express }                    from 'express-serve-static-core';
    import express                        from 'express';
    import * as ExpressValidator          from 'express-validator';
    import { StatusCodes }                from 'http-status-codes';
    import RoutesManager                  from '../express/RoutesManager';
    import ParamsValidatorMiddleware      from '../middlewares/ParamsValidatorMiddleware';
    import SecurityMiddleware             from '../middlewares/SecurityMiddleware';
    import SecurityCheckType              from '../types/SecurityCheckType';
    import GitlabUser                     from '../shared/types/Gitlab/GitlabUser';
    import GitlabManager                  from '../managers/GitlabManager';
    import Config                         from '../config/Config';
    import GitlabMember                   from '../shared/types/Gitlab/GitlabMember';
    import GitlabAccessLevel              from '../shared/types/Gitlab/GitlabAccessLevel';
    import GitlabRepository               from '../shared/types/Gitlab/GitlabRepository';
    import { AxiosError, HttpStatusCode } from 'axios';
    import logger                         from '../shared/logging/WinstonLogger';
    import DojoValidators                 from '../helpers/DojoValidators';
    import { Prisma }                     from '@prisma/client';
    import db                             from '../helpers/DatabaseHelper';
    import { Assignment }                 from '../types/DatabaseTypes';
    import AssignmentManager              from '../managers/AssignmentManager';
    import GitlabVisibility               from '../shared/types/Gitlab/GitlabVisibility';
    import fs                             from 'fs';
    import path                           from 'path';
    import SharedAssignmentHelper         from '../shared/helpers/Dojo/SharedAssignmentHelper';
    import GlobalHelper                   from '../helpers/GlobalHelper';
    import DojoStatusCode                 from '../shared/types/Dojo/DojoStatusCode';
    
    class AssignmentRoutes implements RoutesManager {
        private readonly assignmentValidator: ExpressValidator.Schema = {
            name    : {
                trim    : true,
                notEmpty: true
            },
            members : {
                trim           : true,
                notEmpty       : true,
                customSanitizer: DojoValidators.jsonSanitizer
            },
            template: {
                trim           : true,
                custom         : DojoValidators.templateUrlValidator,
                customSanitizer: DojoValidators.templateUrlSanitizer
            }
        };
        
        registerOnBackend(backend: Express) {
            backend.get('/assignments/:assignmentNameOrUrl', SecurityMiddleware.check(true), this.getAssignment.bind(this));
            backend.post('/assignments', SecurityMiddleware.check(true, SecurityCheckType.TEACHING_STAFF), ParamsValidatorMiddleware.validate(this.assignmentValidator), this.createAssignment.bind(this));
            
            backend.patch('/assignments/:assignmentNameOrUrl/publish', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), this.publishAssignment.bind(this));
            backend.patch('/assignments/:assignmentNameOrUrl/unpublish', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), this.unpublishAssignment.bind(this));
            
            // backend.get('/assignments/:onlyMine', SecurityMiddleware.check(false, SecurityCheckType.TEACHING_STAFF),this.getAssignmentById.bind(this));
            backend.get('/assignmentss', SecurityMiddleware.check(false, SecurityCheckType.TEACHING_STAFF),this.getAssignmentById.bind(this));
        }
        // Get an assignment by its name or gitlab url
        private async getAssignment(req: express.Request, res: express.Response) {
            const assignment: Assignment | undefined = req.boundParams.assignment;
            
            if ( assignment && !assignment.published && !await AssignmentManager.isUserAllowedToAccessAssignment(assignment, req.session.profile) ) {
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                delete assignment.gitlabId;
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                delete assignment.gitlabLink;
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                delete assignment.gitlabCreationInfo;
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                delete assignment.gitlabLastInfo;
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                delete assignment.gitlabLastInfoDate;
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                delete assignment.staff;
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                delete assignment.exercises;
            }
            
            return assignment ? req.session.sendResponse(res, StatusCodes.OK, assignment) : res.status(StatusCodes.NOT_FOUND).send();
        }
        
        private async createAssignment(req: express.Request, res: express.Response) {
            const params: {
                name: string, members: Array<GitlabUser>, template: string
            } = req.body;
            params.members = [ await req.session.profile.gitlabProfile.value, ...params.members ];
            params.members = params.members.removeObjectDuplicates(gitlabUser => gitlabUser.id);
            
            
            let repository: GitlabRepository;
            try {
                repository = await GitlabManager.createRepository(params.name, Config.assignment.default.description.replace('{{ASSIGNMENT_NAME}}', params.name), Config.assignment.default.visibility, Config.assignment.default.initReadme, Config.gitlab.group.assignments, Config.assignment.default.sharedRunnersEnabled, Config.assignment.default.wikiEnabled, params.template);
            } catch ( error ) {
                logger.error('Repo creation error');
                logger.error(error);
                
                if ( error instanceof AxiosError ) {
                    if ( error.response?.data.message.name && error.response.data.message.name == 'has already been taken' ) {
                        return res.status(StatusCodes.CONFLICT).send();
                    }
                    
                    return res.status(error.response?.status ?? HttpStatusCode.InternalServerError).send();
                }
                
                return res.status(StatusCodes.INTERNAL_SERVER_ERROR).send();
            }
            
            await new Promise(resolve => setTimeout(resolve, Config.gitlab.repository.timeoutAfterCreation));
            
            try {
                await GitlabManager.protectBranch(repository.id, '*', true, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.OWNER);
                
                await GitlabManager.addRepositoryBadge(repository.id, Config.gitlab.badges.pipeline.link, Config.gitlab.badges.pipeline.imageUrl, 'Pipeline Status');
            } catch ( error ) {
                return GlobalHelper.repositoryCreationError('Repo params error', error, req, res, DojoStatusCode.ASSIGNMENT_CREATION_GITLAB_ERROR, DojoStatusCode.ASSIGNMENT_CREATION_INTERNAL_ERROR, repository);
            }
            
            try {
                await GitlabManager.deleteFile(repository.id, '.gitlab-ci.yml', 'Remove .gitlab-ci.yml');
            } catch ( error ) { /* empty */ }
            
            try {
                await GitlabManager.createFile(repository.id, '.gitlab-ci.yml', fs.readFileSync(path.join(__dirname, '../../assets/assignment_gitlab_ci.yml'), 'base64'), 'Add .gitlab-ci.yml (DO NOT MODIFY THIS FILE)');
            } catch ( error ) {
                return GlobalHelper.repositoryCreationError('CI file error', error, req, res, DojoStatusCode.ASSIGNMENT_CREATION_GITLAB_ERROR, DojoStatusCode.ASSIGNMENT_CREATION_INTERNAL_ERROR, repository);
            }
            
            try {
                await Promise.all(params.members.map(member => member.id).map(async (memberId: number): Promise<GitlabMember | false> => {
                    try {
                        return await GitlabManager.addRepositoryMember(repository.id, memberId, GitlabAccessLevel.DEVELOPER);
                    } catch ( error ) {
                        logger.error('Add member error');
                        logger.error(error);
                        return false;
                    }
                }));
                
                const assignment: Assignment = await db.assignment.create({
                    data: {
                        name              : repository.name,
                        gitlabId          : repository.id,
                        gitlabLink        : repository.web_url,
                        gitlabCreationInfo: repository as unknown as Prisma.JsonObject,
                        gitlabLastInfo    : repository as unknown as Prisma.JsonObject,
                        gitlabLastInfoDate: new Date(),
                        staff             : {
                            connectOrCreate: [ ...params.members.map(gitlabUser => {
                                return {
                                    create: {
                                        id            : gitlabUser.id,
                                        gitlabUsername: gitlabUser.name
                                    },
                                    where : {
                                        id: gitlabUser.id
                                    }
                                };
                            }) ]
                        }
                    }
                }) as unknown as Assignment;
                
                return req.session.sendResponse(res, StatusCodes.OK, assignment);
            } catch ( error ) {
                return GlobalHelper.repositoryCreationError('DB error', error, req, res, DojoStatusCode.ASSIGNMENT_CREATION_GITLAB_ERROR, DojoStatusCode.ASSIGNMENT_CREATION_INTERNAL_ERROR, repository);
            }
        }
        
        private async publishAssignment(req: express.Request, res: express.Response) {
            return this.changeAssignmentPublishedStatus(true)(req, res);
        }
        
        private async unpublishAssignment(req: express.Request, res: express.Response) {
            return this.changeAssignmentPublishedStatus(false)(req, res);
        }
        
        private changeAssignmentPublishedStatus(publish: boolean): (req: express.Request, res: express.Response) => Promise<void> {
            return async (req: express.Request, res: express.Response): Promise<void> => {
                if ( publish ) {
                    const isPublishable = await SharedAssignmentHelper.isPublishable(req.boundParams.assignment!.gitlabId);
                    if ( !isPublishable.isPublishable ) {
                        return req.session.sendResponse(res, StatusCodes.BAD_REQUEST, { lastPipeline: isPublishable.lastPipeline }, isPublishable.status?.message, isPublishable.status?.code);
                    }
                }
                
                try {
                    await GitlabManager.changeRepositoryVisibility(req.boundParams.assignment!.gitlabId, publish ? GitlabVisibility.INTERNAL : GitlabVisibility.PRIVATE);
                    
                    await db.assignment.update({
                        where: {
                            name: req.boundParams.assignment!.name
                        },
                        data : {
                            published: publish
                        }
                    });
                    
                    req.session.sendResponse(res, StatusCodes.OK);
                } catch ( error ) {
                    if ( error instanceof AxiosError ) {
                        res.status(error.response?.status ?? HttpStatusCode.InternalServerError).send();
                        return;
                    }
                    
                    logger.error(error);
                    res.status(StatusCodes.INTERNAL_SERVER_ERROR).send();
                }
            };
        }
        
        private async getAssignmentById(req : express.Request, res : express.Response) {
            // const onlyMine = req.boundParams.user?.id;
            // const users = await db.assignment.findMany();
            // console.log(onlyMine);
            // const assign = await db.user.findUnique({
            //     where: {
            //       id: onlyMine,
            //     },
            //     include: {
            //       assignments: true,
            //     },
            //   });
            const assign = await db.assignment.findMany();
            return req.session.sendResponse(res, StatusCodes.OK, assign);
        }
        
        // private async deleteAssignment(req : express.Request, res : express.Response) {
            
        // }
    }
    
    
    export default new AssignmentRoutes();