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

Merge branch 'bedran_exercise-list' into v6.0.0

parents 351f58b4 172bf169
No related branches found
No related tags found
No related merge requests found
Pipeline #38758 passed
...@@ -5,6 +5,13 @@ import * as Gitlab from '@gitbeaker/rest'; ...@@ -5,6 +5,13 @@ import * as Gitlab from '@gitbeaker/rest';
class UserManager { 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> { async getByMail(mail: string, include: Prisma.UserInclude | undefined = undefined): Promise<User | undefined> {
return await db.user.findUnique({ return await db.user.findUnique({
where : { where : {
...@@ -14,10 +21,10 @@ class UserManager { ...@@ -14,10 +21,10 @@ class UserManager {
}) as unknown as User ?? undefined; }) 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({ return await db.user.findUnique({
where : { where : {
id: id id: Number(id)
}, },
include: include include: include
}) as unknown as User ?? undefined; }) as unknown as User ?? undefined;
......
...@@ -5,6 +5,7 @@ import ExerciseManager from '../managers/ExerciseManager'; ...@@ -5,6 +5,7 @@ import ExerciseManager from '../managers/ExerciseManager';
import AssignmentManager from '../managers/AssignmentManager'; import AssignmentManager from '../managers/AssignmentManager';
import TagManager from '../managers/TagManager'; import TagManager from '../managers/TagManager';
import TagProposalManager from '../managers/TagProposalManager'; import TagProposalManager from '../managers/TagProposalManager';
import UserManager from '../managers/UserManager';
type GetFunction = (id: string | number, ...args: Array<unknown>) => Promise<unknown> type GetFunction = (id: string | number, ...args: Array<unknown>) => Promise<unknown>
...@@ -29,6 +30,7 @@ class ParamsCallbackManager { ...@@ -29,6 +30,7 @@ class ParamsCallbackManager {
initBoundParams(req: express.Request) { initBoundParams(req: express.Request) {
if ( !req.boundParams ) { if ( !req.boundParams ) {
req.boundParams = { req.boundParams = {
user : undefined,
assignment : undefined, assignment : undefined,
exercise : undefined, exercise : undefined,
tag : undefined, tag : undefined,
...@@ -38,13 +40,31 @@ class ParamsCallbackManager { ...@@ -38,13 +40,31 @@ class ParamsCallbackManager {
} }
registerOnBackend(backend: Express) { 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), [ { this.listenParam('assignmentNameOrUrl', backend, (AssignmentManager.get as GetFunction).bind(AssignmentManager), [ {
exercises: true, exercises: true,
staff : true staff : true
} ], 'assignment'); } ], 'assignment');
this.listenParam('exerciseIdOrUrl', backend, (ExerciseManager.get as GetFunction).bind(ExerciseManager), [ { this.listenParam('exerciseIdOrUrl', backend, (ExerciseManager.get as GetFunction).bind(ExerciseManager), [ {
assignment: true, assignment: {
include: {
staff: true
}
},
members : true, members : true,
results : true results : true
} ], 'exercise'); } ], 'exercise');
......
...@@ -6,6 +6,7 @@ import AssignmentRoutes from './AssignmentRoutes.js'; ...@@ -6,6 +6,7 @@ import AssignmentRoutes from './AssignmentRoutes.js';
import GitlabRoutes from './GitlabRoutes.js'; import GitlabRoutes from './GitlabRoutes.js';
import ExerciseRoutes from './ExerciseRoutes.js'; import ExerciseRoutes from './ExerciseRoutes.js';
import TagsRoutes from './TagRoutes'; import TagsRoutes from './TagRoutes';
import UserRoutes from './UserRoutes';
class AdminRoutesManager implements RoutesManager { class AdminRoutesManager implements RoutesManager {
...@@ -16,6 +17,7 @@ class AdminRoutesManager implements RoutesManager { ...@@ -16,6 +17,7 @@ class AdminRoutesManager implements RoutesManager {
AssignmentRoutes.registerOnBackend(backend); AssignmentRoutes.registerOnBackend(backend);
ExerciseRoutes.registerOnBackend(backend); ExerciseRoutes.registerOnBackend(backend);
TagsRoutes.registerOnBackend(backend); TagsRoutes.registerOnBackend(backend);
UserRoutes.registerOnBackend(backend);
} }
} }
......
...@@ -70,20 +70,68 @@ class ExerciseRoutes implements RoutesManager { ...@@ -70,20 +70,68 @@ class ExerciseRoutes implements RoutesManager {
backend.get('/exercises', SecurityMiddleware.check(true, SecurityCheckType.ADMIN), this.getAllExercises.bind(this) as RequestHandler); backend.get('/exercises', SecurityMiddleware.check(true, SecurityCheckType.ADMIN), this.getAllExercises.bind(this) as RequestHandler);
backend.get('/exercises/:exerciseIdOrUrl/assignment', SecurityMiddleware.check(false, SecurityCheckType.EXERCISE_SECRET), this.getAssignment.bind(this) as RequestHandler); backend.get('/exercises/:exerciseIdOrUrl/assignment', SecurityMiddleware.check(false, SecurityCheckType.EXERCISE_SECRET), this.getAssignment.bind(this) as RequestHandler);
backend.get('/exercises/:exerciseIdOrUrl', SecurityMiddleware.check(true, SecurityCheckType.ADMIN, SecurityCheckType.EXERCISE_MEMBERS), this.getExercise.bind(this) as RequestHandler);
backend.get('/exercises/:exerciseIdOrUrl/members', SecurityMiddleware.check(true, SecurityCheckType.ADMIN, SecurityCheckType.EXERCISE_MEMBERS), this.getExerciseMembers.bind(this) as RequestHandler); backend.get('/exercises/:exerciseIdOrUrl/members', SecurityMiddleware.check(true, SecurityCheckType.ADMIN, SecurityCheckType.EXERCISE_MEMBERS), this.getExerciseMembers.bind(this) as RequestHandler);
backend.get('/exercises/:exerciseIdOrUrl/results', SecurityMiddleware.check(true, SecurityCheckType.ADMIN, SecurityCheckType.EXERCISE_MEMBERS), this.getExerciseResults.bind(this) as RequestHandler); backend.get('/exercises/:exerciseIdOrUrl/results', SecurityMiddleware.check(true, SecurityCheckType.ADMIN, SecurityCheckType.EXERCISE_MEMBERS), this.getExerciseResults.bind(this) as RequestHandler);
backend.delete('/exercises/:exerciseIdOrUrl', SecurityMiddleware.check(true, SecurityCheckType.ADMIN, SecurityCheckType.EXERCISE_MEMBERS), this.deleteExercise.bind(this) as RequestHandler); backend.delete('/exercises/:exerciseIdOrUrl', SecurityMiddleware.check(true, SecurityCheckType.ADMIN, SecurityCheckType.EXERCISE_MEMBERS), this.deleteExercise.bind(this) as RequestHandler);
backend.get('/users/:userId/exercises', SecurityMiddleware.check(true), this.getUserExercises.bind(this) as RequestHandler);
backend.get('/exercises/:exerciseIdOrLink/results', SecurityMiddleware.check(true), this.getExerciseResultsByIdOrLink.bind(this) as RequestHandler);
backend.post('/exercises/:exerciseIdOrUrl/results', SecurityMiddleware.check(false, SecurityCheckType.EXERCISE_SECRET), ParamsValidatorMiddleware.validate(this.resultValidator), this.createResult.bind(this) as RequestHandler); backend.post('/exercises/:exerciseIdOrUrl/results', SecurityMiddleware.check(false, SecurityCheckType.EXERCISE_SECRET), ParamsValidatorMiddleware.validate(this.resultValidator), this.createResult.bind(this) as RequestHandler);
} }
private async getExerciseResultsByIdOrLink(req: express.Request, res: express.Response) {
const exerciseIdOrLink = req.params.exerciseIdOrLink;
const exercise = await db.exercise.findFirst({
where: {
OR: [ { id: exerciseIdOrLink }, { gitlabLink: exerciseIdOrLink } ]
}
});
if ( !exercise ) {
return res.status(StatusCodes.NOT_FOUND).send('Exercise not found');
}
const results = await db.result.findMany({
where: { exerciseId: exercise.id }
});
return res.status(StatusCodes.OK).json(results);
}
private async getAllExercises(req: express.Request, res: express.Response) {
const exos = await db.exercise.findMany();
return req.session.sendResponse(res, StatusCodes.OK, exos);
}
private async getUserExercises(req: express.Request, res: express.Response) {
if ( req.boundParams.user ) {
if ( req.session.profile.isAdmin || req.session.profile.id === req.boundParams.user.id ) {
return req.session.sendResponse(res, StatusCodes.OK, req.boundParams.user.exercises.filter(exercise => !exercise.deleted));
} else {
return req.session.sendResponse(res, StatusCodes.FORBIDDEN);
}
} else {
return req.session.sendResponse(res, StatusCodes.NOT_FOUND);
}
}
private getExerciseName(assignment: Assignment, members: Array<Gitlab.UserSchema>, suffix: number): string { private getExerciseName(assignment: Assignment, members: Array<Gitlab.UserSchema>, suffix: number): string {
const memberNames: string = members.map(member => member.username).sort((a, b) => a.localeCompare(b)).join(' + '); const memberNames: string = members.map(member => member.username).sort((a, b) => a.localeCompare(b)).join(' + ');
const suffixString: string = suffix > 0 ? ` - ${ suffix }` : ''; const suffixString: string = suffix > 0 ? ` - ${ suffix }` : '';
return `DojoEx - ${ assignment.name } - ${ memberNames }${ suffixString }`; return `DojoEx - ${ assignment.name } - ${ memberNames }${ suffixString }`;
} }
private async getExercise(req: express.Request, res: express.Response) {
return req.session.sendResponse(res, StatusCodes.OK, req.boundParams.exercise!);
}
private async getExerciseMembers(req: express.Request, res: express.Response) { private async getExerciseMembers(req: express.Request, res: express.Response) {
const repoId = req.boundParams.exercise!.gitlabId; const repoId = req.boundParams.exercise!.gitlabId;
...@@ -133,13 +181,6 @@ class ExerciseRoutes implements RoutesManager { ...@@ -133,13 +181,6 @@ class ExerciseRoutes implements RoutesManager {
return `dojo-ex_${ (assignment.gitlabLastInfo as unknown as Gitlab.ProjectSchema).path }_${ exerciseId }`; return `dojo-ex_${ (assignment.gitlabLastInfo as unknown as Gitlab.ProjectSchema).path }_${ exerciseId }`;
} }
// Get all exercise
private async getAllExercises(req: express.Request, res: express.Response) {
const exos = await db.exercise.findMany();
return req.session.sendResponse(res, StatusCodes.OK, exos);
}
private async checkExerciseLimit(assignment: Assignment, members: Array<Gitlab.UserSchema>): Promise<Array<Gitlab.UserSchema>> { private async checkExerciseLimit(assignment: Assignment, members: Array<Gitlab.UserSchema>): Promise<Array<Gitlab.UserSchema>> {
const exercises: Array<Exercise> | undefined = await ExerciseManager.getFromAssignment(assignment.name, false, { members: true }); const exercises: Array<Exercise> | undefined = await ExerciseManager.getFromAssignment(assignment.name, false, { members: true });
...@@ -225,33 +266,42 @@ class ExerciseRoutes implements RoutesManager { ...@@ -225,33 +266,42 @@ class ExerciseRoutes implements RoutesManager {
await repoCreationFnExec(async () => Promise.all([ ...new Set([ ...assignment.staff, ...params.members ].map(member => member.id)) ].map(GlobalHelper.addRepoMember(repository.id))), 'Add repository members error'); await repoCreationFnExec(async () => Promise.all([ ...new Set([ ...assignment.staff, ...params.members ].map(member => member.id)) ].map(GlobalHelper.addRepoMember(repository.id))), 'Add repository members error');
const exercise: Exercise = await repoCreationFnExec(() => db.exercise.create({ let exercise: Exercise = await repoCreationFnExec(() => db.exercise.create({
data: { data: {
id : exerciseId, id : exerciseId,
assignmentName : assignment.name, assignmentName : assignment.name,
name : repository.name, name : repository.name,
secret : secret, secret : secret,
gitlabId : repository.id, gitlabId : repository.id,
gitlabLink : repository.web_url, gitlabLink : repository.web_url,
gitlabCreationInfo: repository as unknown as Prisma.JsonObject, gitlabCreationInfo: repository as unknown as Prisma.JsonObject,
gitlabCreationDate: new Date(), gitlabCreationDate: new Date(),
gitlabLastInfo : repository as unknown as Prisma.JsonObject, gitlabLastInfo : repository as unknown as Prisma.JsonObject,
gitlabLastInfoDate: new Date(), gitlabLastInfoDate: new Date(),
members : { members : {
connectOrCreate: [ ...params.members.map(gitlabUser => { connectOrCreate: [ ...params.members.map(gitlabUser => {
return { return {
create: { create: {
id : gitlabUser.id, id : gitlabUser.id,
gitlabUsername: gitlabUser.name gitlabUsername: gitlabUser.name
}, },
where : { where : {
id: gitlabUser.id id: gitlabUser.id
} }
}; };
}) ] }) ]
} }
} }
})) as Exercise; })) as Exercise;
exercise = await ExerciseManager.get(exercise.id, {
members : true,
assignment: {
include: {
staff: true
}
}
}) as Exercise;
req.session.sendResponse(res, StatusCodes.OK, exercise); req.session.sendResponse(res, StatusCodes.OK, exercise);
return; return;
......
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 SecurityMiddleware from '../middlewares/SecurityMiddleware';
import * as ExpressValidator from 'express-validator';
import ParamsValidatorMiddleware from '../middlewares/ParamsValidatorMiddleware';
import { Prisma, UserRole } from '@prisma/client';
import UserManager from '../managers/UserManager';
class UserRoutes implements RoutesManager {
private readonly usersGetValidator: ExpressValidator.Schema = {
role: {
trim : true,
notEmpty: false,
optional: true
}
};
registerOnBackend(backend: Express) {
backend.get('/users', SecurityMiddleware.check(true), ParamsValidatorMiddleware.validate(this.usersGetValidator), this.getUsers.bind(this) as RequestHandler);
}
private async getUsers(req: express.Request, res: express.Response) {
let roleFilter: Prisma.UserWhereInput | undefined = undefined;
if ( req.query.role ) {
if ( req.query.role === UserRole.ADMIN ) {
roleFilter = {
role: UserRole.ADMIN
};
} else if ( req.query.role === UserRole.TEACHING_STAFF ) {
roleFilter = {
OR: [ {
role: UserRole.ADMIN
}, {
role: UserRole.TEACHING_STAFF
} ]
};
} else if ( req.query.role === UserRole.STUDENT ) {
roleFilter = {
role: UserRole.STUDENT
};
} else {
return req.session.sendResponse(res, StatusCodes.FORBIDDEN);
}
} else if ( !req.session.profile.isAdmin ) {
return req.session.sendResponse(res, StatusCodes.FORBIDDEN);
}
return req.session.sendResponse(res, StatusCodes.OK, await UserManager.getFiltered(roleFilter));
}
}
export default new UserRoutes();
import Session from '../../controllers/Session.js'; import Session from '../../controllers/Session.js';
import { Assignment, Exercise, Tag } from '../DatabaseTypes'; import { Assignment, Exercise, Tag, User } from '../DatabaseTypes';
import { TagProposal } from '@prisma/client'; import { TagProposal } from '@prisma/client';
// to make the file a module and avoid the TypeScript error // to make the file a module and avoid the TypeScript error
export {}; export {};
...@@ -10,7 +10,7 @@ declare global { ...@@ -10,7 +10,7 @@ declare global {
export interface Request { export interface Request {
session: Session, session: Session,
boundParams: { boundParams: {
assignment: Assignment | undefined, exercise: Exercise | undefined, tag: Tag | undefined, tagProposal: TagProposal | undefined user: User | undefined, assignment: Assignment | undefined, exercise: Exercise | undefined, tag: Tag | undefined, tagProposal: TagProposal | undefined
} }
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment