Skip to content
Snippets Groups Projects
Commit 28bd8ec8 authored by michael.minelli's avatar michael.minelli
Browse files

Add Exercice route and manager + Exercice creation

parent a39ad1e6
No related branches found
No related tags found
No related merge requests found
import Exercice from '../models/Exercice';
class ExerciceManager {
private static _instance: ExerciceManager;
private constructor() { }
public static get instance(): ExerciceManager {
if ( !ExerciceManager._instance ) {
ExerciceManager._instance = new ExerciceManager();
}
return ExerciceManager._instance;
}
createObjectFromRawSql(raw: any): Exercice {
const exercice = Exercice.createFromSql(raw);
exercice.exerciceGitlabCreationInfo = raw.exerciceGitlabCreationInfo;
exercice.exerciceGitlabLastInfo = raw.exerciceGitlabLastInfo;
return exercice;
}
}
export default ExerciceManager.instance;
import Model from './Model';
import db from '../helpers/DatabaseHelper';
import GitlabRepository from '../shared/types/Gitlab/GitlabRepository';
class Exercice extends Model {
static tableName: string = 'Exercice';
exerciceId: string = '';
exerciceEnonceName: string = '';
exerciceName: string = '';
exerciceGitlabId: number = null;
exerciceGitlabLink: string = '';
private _exerciceGitlabCreationInfo: string = '{}';
private _exerciceGitlabLastInfo: string = '{}';
exerciceGitlabLastInfoTs: number = null;
get exerciceGitlabCreationInfo(): GitlabRepository {
return JSON.parse(this._exerciceGitlabCreationInfo);
}
set exerciceGitlabCreationInfo(value: any) {
if ( typeof value === 'string' ) {
this._exerciceGitlabCreationInfo = value;
return;
}
this._exerciceGitlabCreationInfo = JSON.stringify(value);
}
get exerciceGitlabLastInfo(): GitlabRepository {
return JSON.parse(this._exerciceGitlabLastInfo);
}
set exerciceGitlabLastInfo(value: any) {
if ( typeof value === 'string' ) {
this._exerciceGitlabLastInfo = value;
return;
}
this._exerciceGitlabLastInfo = JSON.stringify(value);
}
public async toJsonObject(): Promise<Object> {
const result = {
'id' : this.exerciceId,
'enonceName' : this.exerciceEnonceName,
'name' : this.exerciceName,
'gitlabId' : this.exerciceGitlabId,
'gitlabLink' : this.exerciceGitlabLink,
'gitlabCreationInfo': this.exerciceGitlabCreationInfo,
'gitlabLastInfo' : this.exerciceGitlabLastInfo,
'gitlabLastInfoTs' : this.exerciceGitlabLastInfoTs
};
return result;
};
public importFromJsonObject(jsonObject: any) {
this.exerciceId = jsonObject.id;
this.exerciceEnonceName = jsonObject.enonceName;
this.exerciceName = jsonObject.name;
this.exerciceGitlabId = jsonObject.gitlabId;
this.exerciceGitlabLink = jsonObject.gitlabLink;
this.exerciceGitlabCreationInfo = jsonObject.gitlabCreationInfo;
this.exerciceGitlabLastInfo = jsonObject.gitlabLastInfo;
this.exerciceGitlabLastInfoTs = jsonObject.gitlabLastInfoTs;
}
public toDb(): any {
return {
exerciceId : this.exerciceId,
exerciceEnonceName : this.exerciceEnonceName,
exerciceName : this.exerciceName,
exerciceGitlabId : this.exerciceGitlabId,
exerciceGitlabLink : this.exerciceGitlabLink,
exerciceGitlabCreationInfo: this._exerciceGitlabCreationInfo,
exerciceGitlabLastInfo : this._exerciceGitlabLastInfo,
exerciceGitlabLastInfoTs : this.exerciceGitlabLastInfoTs
};
}
async create(): Promise<Exercice> {
await db(Exercice.tableName).insert(this.toDb());
return this;
}
update(): Promise<void> {
return db(Exercice.tableName).where('exerciceId', this.exerciceId).update(this.toDb());
}
del(): Promise<void> {
return db(Exercice.tableName).where('exerciceId', this.exerciceId).del();
}
}
export default Exercice;
import Model from './Model';
import db from '../helpers/DatabaseHelper';
class ExerciceMember extends Model {
static tableName: string = 'ExerciceMember';
exerciceId: string = '';
userId: number = null;
public async toJsonObject(): Promise<Object> {
const result = {
'exerciceId': this.exerciceId,
'userId' : this.userId
};
return result;
};
public importFromJsonObject(jsonObject: any) {
this.exerciceId = jsonObject.exerciceId;
this.userId = jsonObject.userId;
}
public toDb(): any {
return {
exerciceId: this.exerciceId,
userId : this.userId
};
}
async create(): Promise<ExerciceMember> {
await db(ExerciceMember.tableName).insert(this.toDb());
return this;
}
del(): Promise<void> {
return db(ExerciceMember.tableName).where('exerciceId', this.exerciceId).andWhere('userId', this.userId).del();
}
}
export default ExerciceMember;
...@@ -4,6 +4,7 @@ import BaseRoutes from './BaseRoutes'; ...@@ -4,6 +4,7 @@ import BaseRoutes from './BaseRoutes';
import SessionRoutes from './SessionRoutes'; import SessionRoutes from './SessionRoutes';
import EnonceRoutes from './EnonceRoutes'; import EnonceRoutes from './EnonceRoutes';
import GitlabRoutes from './GitlabRoutes'; import GitlabRoutes from './GitlabRoutes';
import ExerciceRoutes from './ExerciceRoutes';
class AdminRoutesManager implements RoutesManager { class AdminRoutesManager implements RoutesManager {
...@@ -22,8 +23,9 @@ class AdminRoutesManager implements RoutesManager { ...@@ -22,8 +23,9 @@ class AdminRoutesManager implements RoutesManager {
registerOnBackend(backend: Express) { registerOnBackend(backend: Express) {
BaseRoutes.registerOnBackend(backend); BaseRoutes.registerOnBackend(backend);
SessionRoutes.registerOnBackend(backend); SessionRoutes.registerOnBackend(backend);
EnonceRoutes.registerOnBackend(backend);
GitlabRoutes.registerOnBackend(backend); GitlabRoutes.registerOnBackend(backend);
EnonceRoutes.registerOnBackend(backend);
ExerciceRoutes.registerOnBackend(backend);
} }
} }
......
import { Express } from 'express-serve-static-core';
import express from 'express';
import * as ExpressValidator from 'express-validator';
import { StatusCodes } from 'http-status-codes';
import RoutesManager from '../express/RoutesManager';
import ParamsValidatorMiddleware from '../middlewares/ParamsValidatorMiddleware';
import ApiRequest from '../models/ApiRequest';
import SecurityMiddleware from '../middlewares/SecurityMiddleware';
import GitlabUser from '../shared/types/Gitlab/GitlabUser';
import GitlabManager from '../managers/GitlabManager';
import Config from '../config/Config';
import GitlabRepository from '../shared/types/Gitlab/GitlabRepository';
import Enonce from '../models/Enonce';
import { AxiosError } from 'axios';
import logger from '../shared/logging/WinstonLogger';
import DojoValidators from '../helpers/DojoValidators';
import { v4 as uuidv4 } from 'uuid';
import GitlabMember from '../shared/types/Gitlab/GitlabMember';
import GitlabAccessLevel from '../shared/types/Gitlab/GitlabAccessLevel';
import User from '../models/User';
import UserManager from '../managers/UserManager';
import Exercice from '../models/Exercice';
import ExerciceMember from '../models/ExerciceMember';
import ExerciceManager from '../managers/ExerciceManager';
class ExerciceRoutes implements RoutesManager {
private static _instance: ExerciceRoutes;
private constructor() { }
public static get instance(): ExerciceRoutes {
if ( !ExerciceRoutes._instance ) {
ExerciceRoutes._instance = new ExerciceRoutes();
}
return ExerciceRoutes._instance;
}
private readonly exerciceValidator: ExpressValidator.Schema = {
members: {
trim : true,
notEmpty : true,
customSanitizer: DojoValidators.jsonSanitizer
}
};
registerOnBackend(backend: Express) {
backend.post('/enonces/:enonceNameOrUrl/exercices', SecurityMiddleware.check(true), ParamsValidatorMiddleware.validate(this.exerciceValidator), this.createExercice.bind(this));
}
private getExerciceName(enonce: Enonce, members: Array<GitlabUser>, suffix: number): string {
return `DojoEx - ${ enonce.enonceName } - ${ members.map(member => member.username).join(' + ') }${ suffix > 0 ? ` - ${ suffix }` : '' }`;
}
private getExercicePath(enonce: Enonce, exerciceId: string): string {
return `dojo-ex_${ enonce.enonceGitlabLastInfo.path }_${ exerciceId }`;
}
private async createExercice(req: ApiRequest, res: express.Response) {
const params: { members: Array<GitlabUser> } = req.body;
params.members = [ await req.session.profile.gitlabProfile.value, ...params.members ];
const exerciceId: string = uuidv4();
let repository: GitlabRepository;
let suffix: number = 0;
do {
try {
repository = await GitlabManager.forkRepository(req.boundParams.enonce.enonceGitlabCreationInfo.id, this.getExerciceName(req.boundParams.enonce, params.members, suffix), this.getExercicePath(req.boundParams.enonce, exerciceId), Config.exercice.default.description.replace('{{ENONCE_NAME}}', req.boundParams.enonce.enonceName), Config.exercice.default.visibility, Config.gitlab.group.exercices);
break;
} catch ( error ) {
if ( error instanceof AxiosError ) {
if ( error.response.data.message.name && error.response.data.message.name == 'has already been taken' ) {
suffix++;
} else {
return res.status(error.response.status).send();
}
} else {
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).send();
}
}
} while ( suffix < Config.exercice.maxSameName );
if ( suffix >= Config.exercice.maxSameName ) {
return res.status(StatusCodes.INSUFFICIENT_SPACE_ON_RESOURCE).send();
}
try {
const members: Array<GitlabMember | false> = await Promise.all([ ...new Set([ ...(await req.boundParams.enonce.staff.value).map(member => member.userGitlabId), ...params.members.map(member => member.id) ]) ].map(async (memberId: number): Promise<GitlabMember | false> => {
try {
return await GitlabManager.addRepositoryMember(repository.id, memberId, GitlabAccessLevel.Maintainer);
} catch ( e ) {
return false;
}
}));
const exercice: Exercice = await ExerciceManager.createObjectFromRawSql({
exerciceId : exerciceId,
exerciceEnonceName : req.boundParams.enonce.enonceName,
exerciceName : repository.name,
exerciceGitlabId : repository.id,
exerciceGitlabLink : repository.web_url,
exerciceGitlabCreationInfo: JSON.stringify(repository),
exerciceGitlabLastInfo : JSON.stringify(repository),
exerciceGitlabLastInfoTs : new Date().getTime()
}).create();
let dojoUsers: Array<User> = await UserManager.getFromGitlabUsers(params.members, true) as Array<User>;
dojoUsers = dojoUsers.reduce((unique, user) => (unique.findIndex(uniqueUser => uniqueUser.userId === user.userId) !== -1 ? unique : [ ...unique, user ]), Array<User>());
await Promise.all(dojoUsers.map(dojoUser => ExerciceMember.createFromSql({
exerciceId: exercice.exerciceId,
userId : dojoUser.userId
}).create()));
return req.session.sendResponse(res, StatusCodes.OK, exercice.toJsonObject());
} catch ( error ) {
if ( error instanceof AxiosError ) {
return res.status(error.response.status).send();
}
logger.error(error);
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).send();
}
}
}
export default ExerciceRoutes.instance;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment