diff --git a/ExpressAPI/.idea/jetbrainsConfiguration b/ExpressAPI/.idea/jetbrainsConfiguration index 4d703a2dd39ec0c2b71bbbbda8900588c4e360bd..ffc5d65f9f0f0e825688177425e526131aa84631 160000 --- a/ExpressAPI/.idea/jetbrainsConfiguration +++ b/ExpressAPI/.idea/jetbrainsConfiguration @@ -1 +1 @@ -Subproject commit 4d703a2dd39ec0c2b71bbbbda8900588c4e360bd +Subproject commit ffc5d65f9f0f0e825688177425e526131aa84631 diff --git a/ExpressAPI/.idea/jsLibraryMappings.xml b/ExpressAPI/.idea/jsLibraryMappings.xml new file mode 100644 index 0000000000000000000000000000000000000000..d23208fbb7168875464dd7aaff4169c37be615ea --- /dev/null +++ b/ExpressAPI/.idea/jsLibraryMappings.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="JavaScriptLibraryMappings"> + <includedPredefinedLibrary name="Node.js Core" /> + </component> +</project> \ No newline at end of file diff --git a/ExpressAPI/.idea/jsLinters/eslint.xml b/ExpressAPI/.idea/jsLinters/eslint.xml new file mode 100644 index 0000000000000000000000000000000000000000..541945bb0819b8ff4a3dae9431632ebd10e6f98b --- /dev/null +++ b/ExpressAPI/.idea/jsLinters/eslint.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="EslintConfiguration"> + <option name="fix-on-save" value="true" /> + </component> +</project> \ No newline at end of file diff --git a/ExpressAPI/src/InitialImports.ts b/ExpressAPI/src/InitialImports.ts index 7fd00732ce602000be8d23d218acc009c6652f8f..98e4273b1c3a1b46b6ef444a71a72bf8ae12fa6a 100644 --- a/ExpressAPI/src/InitialImports.ts +++ b/ExpressAPI/src/InitialImports.ts @@ -1,15 +1,15 @@ import path from 'node:path'; import cluster from 'node:cluster'; +import myEnv = require('dotenv'); +import dotenvExpand = require('dotenv-expand'); if ( cluster.isPrimary ) { if ( process.env.NODE_ENV && process.env.NODE_ENV === 'production' ) { - const myEnv = require('dotenv').config(); - require('dotenv-expand').expand(myEnv); + dotenvExpand.expand(myEnv.config()); } else { - require('dotenv').config({ path: path.join(__dirname, '../.env.keys') }); - const myEnv = require('dotenv').config({ DOTENV_KEY: process.env.DOTENV_KEY_DEVELOPMENT }); - require('dotenv-expand').expand(myEnv); + myEnv.config({ path: path.join(__dirname, '../.env.keys') }); + dotenvExpand.expand(myEnv.config({ DOTENV_KEY: process.env.DOTENV_KEY_DEVELOPMENT })); } } diff --git a/ExpressAPI/src/controllers/Session.ts b/ExpressAPI/src/controllers/Session.ts index 49e044eab67d18a2108e54ef54c1d4e59b6896bb..17efe6873ccc9edd605e74571b31cd9dc63fe6f3 100644 --- a/ExpressAPI/src/controllers/Session.ts +++ b/ExpressAPI/src/controllers/Session.ts @@ -41,7 +41,7 @@ class Session { } } - private static getToken(profileJson: any): string | null { + private static getToken(profileJson: unknown): string | null { return profileJson === null ? null : jwt.sign({ profile: profileJson }, Config.jwtConfig.secret, Config.jwtConfig.expiresIn > 0 ? { expiresIn: Config.jwtConfig.expiresIn } : {}); } @@ -52,7 +52,7 @@ class Session { try { reasonPhrase = getReasonPhrase(code); - } catch {} + } catch { /* empty */ } return { timestamp : (new Date()).toISOString(), @@ -67,8 +67,8 @@ class Session { Send a response to the client Information: Data could be a promise or an object. If it's a promise, we wait on the data to be resolved before sending the response */ - sendResponse(res: express.Response, code: number, data?: any, descriptionOverride?: string, internalCode?: number) { - Promise.resolve(data).then((toReturn: any) => { + sendResponse(res: express.Response, code: number, data?: unknown, descriptionOverride?: string, internalCode?: number) { + Promise.resolve(data).then((toReturn: unknown) => { this.getResponse(internalCode ?? code, toReturn, descriptionOverride).then(response => { res.status(code).json(response); }); diff --git a/ExpressAPI/src/helpers/DojoValidators.ts b/ExpressAPI/src/helpers/DojoValidators.ts index ccb2b6575b637cfe2cb226498cd0b24d93e43dc3..0293660deb7449cc45f47366e7fac2868c801f2e 100644 --- a/ExpressAPI/src/helpers/DojoValidators.ts +++ b/ExpressAPI/src/helpers/DojoValidators.ts @@ -5,13 +5,14 @@ import { BailOptions, ValidationChain } from 'expres import GitlabManager from '../managers/GitlabManager'; import express from 'express'; import SharedExerciseHelper from '../shared/helpers/Dojo/SharedExerciseHelper'; +import logger from '../shared/logging/WinstonLogger'; declare type DojoMeta = Meta & { req: express.Request }; -declare type DojoCustomValidator = (input: any, meta: DojoMeta) => any; +declare type DojoCustomValidator = (input: unknown, meta: DojoMeta) => unknown; declare type DojoCustomValidatorSchemaOptions = { errorMessage?: FieldMessageFactory | ErrorMessage, negated?: boolean, bail?: boolean | BailOptions, if?: CustomValidator | ValidationChain, options?: CustomValidator } @@ -22,7 +23,7 @@ class DojoValidators { return arg as unknown as DojoCustomValidatorSchemaOptions; } - private getParamValue(req: express.Request, path: string): any { + private getParamValue(req: express.Request, path: string): unknown { return 'body' in req && path in req.body ? req.body[path] : req.query[path]; } @@ -30,7 +31,9 @@ class DojoValidators { options: (value) => { try { return value == 'null' || value == 'undefined' || value == '' ? null : value; - } catch ( e ) { + } catch ( error ) { + logger.error(`null sanitizer error: ${ error }`); + return value; } } @@ -39,7 +42,7 @@ class DojoValidators { readonly jsonSanitizer = this.toValidatorSchemaOptions({ options: (value) => { try { - return JSON.parse(value); + return JSON.parse(value as string); } catch ( e ) { return value; } @@ -54,7 +57,7 @@ class DojoValidators { path }) => { return new Promise((resolve, reject) => { - const template = this.getParamValue(req, path); + const template = this.getParamValue(req, path) as string; if ( template ) { GitlabManager.checkTemplateAccess(template, req).then((templateAccess) => { templateAccess !== StatusCodes.OK ? reject() : resolve(true); @@ -77,9 +80,11 @@ class DojoValidators { } else { return Config.assignment.default.template; } - } catch ( e ) { } + } catch ( error ) { + logger.error(`Template url sanitizer error: ${ error }`); - return value; + return value; + } } }); @@ -91,7 +96,7 @@ class DojoValidators { path }) => { return new Promise((resolve, reject) => { - const results = this.getParamValue(req, path); + const results = this.getParamValue(req, path) as string; if ( results ) { SharedExerciseHelper.validateResultFile(results, false).isValid ? resolve(true) : reject(); } else { diff --git a/ExpressAPI/src/helpers/GlobalHelper.ts b/ExpressAPI/src/helpers/GlobalHelper.ts index c97328d8e5cbc2d99b7339da2a94219e4ef01618..8a425a0d6e27b94ba6078da3b0e9bfa4f1e0ea88 100644 --- a/ExpressAPI/src/helpers/GlobalHelper.ts +++ b/ExpressAPI/src/helpers/GlobalHelper.ts @@ -8,7 +8,7 @@ import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode'; class GlobalHelper { - async repositoryCreationError(message: string, error: any, req: express.Request, res: express.Response, gitlabError: DojoStatusCode, internalError: DojoStatusCode, repositoryToRemove?: GitlabRepository): Promise<void> { + async repositoryCreationError(message: string, error: unknown, req: express.Request, res: express.Response, gitlabError: DojoStatusCode, internalError: DojoStatusCode, repositoryToRemove?: GitlabRepository): Promise<void> { logger.error(message); logger.error(error); @@ -26,7 +26,7 @@ class GlobalHelper { } return req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, {}, `Unknown error: ${ message }`, internalError); - }; + } } diff --git a/ExpressAPI/src/managers/GitlabManager.ts b/ExpressAPI/src/managers/GitlabManager.ts index 0c93da87efa87ca244f7a11d21d831ccb7c1bc16..80ac7427fec1bf79d6e7d6b414734c286b1c021e 100644 --- a/ExpressAPI/src/managers/GitlabManager.ts +++ b/ExpressAPI/src/managers/GitlabManager.ts @@ -29,32 +29,31 @@ class GitlabManager { DojoAuthorizationValue : `Bearer ${ token }` } })).data; - } catch ( e ) { } - - return undefined; + } catch ( e ) { + return undefined; + } } public async getUserById(id: number): Promise<GitlabUser | undefined> { try { - const params: any = {}; - const user = (await axios.get<GitlabUser>(`${ this.getApiUrl(GitlabRoute.USERS_GET) }/${ String(id) }`, { params: params })).data; + const user = (await axios.get<GitlabUser>(`${ this.getApiUrl(GitlabRoute.USERS_GET) }/${ String(id) }`)).data; return user.id === id ? user : undefined; - } catch ( e ) { } - - return undefined; + } catch ( e ) { + return undefined; + } } public async getUserByUsername(username: string): Promise<GitlabUser | undefined> { try { - const params: any = {}; + const params: Record<string, string> = {}; params['search'] = username; const user = (await axios.get<Array<GitlabUser>>(this.getApiUrl(GitlabRoute.USERS_GET), { params: params })).data[0]; return user.username === username ? user : undefined; - } catch ( e ) { } - - return undefined; + } catch ( e ) { + return undefined; + } } async getRepository(idOrNamespace: string): Promise<GitlabRepository> { @@ -185,15 +184,15 @@ class GitlabManager { } async getRepositoryTree(repoId: number, recursive: boolean = true, branch: string = 'main'): Promise<Array<GitlabTreeFile>> { - let address: string | undefined = this.getApiUrl(GitlabRoute.REPOSITORY_TREE).replace('{{id}}', String(repoId)); - let params: any = { + const address: string | undefined = this.getApiUrl(GitlabRoute.REPOSITORY_TREE).replace('{{id}}', String(repoId)); + let params: Partial<parseLinkHeader.Link | { recursive: boolean, per_page: number }> | undefined = { pagination: 'keyset', recursive : recursive, per_page : 100, ref : branch }; - let results: Array<GitlabTreeFile> = []; + const results: Array<GitlabTreeFile> = []; while ( params !== undefined ) { const response = await axios.get<Array<GitlabTreeFile>>(address, { diff --git a/ExpressAPI/src/managers/UserManager.ts b/ExpressAPI/src/managers/UserManager.ts index b69705e1e6b5c65c29efe2a0590b27b7a51c48b2..686ee267551004d22b1745e93f343c30c21aec02 100644 --- a/ExpressAPI/src/managers/UserManager.ts +++ b/ExpressAPI/src/managers/UserManager.ts @@ -24,7 +24,7 @@ class UserManager { }) as unknown as User ?? undefined; } - async getUpdateFromGitlabProfile(gitlabProfile: GitlabProfile, refreshToken: string): Promise<User> { + async getUpdateFromGitlabProfile(gitlabProfile: GitlabProfile): Promise<User> { await db.user.upsert({ where : { id: gitlabProfile.id diff --git a/ExpressAPI/src/middlewares/ParamsCallbackManager.ts b/ExpressAPI/src/middlewares/ParamsCallbackManager.ts index e81e172e444e0ccaf8723fef8a31a658dbdf2eb1..9af8f193cba8598dbddaf8d710a6a343e971f0bb 100644 --- a/ExpressAPI/src/middlewares/ParamsCallbackManager.ts +++ b/ExpressAPI/src/middlewares/ParamsCallbackManager.ts @@ -5,16 +5,16 @@ import ExerciseManager from '../managers/ExerciseManager'; import AssignmentManager from '../managers/AssignmentManager'; -type GetFunction = (id: string | number, ...args: Array<any>) => Promise<any> +type GetFunction = (id: string | number, ...args: Array<unknown>) => Promise<unknown> class ParamsCallbackManager { - protected listenParam(paramName: string, backend: Express, getFunction: GetFunction, args: Array<any>, indexName: string) { + protected listenParam(paramName: string, backend: Express, getFunction: GetFunction, args: Array<unknown>, indexName: string) { backend.param(paramName, (req: express.Request, res: express.Response, next: express.NextFunction, id: string | number) => { getFunction(id, ...args).then(result => { if ( result ) { this.initBoundParams(req); - (req.boundParams as any)[indexName] = result; + (req.boundParams as Record<string, unknown>)[indexName] = result; next(); } else { diff --git a/ExpressAPI/src/routes/AssignmentRoutes.ts b/ExpressAPI/src/routes/AssignmentRoutes.ts index e4eb82bfa416c6fcfb1062b84883551c9b821988..025dc331c72b2a94258e472fb488ef55266896f8 100644 --- a/ExpressAPI/src/routes/AssignmentRoutes.ts +++ b/ExpressAPI/src/routes/AssignmentRoutes.ts @@ -58,18 +58,25 @@ class AssignmentRoutes implements RoutesManager { 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; } diff --git a/ExpressAPI/src/routes/ExerciseRoutes.ts b/ExpressAPI/src/routes/ExerciseRoutes.ts index 8bc2e8a43832d6d59e8fb253d6d857fad24de290..1b9bc1d28023449c88f8cd065635f6cfadaa6f6b 100644 --- a/ExpressAPI/src/routes/ExerciseRoutes.ts +++ b/ExpressAPI/src/routes/ExerciseRoutes.ts @@ -29,6 +29,7 @@ import AssignmentFile from '../shared/types/Dojo/AssignmentFile'; import ExerciseResultsFile from '../shared/types/Dojo/ExerciseResultsFile'; import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode'; import GlobalHelper from '../helpers/GlobalHelper'; +import { IFileDirStat } from '../shared/helpers/recursiveFilesStats/RecursiveFilesStats'; class ExerciseRoutes implements RoutesManager { @@ -187,8 +188,8 @@ class ExerciseRoutes implements RoutesManager { const repoTree: Array<GitlabTreeFile> = await GitlabManager.getRepositoryTree(req.boundParams.exercise!.assignment.gitlabId); let assignmentHjsonFile!: GitlabFile; - let immutableFiles: Array<GitlabFile> = await Promise.all(Config.assignment.baseFiles.map(async (baseFile: string) => { - let file = await GitlabManager.getFile(req.boundParams.exercise!.assignment.gitlabId, baseFile); + const immutableFiles: Array<GitlabFile> = await Promise.all(Config.assignment.baseFiles.map(async (baseFile: string) => { + const file = await GitlabManager.getFile(req.boundParams.exercise!.assignment.gitlabId, baseFile); if ( baseFile === Config.assignment.filename ) { assignmentHjsonFile = file; @@ -220,7 +221,7 @@ class ExerciseRoutes implements RoutesManager { } private async createResult(req: express.Request, res: express.Response) { - const params: { exitCode: number, commit: any, results: ExerciseResultsFile, files: any, archiveBase64: string } = req.body; + const params: { exitCode: number, commit: Record<string, string>, results: ExerciseResultsFile, files: Array<IFileDirStat>, archiveBase64: string } = req.body; const exercise: Exercise = req.boundParams.exercise!; const result = await db.result.create({ diff --git a/ExpressAPI/src/routes/SessionRoutes.ts b/ExpressAPI/src/routes/SessionRoutes.ts index 0479205b47fa69630d954e3c6e08aa703f716043..29ebdfbacc5578ec02b597af6d09539903c9a2a5 100644 --- a/ExpressAPI/src/routes/SessionRoutes.ts +++ b/ExpressAPI/src/routes/SessionRoutes.ts @@ -46,7 +46,7 @@ class SessionRoutes implements RoutesManager { const gitlabUser = await GitlabManager.getUserProfile(params.accessToken); if ( gitlabUser ) { - req.session.profile = await UserManager.getUpdateFromGitlabProfile(gitlabUser, params.refreshToken); + req.session.profile = await UserManager.getUpdateFromGitlabProfile(gitlabUser); req.session.sendResponse(res, StatusCodes.OK); return; diff --git a/ExpressAPI/src/shared b/ExpressAPI/src/shared index 4a5eb68209ae9204b6d4cc8020bd62cf6a5be989..101cc26895eb0b5fe97e03bb96039e0cddd94391 160000 --- a/ExpressAPI/src/shared +++ b/ExpressAPI/src/shared @@ -1 +1 @@ -Subproject commit 4a5eb68209ae9204b6d4cc8020bd62cf6a5be989 +Subproject commit 101cc26895eb0b5fe97e03bb96039e0cddd94391