import axios, { AxiosError } from 'axios'; import ora from 'ora'; import ApiRoute from '../sharedByClients/types/Dojo/ApiRoute'; import { StatusCodes } from 'http-status-codes'; import GitlabUser from '../shared/types/Gitlab/GitlabUser'; import ClientsSharedConfig from '../sharedByClients/config/ClientsSharedConfig'; import Assignment from '../sharedByClients/models/Assignment'; import DojoBackendResponse from '../shared/types/Dojo/DojoBackendResponse'; import Exercise from '../sharedByClients/models/Exercise'; import GitlabToken from '../shared/types/Gitlab/GitlabToken'; import User from '../sharedByClients/models/User'; import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode'; class DojoBackendManager { public getApiUrl(route: ApiRoute): string { return `${ ClientsSharedConfig.apiURL }${ route }`; } public async login(gitlabTokens: GitlabToken): Promise<User | undefined> { try { return (await axios.post<DojoBackendResponse<User>>(this.getApiUrl(ApiRoute.LOGIN), { accessToken : gitlabTokens.access_token, refreshToken: gitlabTokens.refresh_token })).data.data; } catch ( error ) { return undefined; } } public async refreshTokens(refreshToken: string): Promise<GitlabToken> { return (await axios.post<DojoBackendResponse<GitlabToken>>(this.getApiUrl(ApiRoute.REFRESH_TOKENS), { refreshToken: refreshToken })).data.data; } public async getAssignment(nameOrUrl: string): Promise<Assignment | undefined> { try { return (await axios.get<DojoBackendResponse<Assignment>>(this.getApiUrl(ApiRoute.ASSIGNMENT_GET).replace('{{nameOrUrl}}', encodeURIComponent(nameOrUrl)))).data.data; } catch ( error ) { return undefined; } } public async checkTemplateAccess(idOrNamespace: string, verbose: boolean = true): Promise<boolean> { const spinner: ora.Ora = ora('Checking template access'); if ( verbose ) { spinner.start(); } try { await axios.get(this.getApiUrl(ApiRoute.GITLAB_CHECK_TEMPLATE_ACCESS).replace('{{id}}', idOrNamespace)); if ( verbose ) { spinner.succeed('Template access granted'); } return true; } catch ( error ) { if ( verbose ) { if ( error instanceof AxiosError ) { if ( error.response ) { if ( error.response.status === StatusCodes.NOT_FOUND ) { spinner.fail(`Template not found or access denied. Please check the template ID or url. Also, please check that the template have public/internal visibility or that your and Dojo account (${ ClientsSharedConfig.gitlab.dojoAccount.username }) have at least reporter role to the template (if private).`); } else if ( error.response.status === StatusCodes.UNAUTHORIZED ) { spinner.fail(`Please check that the template have public/internal visibility or that your and Dojo account (${ ClientsSharedConfig.gitlab.dojoAccount.username }) have at least reporter role to the template (if private).`); } else { spinner.fail(`Template error: ${ error.response.statusText }`); } } } else { spinner.fail(`Template error: ${ error }`); } } return false; } } public async createAssignment(name: string, members: Array<GitlabUser>, templateIdOrNamespace: string | null, verbose: boolean = true): Promise<Assignment> { const spinner: ora.Ora = ora('Creating assignment...'); if ( verbose ) { spinner.start(); } try { const response = await axios.post<DojoBackendResponse<Assignment>>(this.getApiUrl(ApiRoute.ASSIGNMENT_CREATE), Object.assign({ name : name, members: JSON.stringify(members) }, templateIdOrNamespace ? { template: templateIdOrNamespace } : {})); if ( verbose ) { spinner.succeed(`Assignment successfully created`); } return response.data.data; } catch ( error ) { if ( verbose ) { if ( error instanceof AxiosError ) { if ( error.response ) { if ( error.response.status === StatusCodes.CONFLICT ) { spinner.fail(`The assignment name is already used. Please choose another one.`); } else { if ( (error.response.data as DojoBackendResponse<unknown>).code === DojoStatusCode.ASSIGNMENT_CREATION_GITLAB_ERROR ) { spinner.fail(`Assignment creation error: An unknown error occurred while creating the assignment on Gitlab. Please try again later or contact an administrator.`); } else { spinner.fail(`Assignment creation error: An unknown error occurred while creating the assignment on Dojo server. Please try again later or contact an administrator.`); } } } } else { spinner.fail(`Assignment creation error: unknown error`); } } throw error; } } public async createExercise(assignmentName: string, members: Array<GitlabUser>, verbose: boolean = true): Promise<Exercise> { const spinner: ora.Ora = ora('Creating exercise...'); if ( verbose ) { spinner.start(); } try { const response = await axios.post<DojoBackendResponse<Exercise>>(this.getApiUrl(ApiRoute.EXERCISE_CREATE).replace('{{nameOrUrl}}', encodeURIComponent(assignmentName)), { members: JSON.stringify(members) }); if ( verbose ) { spinner.succeed(`Exercise successfully created`); } return response.data.data; } catch ( error ) { if ( verbose ) { if ( error instanceof AxiosError ) { if ( error.response ) { if ( error.response.status === StatusCodes.INSUFFICIENT_SPACE_ON_RESOURCE ) { if ( error.response.data && (error.response.data as DojoBackendResponse<Array<GitlabUser>>).code === DojoStatusCode.MAX_EXERCISE_PER_ASSIGNMENT_REACHED ) { spinner.fail(`The following users have reached the maximum number of exercise of this assignment : ${ ((error.response.data as DojoBackendResponse<Array<GitlabUser>>).data as Array<GitlabUser>).map(user => user.name).join(', ') }.`); } else { spinner.fail(`You've already reached the max number of exercise of this assignment.`); } } else { if ( (error.response.data as DojoBackendResponse<unknown>).code === DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR ) { spinner.fail(`Exercise creation error: An unknown error occurred while creating the exercise on Gitlab. Please try again later or contact an administrator.`); } else { spinner.fail(`Exercise creation error: An unknown error occurred while creating the exercise on Dojo server. Please try again later or contact an administrator.`); } } } } else { spinner.fail(`Exercise creation error: unknown error`); } } throw error; } } public async changeAssignmentPublishedStatus(assignment: Assignment, publish: boolean, verbose: boolean = true) { const spinner: ora.Ora = ora('Changing published status...'); if ( verbose ) { spinner.start(); } try { await axios.patch<DojoBackendResponse<null>>(this.getApiUrl(publish ? ApiRoute.ASSIGNMENT_PUBLISH : ApiRoute.ASSIGNMENT_UNPUBLISH).replace('{{nameOrUrl}}', encodeURIComponent(assignment.name)), {}); if ( verbose ) { spinner.succeed(`Assignment ${ assignment.name } successfully ${ publish ? 'published' : 'unpublished' }`); } return; } catch ( error ) { if ( verbose ) { if ( error instanceof AxiosError && error.response ) { spinner.fail(`Assignment visibility change error: ${ error.response.statusText }`); } else { spinner.fail(`Assignment visibility change error: unknown error`); } } throw error; } } } export default new DojoBackendManager();