diff --git a/ExpressAPI/src/helpers/GlobalHelper.ts b/ExpressAPI/src/helpers/GlobalHelper.ts index 00f0933829237729892e09281787c33661d02fa6..85c07fd2821c9c47352d855830b04400341d5897 100644 --- a/ExpressAPI/src/helpers/GlobalHelper.ts +++ b/ExpressAPI/src/helpers/GlobalHelper.ts @@ -2,31 +2,40 @@ import express from 'express'; import logger from '../shared/logging/WinstonLogger'; import GitlabManager from '../managers/GitlabManager'; import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode'; -import { StatusCodes } from 'http-status-codes'; +import { StatusCodes } from 'http-status-codes'; import { GitbeakerRequestError } from '@gitbeaker/requester-utils'; -import * as Gitlab from '@gitbeaker/rest'; +import * as Gitlab from '@gitbeaker/rest'; class GlobalHelper { - async repositoryCreationError(message: string, error: unknown, req: express.Request, res: express.Response, gitlabError: DojoStatusCode, internalError: DojoStatusCode, repositoryToRemove?: Gitlab.ProjectSchema): Promise<void> { - logger.error(message); - logger.error(JSON.stringify(error)); + repoCreationFnExecCreator(req: express.Request, res: express.Response, gitlabError: DojoStatusCode, internalError: DojoStatusCode, repositoryToRemove?: Gitlab.ProjectSchema) { + return async (toExec: () => Promise<unknown>, errorMessage?: string) => { + try { + return await toExec(); + } catch ( error ) { + if ( errorMessage ) { + logger.error(errorMessage); + logger.error(JSON.stringify(error)); - try { - if ( repositoryToRemove ) { - await GitlabManager.deleteRepository(repositoryToRemove.id); - } - } catch ( deleteError ) { - logger.error('Repository deletion error'); - logger.error(JSON.stringify(deleteError)); - } + try { + if ( repositoryToRemove ) { + await GitlabManager.deleteRepository(repositoryToRemove.id); + } + } catch ( deleteError ) { + logger.error('Repository deletion error'); + logger.error(JSON.stringify(deleteError)); + } - if ( error instanceof GitbeakerRequestError ) { - return req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, {}, `Unknown gitlab error: ${ message }`, gitlabError); - return; - } + if ( error instanceof GitbeakerRequestError ) { + req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, {}, `Unknown gitlab error: ${ errorMessage }`, gitlabError); + throw error; + } - return req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, {}, `Unknown error: ${ message }`, internalError); + req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, {}, `Unknown error: ${ errorMessage }`, internalError); + throw error; + } + } + }; } } diff --git a/ExpressAPI/src/routes/AssignmentRoutes.ts b/ExpressAPI/src/routes/AssignmentRoutes.ts index 796cc0247e1e0daf882d5b4ad1184fc450082bfd..fddbcb3c29b866264d05c4d1b18574ac87c17ed9 100644 --- a/ExpressAPI/src/routes/AssignmentRoutes.ts +++ b/ExpressAPI/src/routes/AssignmentRoutes.ts @@ -109,26 +109,15 @@ class AssignmentRoutes implements RoutesManager { await new Promise(resolve => setTimeout(resolve, Config.gitlab.repository.timeoutAfterCreation)); - try { - await GitlabManager.protectBranch(repository.id, '*', true, Gitlab.AccessLevel.DEVELOPER, Gitlab.AccessLevel.DEVELOPER, Gitlab.AccessLevel.ADMIN); - - 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); - } + const repoCreationFnExec = GlobalHelper.repoCreationFnExecCreator(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 */ } + await repoCreationFnExec(() => GitlabManager.protectBranch(repository.id, '*', true, Gitlab.AccessLevel.DEVELOPER, Gitlab.AccessLevel.DEVELOPER, Gitlab.AccessLevel.ADMIN), 'Branch protection modification error'); + await repoCreationFnExec(() => GitlabManager.addRepositoryBadge(repository.id, Config.gitlab.badges.pipeline.link, Config.gitlab.badges.pipeline.imageUrl, 'Pipeline Status'), 'Pipeline badge addition error'); + await repoCreationFnExec(() => GitlabManager.deleteFile(repository.id, '.gitlab-ci.yml', 'Remove .gitlab-ci.yml')); + await repoCreationFnExec(() => 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)'), 'CI/CD file creation error'); - 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<Gitlab.MemberSchema | false> => { + await repoCreationFnExec(() => Promise.all(params.members.map(member => member.id).map(async (memberId: number): Promise<Gitlab.MemberSchema | false> => { try { return await GitlabManager.addRepositoryMember(repository.id, memberId, Gitlab.AccessLevel.DEVELOPER); } catch ( error ) { @@ -136,35 +125,35 @@ class AssignmentRoutes implements RoutesManager { logger.error(JSON.stringify(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; + })), 'Add repository members error'); + + const assignment: Assignment = await repoCreationFnExec(() => 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 + } + }; + }) ] + } + } + }), 'Database error') 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); + /* Empty */ } } diff --git a/ExpressAPI/src/routes/ExerciseRoutes.ts b/ExpressAPI/src/routes/ExerciseRoutes.ts index 665e73491e8c97c1954f46ffced50be29c9625c2..4347f61d9b88d4e7c03202f352192980fac9d6a3 100644 --- a/ExpressAPI/src/routes/ExerciseRoutes.ts +++ b/ExpressAPI/src/routes/ExerciseRoutes.ts @@ -158,28 +158,21 @@ class ExerciseRoutes implements RoutesManager { await new Promise(resolve => setTimeout(resolve, Config.gitlab.repository.timeoutAfterCreation)); - try { - await GitlabManager.protectBranch(repository.id, '*', false, Gitlab.AccessLevel.DEVELOPER, Gitlab.AccessLevel.DEVELOPER, Gitlab.AccessLevel.ADMIN); + const repoCreationFnExec = GlobalHelper.repoCreationFnExecCreator(req, res, DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR, DojoStatusCode.EXERCISE_CREATION_INTERNAL_ERROR, repository); - await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_EXERCISE_ID', exerciseId, false, true); - await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_SECRET', secret, false, true); - await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_RESULTS_FOLDER', Config.exercise.pipelineResultsFolder, false, false); + try { + await repoCreationFnExec(() => GitlabManager.protectBranch(repository.id, '*', false, Gitlab.AccessLevel.DEVELOPER, Gitlab.AccessLevel.DEVELOPER, Gitlab.AccessLevel.ADMIN), 'Branch protection modification error'); + await repoCreationFnExec(() => GitlabManager.addRepositoryBadge(repository.id, Config.gitlab.badges.pipeline.link, Config.gitlab.badges.pipeline.imageUrl, 'Pipeline Status'), 'Pipeline badge addition error'); - await GitlabManager.addRepositoryBadge(repository.id, Config.gitlab.badges.pipeline.link, Config.gitlab.badges.pipeline.imageUrl, 'Pipeline Status'); - } catch ( error ) { - await GlobalHelper.repositoryCreationError('Repo params error', error, req, res, DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR, DojoStatusCode.EXERCISE_CREATION_INTERNAL_ERROR, repository); - return; - } + await repoCreationFnExec(async () => { + await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_EXERCISE_ID', exerciseId, false, true); + await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_SECRET', secret, false, true); + await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_RESULTS_FOLDER', Config.exercise.pipelineResultsFolder, false, false); + }, 'Pipeline variables addition error'); - try { - await GitlabManager.updateFile(repository.id, '.gitlab-ci.yml', fs.readFileSync(path.join(__dirname, '../../assets/exercise_gitlab_ci.yml'), 'base64'), 'Add .gitlab-ci.yml (DO NOT MODIFY THIS FILE)'); - } catch ( error ) { - await GlobalHelper.repositoryCreationError('CI file update error', error, req, res, DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR, DojoStatusCode.EXERCISE_CREATION_INTERNAL_ERROR, repository); - return; - } + await repoCreationFnExec(() => GitlabManager.updateFile(repository.id, '.gitlab-ci.yml', fs.readFileSync(path.join(__dirname, '../../assets/exercise_gitlab_ci.yml'), 'base64'), 'Add .gitlab-ci.yml (DO NOT MODIFY THIS FILE)'), 'CI/CD file update error'); - try { - await Promise.all([ ...new Set([ ...assignment.staff.map(user => user.id), ...params.members.map(member => member.id) ]) ].map(async (memberId: number): Promise<Gitlab.MemberSchema | false> => { + await repoCreationFnExec(async () => Promise.all([ ...new Set([ ...assignment.staff.map(user => user.id), ...params.members.map(member => member.id) ]) ].map(async (memberId: number): Promise<Gitlab.MemberSchema | false> => { try { return await GitlabManager.addRepositoryMember(repository.id, memberId, Gitlab.AccessLevel.DEVELOPER); } catch ( error ) { @@ -187,40 +180,38 @@ class ExerciseRoutes implements RoutesManager { logger.error(JSON.stringify(error)); return false; } - })); - - const exercise: Exercise = await db.exercise.create({ - data: { - id : exerciseId, - assignmentName : assignment.name, - name : repository.name, - secret : secret, - gitlabId : repository.id, - gitlabLink : repository.web_url, - gitlabCreationInfo: repository as unknown as Prisma.JsonObject, - gitlabLastInfo : repository as unknown as Prisma.JsonObject, - gitlabLastInfoDate: new Date(), - members : { - connectOrCreate: [ ...params.members.map(gitlabUser => { - return { - create: { - id : gitlabUser.id, - gitlabUsername: gitlabUser.name - }, - where : { - id: gitlabUser.id - } - }; - }) ] - } - } - }) as unknown as Exercise; - - req.session.sendResponse(res, StatusCodes.OK, exercise); - return; + })), 'Add repository members error'); + + const exercise: Exercise = await repoCreationFnExec(() => db.exercise.create({ + data: { + id : exerciseId, + assignmentName : assignment.name, + name : repository.name, + secret : secret, + gitlabId : repository.id, + gitlabLink : repository.web_url, + gitlabCreationInfo: repository as unknown as Prisma.JsonObject, + gitlabLastInfo : repository as unknown as Prisma.JsonObject, + gitlabLastInfoDate: new Date(), + members : { + connectOrCreate: [ ...params.members.map(gitlabUser => { + return { + create: { + id : gitlabUser.id, + gitlabUsername: gitlabUser.name + }, + where : { + id: gitlabUser.id + } + }; + }) ] + } + } + })) as Exercise; + + return req.session.sendResponse(res, StatusCodes.OK, exercise); } catch ( error ) { - await GlobalHelper.repositoryCreationError('DB error', error, req, res, DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR, DojoStatusCode.EXERCISE_CREATION_INTERNAL_ERROR, repository); - return; + /* Empty */ } }