From 14e5e99c650a4b0f42a27b640d718208c9db0c6f Mon Sep 17 00:00:00 2001 From: Joel von der Weid <joel.von-der-weid@hesge.ch> Date: Tue, 12 Mar 2024 14:20:58 +0100 Subject: [PATCH] Add languages route and language in assignment creation --- ExpressAPI/assets/OpenAPI/OpenAPI.yaml | 41 +++++++++++++++++++ .../migration.sql | 2 +- ExpressAPI/prisma/schema.prisma | 1 + ExpressAPI/src/helpers/DojoValidators.ts | 23 ++++++++++- ExpressAPI/src/routes/AssignmentRoutes.ts | 20 +++++++-- 5 files changed, 81 insertions(+), 6 deletions(-) diff --git a/ExpressAPI/assets/OpenAPI/OpenAPI.yaml b/ExpressAPI/assets/OpenAPI/OpenAPI.yaml index 72494a9..43d8d1e 100644 --- a/ExpressAPI/assets/OpenAPI/OpenAPI.yaml +++ b/ExpressAPI/assets/OpenAPI/OpenAPI.yaml @@ -333,9 +333,21 @@ paths: type: boolean default: false description: Whether or not to use the Sonar integration to validate the assignment and exercise solutions + language: + type: string + default: other + description: Main programming language of the assignment + examples: + - java + - python + - csharp + - js + - c + - other required: - name + - language - members responses: '200': @@ -541,6 +553,35 @@ paths: $ref: '#/components/schemas/User' default: $ref: '#/components/responses/ERROR' + /assignments/languages: + get: + tags: + - Assignment + summary: Get all supported languages for assignments + description: | + This route can be used to get the list of all supported programming languages for which an assignment can be created. + security: + - Clients_Token: [ ] + responses: + '200': + description: OK + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/DojoBackendResponse' + - type: object + properties: + data: + type: array + items: + type: string + '401': + $ref: '#/components/responses/UNAUTHORIZED' + '404': + $ref: '#/components/responses/NOT_FOUND' + default: + $ref: '#/components/responses/ERROR' /exercises/{exerciseIdOrUrl}/assignment: get: tags: diff --git a/ExpressAPI/prisma/migrations/20240311145203_add_language_to_assignment/migration.sql b/ExpressAPI/prisma/migrations/20240311145203_add_language_to_assignment/migration.sql index 94b1ce8..e0ed08c 100644 --- a/ExpressAPI/prisma/migrations/20240311145203_add_language_to_assignment/migration.sql +++ b/ExpressAPI/prisma/migrations/20240311145203_add_language_to_assignment/migration.sql @@ -1,2 +1,2 @@ -- AlterTable -ALTER TABLE `Assignment` ADD COLUMN `language` ENUM('abap', 'ada', 'asm', 'bash', 'bqn', 'c', 'caml', 'cloudformation', 'csharp', 'css', 'cuda', 'dart', 'delphi', 'docker', 'erlang', 'f', 'fsharp', 'flex', 'fortran', 'futhark', 'go', 'groovy', 'haskell', 'hepial', 'json', 'jsp', 'java', 'js', 'julia', 'kotlin', 'kubernetes', 'latex', 'lisp', 'lua', 'matlab', 'objc', 'ocaml', 'pascal', 'pearl', 'perl', 'php', 'postscript', 'powershell', 'prolog', 'promela', 'python', 'r', 'ruby', 'rust', 'scala', 'sql', 'smalltalk', 'swift', 'terraform', 'text', 'ts', 'tsql', 'typst', 'vba', 'vbnet', 'web', 'xml', 'yaml', 'other') NOT NULL DEFAULT 'other'; +ALTER TABLE `Assignment` ADD COLUMN `language` ENUM('abap', 'ada', 'asm', 'bash', 'bqn', 'c', 'caml', 'cloudformation', 'cpp', 'csharp', 'css', 'cuda', 'dart', 'delphi', 'docker', 'erlang', 'f', 'fsharp', 'flex', 'fortran', 'futhark', 'go', 'groovy', 'haskell', 'hepial', 'json', 'jsp', 'java', 'js', 'julia', 'kotlin', 'kubernetes', 'latex', 'lisp', 'lua', 'matlab', 'objc', 'ocaml', 'pascal', 'pearl', 'perl', 'php', 'postscript', 'powershell', 'prolog', 'promela', 'python', 'r', 'ruby', 'rust', 'scala', 'sql', 'smalltalk', 'swift', 'terraform', 'text', 'ts', 'tsql', 'typst', 'vba', 'vbnet', 'web', 'xml', 'yaml', 'other') NOT NULL DEFAULT 'other'; diff --git a/ExpressAPI/prisma/schema.prisma b/ExpressAPI/prisma/schema.prisma index 95cc37e..5f2f6e8 100644 --- a/ExpressAPI/prisma/schema.prisma +++ b/ExpressAPI/prisma/schema.prisma @@ -111,6 +111,7 @@ enum Language { c caml cloudformation + cpp csharp css cuda diff --git a/ExpressAPI/src/helpers/DojoValidators.ts b/ExpressAPI/src/helpers/DojoValidators.ts index 652c600..d3a72b5 100644 --- a/ExpressAPI/src/helpers/DojoValidators.ts +++ b/ExpressAPI/src/helpers/DojoValidators.ts @@ -7,9 +7,11 @@ import ExerciseResultsFile from '../ import ParamsCallbackManager from '../middlewares/ParamsCallbackManager.js'; import ExerciseManager from '../managers/ExerciseManager.js'; import Toolbox from '../shared/helpers/Toolbox.js'; -import { CustomValidator, FieldMessageFactory, Meta, ValidationChain } from 'express-validator/lib/index.js'; +import { CustomValidator, FieldMessageFactory, Meta, ValidationChain, ErrorMessage } from 'express-validator/lib/index.js'; import { ErrorMessage } from 'express-validator/lib/base.js'; -import { BailOptions } from 'express-validator/lib/chain/index.js'; +import { StatusCodes } from 'http-status-codes'; +import { BailOptions, ValidationChain } from 'express-validator/src/chain'; +import { Language } from '@prisma/client'; declare type DojoMeta = Meta & { @@ -136,6 +138,23 @@ class DojoValidators { }); } }); + + readonly supportedLanguageValidator = this.toValidatorSchemaOptions({ + bail : true, + errorMessage: 'Unsupported language', + options : (_value, { + req, + path + }) => { + return new Promise((resolve, reject) => { + const language = this.getParamValue(req, path) as string; + if ( language ) { + (Object.values(Language).includes(language as keyof typeof Language) ? resolve(true) : reject()); + } + reject(); + }); + } + }); } diff --git a/ExpressAPI/src/routes/AssignmentRoutes.ts b/ExpressAPI/src/routes/AssignmentRoutes.ts index 84de91f..93faa05 100644 --- a/ExpressAPI/src/routes/AssignmentRoutes.ts +++ b/ExpressAPI/src/routes/AssignmentRoutes.ts @@ -23,6 +23,8 @@ import DojoModelsHelper from '../helpers/DojoModelsHelper.js'; import * as Gitlab from '@gitbeaker/rest'; import { GitbeakerRequestError } from '@gitbeaker/requester-utils'; import SharedConfig from '../shared/config/SharedConfig.js'; +import { AxiosError, HttpStatusCode } from 'axios'; +import { Language, Prisma } from '@prisma/client'; class AssignmentRoutes implements RoutesManager { @@ -46,6 +48,11 @@ class AssignmentRoutes implements RoutesManager { notEmpty : true, isBoolean: true, }, + language : { + trim : true, + notEmpty: true, + custom : DojoValidators.supportedLanguageValidator + } }; private readonly assignmentAddCorrigeValidator: ExpressValidator.Schema = { @@ -79,6 +86,8 @@ class AssignmentRoutes implements RoutesManager { backend.get('/assignments/:assignmentNameOrUrl', SecurityMiddleware.check(true), this.getAssignment.bind(this) as RequestHandler); backend.post('/assignments', SecurityMiddleware.check(true, SecurityCheckType.TEACHING_STAFF), ParamsValidatorMiddleware.validate(this.assignmentValidator), this.createAssignment.bind(this) as RequestHandler); + backend.get('/assignments/languages', this.getLanguages.bind(this) as RequestHandler); + backend.patch('/assignments/:assignmentNameOrUrl/publish', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), this.changeAssignmentPublishedStatus(true).bind(this) as RequestHandler); backend.patch('/assignments/:assignmentNameOrUrl/unpublish', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), this.changeAssignmentPublishedStatus(false).bind(this) as RequestHandler); @@ -133,7 +142,7 @@ class AssignmentRoutes implements RoutesManager { private async createAssignment(req: express.Request, res: express.Response) { const params: { - name: string, members: Array<Gitlab.UserSchema>, template: string, useSonar: string + name: string, members: Array<Gitlab.UserSchema>, template: string, useSonar: string, language: string } = req.body; const useSonar = params.useSonar === 'true'; @@ -190,6 +199,7 @@ class AssignmentRoutes implements RoutesManager { gitlabLastInfo : repository as unknown as Prisma.JsonObject, gitlabLastInfoDate: new Date(), useSonar : useSonar, + language : Language[params.language as keyof typeof Language], staff : { connectOrCreate: [ ...params.members.map(gitlabUser => { return { @@ -205,8 +215,8 @@ class AssignmentRoutes implements RoutesManager { } } }), 'Database error') as Assignment; - - req.session.sendResponse(res, StatusCodes.OK, assignment); + + req.session.sendResponse(res, StatusCodes.OK, assignment); } catch ( error ) { /* Empty */ } @@ -314,6 +324,10 @@ class AssignmentRoutes implements RoutesManager { return req.session.sendResponse(res, StatusCodes.OK); } + + private async getLanguages(req: express.Request, res: express.Response) { + req.session.sendResponse(res, StatusCodes.OK, Object.values(Language)); + } } -- GitLab