Select Git revision
DojoBackendManager.ts
DojoBackendManager.ts 13.24 KiB
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, language: string, members: Array<GitlabUser>, templateIdOrNamespace: string | null, sonar: boolean = false, sonarGate: string | undefined = undefined, sonarProfiles: string[] = [], 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,
language : language,
members : JSON.stringify(members),
useSonar : String(sonar),
sonarGate: sonarGate ?? '',
sonarProfiles : JSON.stringify(sonarProfiles),
}, 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;
}
}
public async linkUpdateCorrection(exerciseIdOrUrl: string, assignment: Assignment, isUpdate: boolean, verbose: boolean = true): Promise<boolean> {
const spinner: ora.Ora = ora(`${ isUpdate ? 'Updating' : 'Linking' } correction`);
if ( verbose ) {
spinner.start();
}
try {
const axiosFunction = isUpdate ? axios.patch : axios.post;
const route = isUpdate ? ApiRoute.ASSIGNMENT_CORRECTION_UPDATE : ApiRoute.ASSIGNMENT_CORRECTION_LINK;
await axiosFunction(this.getApiUrl(route).replace('{{assignmentNameOrUrl}}', encodeURIComponent(assignment.name)).replace('{{exerciseIdOrUrl}}', encodeURIComponent(exerciseIdOrUrl)), {
exerciseIdOrUrl: exerciseIdOrUrl
});
if ( verbose ) {
spinner.succeed(`Correction ${ isUpdate ? 'updated' : 'linked' }`);
}
return true;
} catch ( error ) {
if ( verbose ) {
if ( error instanceof AxiosError ) {
if ( error.response?.data ) {
if ( error.response.data.code === DojoStatusCode.ASSIGNMENT_EXERCISE_NOT_RELATED ) {
spinner.fail(`The exercise does not belong to the assignment.`);
} else if ( error.response.data.code === DojoStatusCode.EXERCISE_CORRECTION_ALREADY_EXIST ) {
spinner.fail(`This exercise is already labelled as a correction. If you want to update it, please use the update command.`);
} else if ( error.response.data.code === DojoStatusCode.EXERCISE_CORRECTION_NOT_EXIST ) {
spinner.fail(`The exercise is not labelled as a correction so it's not possible to update it.`);
}
} else {
spinner.fail(`Correction ${ isUpdate ? 'update' : 'link' } error: ${ error.response?.statusText }`);
}
} else {
spinner.fail(`Correction ${ isUpdate ? 'update' : 'link' } error: ${ error }`);
}
}
return false;
}
}
public async isSonarEnabled() {
const sonar = await axios.get<DojoBackendResponse<{ sonarEnabled: boolean }>>(this.getApiUrl(ApiRoute.SONAR));
return sonar.data.data.sonarEnabled;
}
public async getSonarLanguages() {
const sonar = await axios.get<DojoBackendResponse<{ languages: string[] }>>(this.getApiUrl(ApiRoute.SONAR));
return sonar.data.data.languages;
}
public async getLanguages() {
const resp = await axios.get<DojoBackendResponse<string[]>>(this.getApiUrl(ApiRoute.LANGUAGES));
return resp.data.data;
}
public async testSonarQualities(gate: string, profiles: string[]) {
const resp = await axios.post<DojoBackendResponse<{ valid: boolean, badProfiles: string[], badGate: string | undefined }>>(
this.getApiUrl(ApiRoute.SONAR_QUALITIES), {
gate: gate,
profiles: profiles,
});
return resp.data.data;
}
}
export default new DojoBackendManager();