Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • Dojo_Project_Nguyen/backend/dojobackendapi
  • dojo_project/projects/backend/dojobackendapi
2 results
Select Git revision
Show changes
Showing
with 1162 additions and 575 deletions
This diff is collapsed.
import axios, { AxiosError, AxiosRequestHeaders } from 'axios';
import Config from '../config/Config';
import FormData from 'form-data';
import logger from '../shared/logging/WinstonLogger';
import SharedConfig from '../shared/config/SharedConfig';
import logger from '../shared/logging/WinstonLogger.js';
class HttpManager {
......@@ -12,33 +10,16 @@ class HttpManager {
}
private registerRequestInterceptor() {
axios.interceptors.request.use((config) => {
axios.interceptors.request.use(config => {
if ( config.data instanceof FormData ) {
config.headers = { ...config.headers, ...(config.data as FormData).getHeaders() } as AxiosRequestHeaders;
config.headers = { ...config.headers, ...config.data.getHeaders() } as AxiosRequestHeaders;
}
if ( config.url && config.url.indexOf(SharedConfig.gitlab.apiURL) !== -1 ) {
if ( !config.headers.DojoOverrideAuthorization ) {
config.headers['PRIVATE-TOKEN'] = Config.gitlab.account.token;
}
}
if ( config.headers.DojoOverrideAuthorization && 'DojoAuthorizationHeader' in config.headers && 'DojoAuthorizationValue' in config.headers ) {
config.headers[config.headers.DojoAuthorizationHeader] = config.headers.DojoAuthorizationValue;
delete config.headers.DojoOverrideAuthorization;
delete config.headers.DojoAuthorizationHeader;
delete config.headers.DojoAuthorizationValue;
}
return config;
});
}
private registerResponseInterceptor() {
axios.interceptors.response.use((response) => {
return response;
}, (error) => {
axios.interceptors.response.use(response => response, error => {
if ( error instanceof AxiosError ) {
logger.error(`${ JSON.stringify(error.response?.data) }`);
} else {
......
import SharedConfig from '../shared/config/SharedConfig';
import SonarRoute from '../shared/types/Sonar/SonarRoute';
import axios, { AxiosInstance } from 'axios';
import Config from '../config/Config';
import SonarProjectCreation from '../shared/types/Sonar/SonarProjectCreation';
import https from 'https';
import GlobalHelper from '../helpers/GlobalHelper';
import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode';
import express from 'express';
import GitlabRepository from '../shared/types/Gitlab/GitlabRepository';
class SonarManager {
private instance: AxiosInstance = axios.create({
httpsAgent: new https.Agent({
rejectUnauthorized: false
})
});
private getApiUrl(route: SonarRoute): string {
return `${ SharedConfig.sonar.url }${ route }`;
}
/**
* Assign a Gitlab Personal Access Token to a Sonar account (needed for any other request linked to gitlab)
* @private
*/
private async setPAT() {
const formData = new FormData();
formData.append('almSetting', 'dojo');
formData.append('pat', Config.gitlab.account.token);
await this.instance.post(this.getApiUrl(SonarRoute.SET_PAT), formData, {
headers: {
Authorization: `Basic ${ btoa(SharedConfig.sonar.token + ":") }`
}
});
}
private async executePostRequest<T>(url: string, data?: FormData) {
await this.setPAT(); // Always set PAT to be sure it has been set
return (await this.instance.post<T>(url, data, {
headers: {
Authorization: `Basic ${ btoa(SharedConfig.sonar.token + ":") }`
}
})).data;
}
private async executeGetRequest<T>(url: string, data?: unknown) {
return (await this.instance.get<T>(url, {
headers: {
Authorization: `Basic ${ btoa(SharedConfig.sonar.token + ":") }`
},
params: data
})).data;
}
async createProjectFromGitlab(projectId: number) {
const formData = new FormData();
formData.append('almSetting', 'dojo');
formData.append('gitlabProjectId', projectId.toString());
return await this.executePostRequest<SonarProjectCreation>(this.getApiUrl(SonarRoute.PROJECT_CREATE_GITLAB), formData)
}
async addQualityGate(projectKey: string, qualityGate: string) {
const formData = new FormData();
formData.append('projectKey', projectKey);
formData.append('gateName', qualityGate);
return await this.executePostRequest<undefined>(this.getApiUrl(SonarRoute.PROJECT_ADD_GATE), formData);
}
async addQualityProfile(projectKey: string, qualityProfile: string, language: string) {
const formData = new FormData();
formData.append('project', projectKey);
formData.append('qualityProfile', qualityProfile);
formData.append('language', language);
return await this.executePostRequest<unknown>(this.getApiUrl(SonarRoute.PROJECT_ADD_PROFILE), formData);
}
async createProjectWithQualities(gitlabRepository: GitlabRepository, qualityGate: string | null, qualityProfiles: string[] | null, req: express.Request, res: express.Response) {
let sonarProject: SonarProjectCreation | undefined = undefined;
try {
sonarProject = await this.createProjectFromGitlab(gitlabRepository.id);
if (sonarProject == undefined) {
return await GlobalHelper.repositoryCreationError('Sonar error', undefined, req, res, DojoStatusCode.ASSIGNMENT_CREATION_SONAR_ERROR, DojoStatusCode.ASSIGNMENT_CREATION_SONAR_ERROR, gitlabRepository);
}
} catch ( error ) {
return await GlobalHelper.repositoryCreationError('Sonar project creation error', error, req, res, DojoStatusCode.ASSIGNMENT_CREATION_SONAR_ERROR, DojoStatusCode.ASSIGNMENT_CREATION_INTERNAL_ERROR, gitlabRepository, sonarProject);
}
// Add gate and profiles to sonar project
if ( qualityGate != undefined && qualityGate != "" ) {
try {
await this.addQualityGate(sonarProject.project.key, qualityGate);
} catch ( error ) {
return await GlobalHelper.repositoryCreationError('Sonar gate error', error, req, res, DojoStatusCode.ASSIGNMENT_SONAR_GATE_NOT_FOUND, DojoStatusCode.ASSIGNMENT_SONAR_GATE_NOT_FOUND, gitlabRepository, sonarProject);
}
}
if ( qualityProfiles != undefined && qualityProfiles.length > 0 ) {
for ( const profile of qualityProfiles ) {
try {
const [ lang, name ] = profile.split('/');
if (lang.trim() != '' && name.trim() != '') {
await this.addQualityProfile(sonarProject.project.key, name.trim(), lang.trim());
} else {
return await GlobalHelper.repositoryCreationError('Sonar profile invalid', undefined, req, res, DojoStatusCode.ASSIGNMENT_SONAR_PROFILE_NOT_FOUND, DojoStatusCode.ASSIGNMENT_SONAR_PROFILE_NOT_FOUND, gitlabRepository, sonarProject);
}
} catch ( error ) {
return await GlobalHelper.repositoryCreationError('Sonar profile not found', error, req, res, DojoStatusCode.ASSIGNMENT_SONAR_PROFILE_NOT_FOUND, DojoStatusCode.ASSIGNMENT_SONAR_PROFILE_NOT_FOUND, gitlabRepository, sonarProject);
}
}
}
return sonarProject;
}
async deleteProject(projectKey: string) {
const formData = new FormData();
formData.append('project', projectKey);
return await this.executePostRequest<SonarProjectCreation>(this.getApiUrl(SonarRoute.PROJECT_DELETE), formData)
}
async getLanguages() {
const resp = await this.executeGetRequest<{ languages: { key: string, name: string }[]}>(this.getApiUrl(SonarRoute.GET_LANGUAGES))
return resp.languages.map(l => l.key)
}
async testQualityGate(gateName: string) {
try {
await this.executeGetRequest(this.getApiUrl(SonarRoute.TEST_GATE), { name: gateName });
return true;
} catch ( e ) {
return false;
}
}
async testQualityProfile(profileName: string, language: string) {
try {
const formData = new FormData();
formData.append('language', language);
formData.append('qualityProfile', profileName);
const resp = await this.executeGetRequest<{ profiles: { key: string, name: string, language: string }[] }>(
this.getApiUrl(SonarRoute.TEST_PROFILE), formData
);
return (resp.profiles.length > 0 && resp.profiles.some(p => p.name === profileName && p.language === language))
} catch ( e ) {
return false;
}
}
/**
* Return the sonar user login name associated with the gitlab username
* @param gitlabUsername Username to look up
*/
async findUserFromGitlabUser(gitlabUsername: string) {
const formData = new FormData();
formData.append('q', gitlabUsername);
const resp = await this.executeGetRequest<{ users: { login: string, name: string }[] }>(this.getApiUrl(SonarRoute.SEARCH_USER), formData);
for (const u of resp.users) {
if ( u.name == gitlabUsername ) {
return u.login;
}
}
return undefined;
}
async addUserToProject(username: string, projectKey: string, privileged: boolean) {
const permissions = ['user', 'codeviewer'];
if (privileged) {
permissions.push('issueadmin');
}
for (const perm of permissions) {
const formData = new FormData();
formData.append('projectKey', projectKey);
formData.append('permission', perm);
formData.append('login', username);
await this.executePostRequest(this.getApiUrl(SonarRoute.PROJECT_ADD_USER), formData)
}
}
async addGitlabUserToProject(gitlabUsername: string, projectKey: string, privileged: boolean) {
const username = await this.findUserFromGitlabUser(gitlabUsername);
if (username == undefined) {
return false;
}
await this.addUserToProject(username, projectKey, privileged);
return true;
}
}
export default new SonarManager();
\ No newline at end of file
import { Prisma, Tag } from '@prisma/client';
import db from '../helpers/DatabaseHelper';
class TagManager {
async get(name: string, include: Prisma.TagInclude | undefined = undefined): Promise<Tag | undefined> {
return await db.tag.findUnique({
where : {
name: name
},
include: include
}) as unknown as Tag ?? undefined;
}
}
export default new TagManager();
import { TagProposal } from '@prisma/client';
import db from '../helpers/DatabaseHelper';
class TagProposalManager {
async get(name: string | undefined = undefined): Promise<TagProposal | undefined> {
return await db.tagProposal.findUnique({
where: {
name: name
}
}) as unknown as TagProposal ?? undefined;
}
}
export default new TagProposalManager();
import GitlabUser from '../shared/types/Gitlab/GitlabUser';
import { Prisma } from '@prisma/client';
import db from '../helpers/DatabaseHelper';
import GitlabProfile from '../shared/types/Gitlab/GitlabProfile';
import { User } from '../types/DatabaseTypes';
import { Prisma } from '@prisma/client';
import db from '../helpers/DatabaseHelper.js';
import { User } from '../types/DatabaseTypes.js';
import * as Gitlab from '@gitbeaker/rest';
class UserManager {
async getFiltered(filters: Prisma.UserWhereInput | undefined, include: Prisma.UserInclude | undefined = undefined): Promise<Array<User> | undefined> {
return await db.user.findMany({
where : filters,
include: include
}) as unknown as Array<User> ?? undefined;
}
async getByMail(mail: string, include: Prisma.UserInclude | undefined = undefined): Promise<User | undefined> {
return await db.user.findUnique({
where : {
......@@ -15,16 +21,16 @@ class UserManager {
}) as unknown as User ?? undefined;
}
async getById(id: number, include: Prisma.UserInclude | undefined = undefined): Promise<User | undefined> {
async getById(id: string | number, include: Prisma.UserInclude | undefined = undefined): Promise<User | undefined> {
return await db.user.findUnique({
where : {
id: id
id: Number(id)
},
include: include
}) as unknown as User ?? undefined;
}
async getUpdateFromGitlabProfile(gitlabProfile: GitlabProfile): Promise<User> {
async getUpdateFromGitlabProfile(gitlabProfile: Gitlab.ExpandedUserSchema): Promise<User> {
await db.user.upsert({
where : {
id: gitlabProfile.id
......@@ -46,7 +52,7 @@ class UserManager {
return (await this.getById(gitlabProfile.id))!;
}
async getFromGitlabUser(gitlabUser: GitlabUser, createIfNotExist: boolean = false, include: Prisma.UserInclude | undefined = undefined): Promise<User | number | undefined> {
async getFromGitlabUser(gitlabUser: Gitlab.UserSchema, createIfNotExist: boolean = false, include: Prisma.UserInclude | undefined = undefined): Promise<User | number | undefined> {
let user = await this.getById(gitlabUser.id, include) ?? gitlabUser.id;
if ( typeof user === 'number' && createIfNotExist ) {
......@@ -61,7 +67,7 @@ class UserManager {
return user;
}
async getFromGitlabUsers(gitlabUsers: Array<GitlabUser>, createIfNotExist: boolean = false, include: Prisma.UserInclude | undefined = undefined): Promise<Array<User | number | undefined>> {
async getFromGitlabUsers(gitlabUsers: Array<Gitlab.UserSchema>, createIfNotExist: boolean = false, include: Prisma.UserInclude | undefined = undefined): Promise<Array<User | number | undefined>> {
return Promise.all(gitlabUsers.map(gitlabUser => this.getFromGitlabUser(gitlabUser, createIfNotExist, include)));
}
}
......
import express from 'express';
import Config from '../config/Config';
import semver from 'semver/preload';
import Session from '../controllers/Session';
import { HttpStatusCode } from 'axios';
import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode';
import express from 'express';
import Config from '../config/Config.js';
import semver from 'semver/preload';
import Session from '../controllers/Session.js';
import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode.js';
import { StatusCodes } from 'http-status-codes';
class ClientVersionCheckerMiddleware {
register(): (req: express.Request, res: express.Response, next: express.NextFunction) => void {
return async (req: express.Request, res: express.Response, next: express.NextFunction) => {
return (req: express.Request, res: express.Response, next: express.NextFunction) => {
if ( req.headers['client'] && req.headers['client-version'] ) {
const requestClient = req.headers['client'] as string;
const requestClientVersion = req.headers['client-version'] as string;
......@@ -19,13 +19,15 @@ class ClientVersionCheckerMiddleware {
next();
return;
} else {
new Session().sendResponse(res, HttpStatusCode.MethodNotAllowed, {}, `Client version ${ requestClientVersion } is not supported. Please update your client.`, DojoStatusCode.CLIENT_VERSION_NOT_SUPPORTED);
new Session().sendResponse(res, StatusCodes.METHOD_NOT_ALLOWED, {}, `Client version ${ requestClientVersion } is not supported. Please update your client.`, DojoStatusCode.CLIENT_VERSION_NOT_SUPPORTED);
return;
}
}
}
new Session().sendResponse(res, HttpStatusCode.MethodNotAllowed, {}, `Unsupported client.`, DojoStatusCode.CLIENT_NOT_SUPPORTED);
new Session().sendResponse(res, StatusCodes.METHOD_NOT_ALLOWED, {}, `Unsupported client.`, DojoStatusCode.CLIENT_NOT_SUPPORTED);
} else {
next();
}
};
}
......
import { Express } from 'express-serve-static-core';
import express from 'express';
import { StatusCodes } from 'http-status-codes';
import ExerciseManager from '../managers/ExerciseManager';
import AssignmentManager from '../managers/AssignmentManager';
import { Express } from 'express-serve-static-core';
import express from 'express';
import { StatusCodes } from 'http-status-codes';
import ExerciseManager from '../managers/ExerciseManager';
import AssignmentManager from '../managers/AssignmentManager';
import TagManager from '../managers/TagManager';
import TagProposalManager from '../managers/TagProposalManager';
import UserManager from '../managers/UserManager';
type GetFunction = (id: string | number, ...args: Array<unknown>) => Promise<unknown>
......@@ -27,23 +30,50 @@ class ParamsCallbackManager {
initBoundParams(req: express.Request) {
if ( !req.boundParams ) {
req.boundParams = {
assignment: undefined,
exercise : undefined
user : undefined,
assignment : undefined,
exercise : undefined,
tag : undefined,
tagProposal: undefined
};
}
}
registerOnBackend(backend: Express) {
this.listenParam('userId', backend, (UserManager.getById as GetFunction).bind(UserManager), [ {
assignments: true,
exercises : {
include: {
members : true,
assignment: {
include: {
staff: true
}
}
}
}
} ], 'user');
this.listenParam('assignmentNameOrUrl', backend, (AssignmentManager.get as GetFunction).bind(AssignmentManager), [ {
exercises: true,
staff : true
} ], 'assignment');
this.listenParam('exerciseIdOrUrl', backend, (ExerciseManager.get as GetFunction).bind(ExerciseManager), [ {
assignment: true,
assignment: {
include: {
staff: true
}
},
members : true,
results : true
} ], 'exercise');
this.listenParam('tagName', backend, (TagManager.get as GetFunction).bind(TagManager), [ {
assignments: true
} ], 'tag');
this.listenParam('tagProposalName', backend, (TagProposalManager.get as GetFunction).bind(TagProposalManager), [ {} ], 'tagProposal');
}
}
......
......@@ -5,20 +5,20 @@ import { StatusCodes } from 'http-status-codes';
class ParamsValidatorMiddleware {
validate(validations: Array<ExpressValidator.ValidationChain> | ExpressValidator.Schema): (req: express.Request, res: express.Response, next: express.NextFunction) => void {
return async (req: express.Request, res: express.Response, next: express.NextFunction) => {
return (req: express.Request, res: express.Response, next: express.NextFunction) => {
if ( !(validations instanceof Array) ) {
validations = ExpressValidator.checkSchema(validations);
}
await Promise.all(validations.map(validation => validation.run(req)));
const errors = ExpressValidator.validationResult(req);
if ( !errors.isEmpty() ) {
return req.session.sendResponse(res, StatusCodes.BAD_REQUEST, { errors: errors.array() });
}
Promise.all(validations.map(validation => validation.run(req))).then(() => {
const errors = ExpressValidator.validationResult(req);
if ( !errors.isEmpty() ) {
req.session.sendResponse(res, StatusCodes.BAD_REQUEST, { errors: errors.array() });
return;
}
return next();
next();
});
};
}
}
......
import express from 'express';
import { StatusCodes } from 'http-status-codes';
import SecurityCheckType from '../types/SecurityCheckType';
import logger from '../shared/logging/WinstonLogger';
import AssignmentManager from '../managers/AssignmentManager';
import SecurityCheckType from '../types/SecurityCheckType.js';
import logger from '../shared/logging/WinstonLogger.js';
import AssignmentManager from '../managers/AssignmentManager.js';
import ExerciseManager from '../managers/ExerciseManager';
class SecurityMiddleware {
private checkIfConnected(checkIfConnected: boolean, req: express.Request): boolean {
return !checkIfConnected || (req.session.profile !== null && req.session.profile !== undefined);
}
private async checkType(checkType: SecurityCheckType, req: express.Request): Promise<boolean> {
try {
switch ( String(checkType) ) {
case SecurityCheckType.USER.valueOf():
return this.checkIfConnected(true, req);
case SecurityCheckType.ADMIN.valueOf():
return req.session.profile.isAdmin;
case SecurityCheckType.TEACHING_STAFF.valueOf():
return req.session.profile.isTeachingStaff;
case SecurityCheckType.EXERCISE_MEMBERS.valueOf():
return await ExerciseManager.isUserAllowedToAccessExercise(req.boundParams.exercise!, req.session.profile);
case SecurityCheckType.ASSIGNMENT_STAFF.valueOf():
return await AssignmentManager.isUserAllowedToAccessAssignment(req.boundParams.assignment!, req.session.profile);
case SecurityCheckType.ASSIGNMENT_IS_PUBLISHED.valueOf():
return req.boundParams.assignment?.published ?? false;
case SecurityCheckType.EXERCISE_SECRET.valueOf():
return (req.headers.exercisesecret as string | undefined) === req.boundParams.exercise!.secret;
case SecurityCheckType.ASSIGNMENT_SECRET:
return (req.headers.assignmentsecret as string | undefined) === req.boundParams.assignment!.secret;
default:
return false;
}
} catch ( e ) {
logger.error('Security check failed !!! => ' + JSON.stringify(e));
return false;
}
}
// First check if connected then check if at least ONE rule match. It's NOT an AND but it's a OR function.
check(checkIfConnected: boolean, ...checkTypes: Array<SecurityCheckType>): (req: express.Request, res: express.Response, next: express.NextFunction) => void {
return async (req: express.Request, res: express.Response, next: express.NextFunction) => {
if ( checkIfConnected ) {
if ( req.session.profile === null || req.session.profile === undefined ) {
return req.session.sendResponse(res, StatusCodes.UNAUTHORIZED);
}
return (req: express.Request, res: express.Response, next: express.NextFunction) => {
if ( !this.checkIfConnected(checkIfConnected, req) ) {
return req.session.sendResponse(res, StatusCodes.UNAUTHORIZED);
}
let isAllowed = checkTypes.length === 0;
if ( !isAllowed ) {
for ( const checkType of checkTypes ) {
try {
switch ( String(checkType) ) {
case SecurityCheckType.TEACHING_STAFF:
isAllowed = isAllowed || req.session.profile.isTeachingStaff;
break;
case SecurityCheckType.ASSIGNMENT_STAFF:
isAllowed = isAllowed || await AssignmentManager.isUserAllowedToAccessAssignment(req.boundParams.assignment!, req.session.profile);
break;
case SecurityCheckType.ASSIGNMENT_IS_PUBLISHED:
isAllowed = isAllowed || (req.boundParams.assignment?.published ?? false);
break;
case SecurityCheckType.EXERCISE_SECRET:
isAllowed = isAllowed || (req.headers.exercisesecret as string | undefined) === req.boundParams.exercise!.secret;
break;
default:
break;
}
} catch ( e ) {
logger.error('Security check failed !!! => ' + e);
isAllowed = isAllowed || false;
}
}
}
const isAllowed: boolean = checkTypes.length === 0 ? true : checkTypes.find(async checkType => this.checkType(checkType, req)) !== undefined;
if ( !isAllowed ) {
return req.session.sendResponse(res, StatusCodes.FORBIDDEN);
......
import express from 'express';
import Session from '../controllers/Session';
import Session from '../controllers/Session.js';
import { Express } from 'express-serve-static-core';
class SessionMiddleware {
registerOnBackend(backend: Express) {
backend.use(async (req: express.Request, res: express.Response, next: express.NextFunction) => {
backend.use((req: express.Request, res: express.Response, next: express.NextFunction) => {
req.session = new Session();
await req.session.initSession(req, res);
return next();
req.session.initSession(req, res).then(() => {
next();
});
});
}
}
......
import cluster, { Worker } from 'node:cluster';
import WorkerRole from './WorkerRole';
import WorkerRole from './WorkerRole.js';
import os from 'os';
import ClusterStrategy from './ClusterStrategy';
import WorkerPool from './WorkerPool';
import logger from '../shared/logging/WinstonLogger';
import ClusterStrategy from './ClusterStrategy.js';
import WorkerPool from './WorkerPool.js';
import logger from '../shared/logging/WinstonLogger.js';
/*
......@@ -11,10 +11,13 @@ import logger from '../shared/logging/WinstonLogger';
*/
class ClusterManager {
public static readonly CORES = os.cpus().length;
private readonly strategy: ClusterStrategy;
private workers: { [pid: number]: WorkerRole; } = [];
constructor(private strategy: ClusterStrategy) {}
constructor(strategy: ClusterStrategy) {
this.strategy = strategy;
}
private getWorkerPool(role: WorkerRole): WorkerPool | undefined {
return this.strategy.find(elem => elem.role === role);
......
import WorkerPool from './WorkerPool';
import WorkerPool from './WorkerPool.js';
type ClusterStrategy = Array<WorkerPool>
......
import WorkerRole from './WorkerRole';
import WorkerTask from './WorkerTask';
import WorkerRole from './WorkerRole.js';
import WorkerTask from './WorkerTask.js';
/*
......
import { Express } from 'express-serve-static-core';
import RoutesManager from '../express/RoutesManager';
import BaseRoutes from './BaseRoutes';
import SessionRoutes from './SessionRoutes';
import AssignmentRoutes from './AssignmentRoutes';
import GitlabRoutes from './GitlabRoutes';
import ExerciseRoutes from './ExerciseRoutes';
import RoutesManager from '../express/RoutesManager.js';
import BaseRoutes from './BaseRoutes.js';
import SessionRoutes from './SessionRoutes.js';
import AssignmentRoutes from './AssignmentRoutes.js';
import GitlabRoutes from './GitlabRoutes.js';
import ExerciseRoutes from './ExerciseRoutes.js';
import TagsRoutes from './TagRoutes';
import UserRoutes from './UserRoutes';
import SonarRoutes from './SonarRoutes';
class AdminRoutesManager implements RoutesManager {
......@@ -14,6 +17,9 @@ class AdminRoutesManager implements RoutesManager {
GitlabRoutes.registerOnBackend(backend);
AssignmentRoutes.registerOnBackend(backend);
ExerciseRoutes.registerOnBackend(backend);
TagsRoutes.registerOnBackend(backend);
UserRoutes.registerOnBackend(backend);
SonarRoutes.registerOnBackend(backend);
}
}
......
import { Express } from 'express-serve-static-core';
import express from 'express';
import { StatusCodes } from 'http-status-codes';
import RoutesManager from '../express/RoutesManager';
import { Express } from 'express-serve-static-core';
import express, { RequestHandler } from 'express';
import { StatusCodes } from 'http-status-codes';
import RoutesManager from '../express/RoutesManager.js';
import Config from '../config/Config';
import SharedConfig from '../shared/config/SharedConfig';
import GlobalHelper from '../helpers/GlobalHelper';
import SharedSonarManager from '../shared/managers/SharedSonarManager';
import SonarManager from '../managers/SonarManager';
class BaseRoutes implements RoutesManager {
registerOnBackend(backend: Express) {
backend.get('/', this.homepage.bind(this));
backend.get('/health_check', this.healthCheck.bind(this));
backend.get('/', this.homepage.bind(this) as RequestHandler);
backend.get('/health_check', this.healthCheck.bind(this) as RequestHandler);
backend.get('/sonar', this.sonar.bind(this));
backend.get('/clients_config', this.clientsConfig.bind(this) as RequestHandler);
}
private async homepage(req: express.Request, res: express.Response) {
......@@ -17,6 +26,24 @@ class BaseRoutes implements RoutesManager {
private async healthCheck(req: express.Request, res: express.Response) {
return req.session.sendResponse(res, StatusCodes.OK);
}
private async clientsConfig(req: express.Request, res: express.Response) {
return req.session.sendResponse(res, StatusCodes.OK, {
gitlabUrl : Config.gitlab.url,
gitlabAccountId : Config.gitlab.account.id,
gitlabAccountUsername : Config.gitlab.account.username,
loginGitlabClientId : Config.login.gitlab.client.id,
exerciseMaxPerAssignment: Config.exercise.maxPerAssignment
});
}
private async sonar(req: express.Request, res: express.Response) {
const data = {
sonarEnabled: await SharedSonarManager.isSonarSupported(),
languages: await SonarManager.getLanguages()
};
return req.session.sendResponse(res, StatusCodes.OK, data);
}
}
......
This diff is collapsed.
import { Express } from 'express-serve-static-core';
import express from 'express';
import RoutesManager from '../express/RoutesManager';
import SecurityMiddleware from '../middlewares/SecurityMiddleware';
import SecurityCheckType from '../types/SecurityCheckType';
import GitlabManager from '../managers/GitlabManager';
import { Express } from 'express-serve-static-core';
import express, { RequestHandler } from 'express';
import RoutesManager from '../express/RoutesManager.js';
import SecurityMiddleware from '../middlewares/SecurityMiddleware.js';
import SecurityCheckType from '../types/SecurityCheckType.js';
import GitlabManager from '../managers/GitlabManager.js';
class GitlabRoutes implements RoutesManager {
registerOnBackend(backend: Express) {
backend.get('/gitlab/project/:gitlabProjectIdOrNamespace/checkTemplateAccess', SecurityMiddleware.check(true, SecurityCheckType.TEACHING_STAFF), this.checkTemplateAccess.bind(this));
backend.get('/gitlab/project/:gitlabProjectIdOrNamespace/checkTemplateAccess', SecurityMiddleware.check(true, SecurityCheckType.TEACHING_STAFF), this.checkTemplateAccess.bind(this) as RequestHandler);
}
private async checkTemplateAccess(req: express.Request, res: express.Response) {
const gitlabProjectIdOrNamespace: string = req.params.gitlabProjectIdOrNamespace;
return res.status(await GitlabManager.checkTemplateAccess(gitlabProjectIdOrNamespace, req)).send();
await GitlabManager.checkTemplateAccess(gitlabProjectIdOrNamespace, req, res);
}
}
......
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 SecurityMiddleware from '../middlewares/SecurityMiddleware';
import GitlabManager from '../managers/GitlabManager';
import UserManager from '../managers/UserManager';
import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode';
import SharedGitlabManager from '../shared/managers/SharedGitlabManager';
import Config from '../config/Config';
import { Express } from 'express-serve-static-core';
import express, { RequestHandler } from 'express';
import * as ExpressValidator from 'express-validator';
import { StatusCodes } from 'http-status-codes';
import RoutesManager from '../express/RoutesManager.js';
import ParamsValidatorMiddleware from '../middlewares/ParamsValidatorMiddleware.js';
import SecurityMiddleware from '../middlewares/SecurityMiddleware.js';
import GitlabManager from '../managers/GitlabManager.js';
import UserManager from '../managers/UserManager.js';
import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode.js';
import Config from '../config/Config.js';
class SessionRoutes implements RoutesManager {
......@@ -32,9 +31,9 @@ class SessionRoutes implements RoutesManager {
};
registerOnBackend(backend: Express) {
backend.post('/login', ParamsValidatorMiddleware.validate(this.loginValidator), this.login.bind(this));
backend.post('/refresh_tokens', ParamsValidatorMiddleware.validate(this.refreshTokensValidator), this.refreshTokens.bind(this));
backend.get('/test_session', SecurityMiddleware.check(true), this.testSession.bind(this));
backend.post('/login', ParamsValidatorMiddleware.validate(this.loginValidator), this.login.bind(this) as RequestHandler);
backend.post('/refresh_tokens', ParamsValidatorMiddleware.validate(this.refreshTokensValidator), this.refreshTokens.bind(this) as RequestHandler);
backend.get('/test_session', SecurityMiddleware.check(true), this.testSession.bind(this) as RequestHandler);
}
private async login(req: express.Request, res: express.Response) {
......@@ -64,7 +63,7 @@ class SessionRoutes implements RoutesManager {
refreshToken: string
} = req.body;
const gitlabTokens = await SharedGitlabManager.getTokens(params.refreshToken, true, Config.login.gitlab.client.secret);
const gitlabTokens = await GitlabManager.getTokens(params.refreshToken, true, Config.login.gitlab.client.secret);
req.session.sendResponse(res, StatusCodes.OK, gitlabTokens);
} catch ( error ) {
......