Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable validation and deletion for exchanges #19

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 139 additions & 13 deletions src/controller/ExchangeController.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,39 @@
import { NextFunction, Request, Response, Router } from 'express';
import { check, ValidationError, validationResult } from 'express-validator';
import { exchangeStatus } from '../entity/Exchange';
import { ExchangeStatus } from '../entity/Exchange';
import { ExchangeService } from '../services/ExchangeService';
import CallBack from '../services/FunctionStatusCode';
import Logger from '../services/Logger';
import { UserService } from '../services/UserService';

export class ExchangeController {

private exchangeService: ExchangeService;
private userService: UserService;
public router: Router;

constructor() {
this.exchangeService = new ExchangeService();
this.userService = new UserService();
this.router = Router();
this.routes();
}

public routes() {
this.router.get('/:id', this.getOne);
this.router.get('/', this.getExchanges);
this.router.get('/:id', this.getOne);
this.router.get('/:id/validate', this.validateExchange)
this.router.get('/:id/cancel', this.cancelExchange)
this.router.post(
'/',
[
check('suggesterStudent')
.exists().withMessage('Field "suggesterStudent" is missing')
.isNumeric().trim().escape(),
.isUUID().trim().escape(),
check('aimStudent')
.exists().withMessage('Field "aimStudent" is missing')
.isNumeric().trim().escape(),
.isUUID().custom((value, { req }) => value !== req.body.suggesterStudent).withMessage('Field "aimStudent" must be different from "suggesterStudent"')
.trim().escape(),
check('exchangedTimeslot')
.exists().withMessage('Field "exchangedTimeslot" is missing')
.isNumeric().trim().escape(),
Expand All @@ -37,19 +43,21 @@ export class ExchangeController {
check('status')
.exists().withMessage('Field "status" is missing').
custom((value: String) => {
return (Object.values(exchangeStatus) as String[]).includes(value);
return (Object.values(ExchangeStatus) as String[]).includes(value);
}).trim().escape(),
],
this.postOne);
this.router.put(
'/:id',
[
check('suggesterStudent').isNumeric().trim().escape(),
check('aimStudent').isNumeric().trim().escape(),
check('suggesterStudent').isUUID().trim().escape(),
check('aimStudent')
.isUUID().custom((value, { req }) => value !== req.body.suggesterStudent).withMessage('Field "aimStudent" must be different from "suggesterStudent"')
.trim().escape(),
check('exchangedTimeslot').isNumeric().trim().escape(),
check('desiredTimeslot').isNumeric().trim().escape(),
check('status').custom((value: String) => {
return (Object.values(exchangeStatus) as String[]).includes(value);
return (Object.values(ExchangeStatus) as String[]).includes(value);
}).trim().escape(),
],
this.putOne);
Expand All @@ -72,18 +80,136 @@ export class ExchangeController {
* GET exchange by id
* @param req Express Request
* @param res Express Response
* @param next Express NextFunction
*/
public getOne = async (req: Request, res: Response, next: NextFunction) => {
const exchangeId = req.params.id;
if (exchangeId === undefined || exchangeId === null) {
res.status(400).send("Error, parameter id is missing or wrong").end();
return;
} else {
res.send(await this.exchangeService.findById(parseInt(exchangeId, 10)))
return;
}
}

/**
* Validate the exchange
* @param req Express Request
* @param res Express Response
* @param next Express NextFunction
* @returns
*/
public getOne = async (req: Request, res: Response, next: NextFunction) => {
public validateExchange = async (req: Request, res: Response, next: NextFunction) => {
const exchangeId = req.params.id;
if (typeof exchangeId === undefined || exchangeId === null) {
res.status(400).send("Error, parameter id is missing or wrong");
if (exchangeId === undefined || exchangeId === null) {
res.status(400).send("Error, parameter id is missing or wrong").end();
return;
} else {
// Get the exchange to validate
const exchange = await this.exchangeService.findById(parseInt(exchangeId, 10));

if (exchange !== undefined) {
// Verify that the user who validate is the right one
const user = await this.userService.findById(res.locals.user.id);
if (user === undefined) {
Logger.error("User no found => id: " + res.locals.user.id);
res.status(403).send("Unauthorized").end();
return;
} else {
// Body validation is now complete
const responseCode = await this.exchangeService.validate(exchange, user);

switch (responseCode) {
case CallBack.Status.DB_ERROR: {
res.status(404)
.send("An error occurred while validating the exchange. Please try later and verify values sent").end();
break;
}
case CallBack.Status.LOGIC_ERROR: {
res.status(401)
.send("Unauthorized to validate this exchange")
.end();
break;
}
case CallBack.Status.FAILURE: {
res.status(404)
.send("Fail to validate the exchange. Please try later or verify values sent")
.end();
break;
}
case CallBack.Status.SUCCESS: {
res.end();
break;
}
default:
res.end();
break;
}
}
} else {
Logger.error("Exchange not found => id: " + exchangeId);
res.status(404).send("Entity not found").end();
return;
}
}
else{
res.send(await this.exchangeService.findUser(parseInt(exchangeId, 10)))
}

/**
* Cancel the exchange
* @param req Express Request
* @param res Express Response
* @param next Express NextFunction
* @returns
*/
public cancelExchange = async (req: Request, res: Response, next: NextFunction) => {
const exchangeId = req.params.id;
if (exchangeId === undefined || exchangeId === null) {
res.status(400).send("Error, parameter id is missing or wrong").end();
return;
} else {
// Get the exchange to validate
const exchange = await this.exchangeService.findById(parseInt(exchangeId, 10));

if (exchange !== undefined) {
// Verify that the user who validate is the right one
const user = await this.userService.findById(res.locals.user.id);
if (user === undefined) {
Logger.error("User no found => id: " + res.locals.user.id);
res.status(403).send("Unauthorized").end();
} else {
// Body validation is now complete
const responseCode = await this.exchangeService.cancel(exchange, user);
switch (responseCode) {
case CallBack.Status.DB_ERROR: {
res.status(404)
.send("An error occurred while validating the exchange. Please try later and verify values sent").end();
break;
}
case CallBack.Status.LOGIC_ERROR: {
res.status(401)
.send("Unauthorized to validate this exchange")
.end();
break;
}
case CallBack.Status.FAILURE: {
res.status(404)
.send("Fail to validate the exchange. Please try later or verify values sent")
.end();
break;
}
case CallBack.Status.SUCCESS: {
res.end();
break;
}
default: break;
}
}
} else {
Logger.error("Exchange not found => id: " + exchangeId);
res.status(404).send("Entity not found").end();
return;
}
}
}

Expand Down
30 changes: 19 additions & 11 deletions src/entity/Exchange.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn, Unique } from "typeorm";
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn, Unique, UpdateDateColumn } from "typeorm";
import { TimeSlot } from "./TimeSlot";
import { User } from "./User";

export enum exchangeStatus {
export enum ExchangeStatus {
'PENDING' = 'PENDING',
'ACCEPTED' ='ACCEPTED',
'VALIDATED' ='VALIDATED'
'SUGGESTER_STUDENT_ACCEPTED' = 'SUGGESTER_STUDENT_ACCEPTED',
'AIM_STUDENT_VALIDATED' = 'AIM_STUDENT_VALIDATED',
'VALIDATED' = 'VALIDATED',
'SUGGESTER_STUDENT_CANCELLED' = 'SUGGESTER_STUDENT_CANCELLED',
'AIM_STUDENT_CANCELLED' = 'AIM_STUDENT_CANCELLED',
'CANCELLED' = 'CANCELLED'
};

/**
Expand All @@ -17,26 +21,30 @@ export enum exchangeStatus {
export class Exchange {

@PrimaryGeneratedColumn()
id?: number;
id!: number;

@Column({
type: "enum",
enum: ["PENDING" , "ACCEPTED" , "VALIDATED"],
enum: ["PENDING" , "SUGGESTER_STUDENT_ACCEPTED", "AIM_STUDENT_VALIDATED", "VALIDATED" , "SUGGESTER_STUDENT_CANCELLED",
"AIM_STUDENT_CANCELLED", "CANCELLED"],
default: "PENDING"
})
status?: String = exchangeStatus.PENDING;
status: String = ExchangeStatus.PENDING;

@UpdateDateColumn()
readonly updatedAt!: Date;

@ManyToOne(() => TimeSlot, timeSlot => timeSlot.id)
exchangedTimeslot?: TimeSlot;
exchangedTimeslot!: TimeSlot;

@ManyToOne(() => TimeSlot, timeSlot => timeSlot.id)
desiredTimeslot?: TimeSlot;
desiredTimeslot!: TimeSlot;

@ManyToOne(() => User, user => user.id)
suggesterStudent?: User;
suggesterStudent!: User;

@ManyToOne(() => User, user => user.id)
aimStudent?: User;
aimStudent!: User;

/**
* Constructor for Exchange
Expand Down
11 changes: 6 additions & 5 deletions src/repository/ExchangeRepository.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { EntityRepository, Repository } from "typeorm";
import { Exchange, exchangeStatus } from "../entity/Exchange";
import { Exchange, ExchangeStatus } from "../entity/Exchange";
import { User } from "../entity/User";

@EntityRepository(Exchange)
export class ExchangeRepository extends Repository<Exchange> {

public findOneWithRelations = (id: number) => {
return this.createQueryBuilder('exchange')
.where("exchange.id = :id", { id })
.where("exchange.id = :id", { id })
.innerJoinAndSelect('exchange.exchangedTimeslot', 'exchangedTimeslot')
.innerJoinAndSelect('exchange.desiredTimeslot', 'desiredTimeslot')
.innerJoinAndSelect('exchange.suggesterStudent', 'suggesterStudent')
.innerJoinAndSelect('exchange.aimStudent', 'aimStudent')
.getOne()
.getOne();
}

public findWithRelations = () => {
Expand All @@ -20,10 +21,10 @@ export class ExchangeRepository extends Repository<Exchange> {
.innerJoinAndSelect('exchange.desiredTimeslot', 'desiredTimeslot')
.innerJoinAndSelect('exchange.suggesterStudent', 'suggesterStudent')
.innerJoinAndSelect('exchange.aimStudent', 'aimStudent')
.getMany()
.getMany();
}

public findByStatus = (status: exchangeStatus) => {
public findByStatus = (status: ExchangeStatus) => {
return this.createQueryBuilder("exchange")
.where("exchange.status = :status", { status })
.getMany();
Expand Down
2 changes: 1 addition & 1 deletion src/repository/TimeSlotRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class TimeSlotRepository extends Repository<TimeSlot> {
public findById = (id: number) => {
return this.createQueryBuilder("timeSlots")
.innerJoinAndSelect("timeSlots.course", "course")
.innerJoinAndSelect("timeSlots.users", "user")
.innerJoinAndSelect("timeSlots.users", "users")
.where("timeSlots.id = :id", { id })
.getOne()
}
Expand Down
Loading