-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat(Approval or Rejection):changes request status
- Add route for approving or rejecting a request - Add authorization middleware - Add approving or rejecting request validations - Add approving rejecting request controller - Add documantation for this route - Add tests for this route [starts #169817553]
- Loading branch information
1 parent
9351436
commit 315b90c
Showing
11 changed files
with
307 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import RequestService from '../services/request.service'; | ||
import ResponseService from '../services/response.service'; | ||
|
||
/** | ||
* | ||
* | ||
* @class RequestController | ||
*/ | ||
class RequestController { | ||
/** | ||
* | ||
* | ||
* @static | ||
* @param {req} req | ||
* @param {res} res | ||
* @returns {response} @memberof RequestController | ||
*/ | ||
static async updateRequestStatus(req, res) { | ||
const [, [{ dataValues }]] = await RequestService.updateRequest({ id: req.params.requestId }, { status: `${req.body.status}` }); | ||
ResponseService.setSuccess(200, `Request has successfully ${dataValues.status}`, dataValues); | ||
return ResponseService.send(res); | ||
} | ||
} | ||
|
||
export default RequestController; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import express from 'express'; | ||
import RequestController from '../controllers/request.controller'; | ||
import authMiddleware from '../middlewares/auth.middleware'; | ||
import { validateChangingRequestStatus } from '../validations/request.validation'; | ||
|
||
const router = express.Router(); | ||
|
||
router.patch('/:requestId', authMiddleware.checkUserLoggedIn, authMiddleware.checkIfUserIsManager, validateChangingRequestStatus, RequestController.updateRequestStatus); | ||
|
||
export default router; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/** | ||
* @swagger | ||
* definitions: | ||
* Request: | ||
* type: object | ||
* properties: | ||
* status: | ||
* type: string | ||
* required: | ||
* - status | ||
*/ | ||
|
||
/** | ||
* @swagger | ||
* /api/requests/{requestId}: | ||
* patch: | ||
* tags: | ||
* - Request | ||
* name: Request | ||
* summary: A manager should be able to approve or reject requests of his direct report | ||
* produces: | ||
* - application/json | ||
* consumes: | ||
* - application/json | ||
* parameters: | ||
* - in: header | ||
* name: Authorization | ||
* required: true | ||
* type: string | ||
* - name: requestId | ||
* in: path | ||
* - name: status | ||
* in: body | ||
* schema: | ||
* $ref: '#/definitions/Request' | ||
* type: object | ||
* responses: | ||
* '200': | ||
* description: Request approved or rejected successfully | ||
* '400': | ||
* description: invalid parameters. | ||
* '401': | ||
* description: No valid token supplied | ||
* '403': | ||
* description: Unauthorized | ||
* '422': | ||
* description: Rejecting rejected or approved request | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import faker from 'faker'; | ||
import RequestService from '../../services/request.service'; | ||
import { createManagers } from './users.fixture'; | ||
|
||
const createRequest = async () => { | ||
const { manager1 } = await createManagers(); | ||
const request = { | ||
id: faker.random.number(), | ||
requesterId: faker.random.number(), | ||
tripId: faker.random.number(), | ||
status: faker.random.word(), | ||
lineManagerId: manager1.id | ||
}; | ||
const { dataValues } = await RequestService.createRequest(request); | ||
return dataValues; | ||
}; | ||
|
||
export default createRequest; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import chai, { expect } from 'chai'; | ||
import chaiHttp from 'chai-http'; | ||
import app from '../../app'; | ||
import createRequest from '../fixtures/request.fixture'; | ||
import { managerToken1, loggedInToken, managerToken2, createUsers } from '../fixtures/users.fixture'; | ||
|
||
chai.should(); | ||
chai.use(chaiHttp); | ||
|
||
describe('Test rejecting a request:', () => { | ||
let request; | ||
before(async () => { | ||
request = await createRequest(); | ||
await createUsers(); | ||
}); | ||
it('Should return status code of 200 on successful request rejection', (done) => { | ||
chai.request(app) | ||
.patch(`/api/requests/${request.id}`) | ||
.set('Authorization', managerToken1) | ||
.send({ status: 'rejected' }) | ||
.end((err, res) => { | ||
expect(res).to.have.status(200); | ||
expect(res.body).to.have.property('data'); | ||
expect(res.body.data).to.have.property('status'); | ||
expect(res.body.data.status).eqls('rejected'); | ||
done(); | ||
}); | ||
}); | ||
it('Should return status code of 403 for user who is not a manager', (done) => { | ||
chai.request(app) | ||
.patch(`/api/requests/${request.id}`) | ||
.set('Authorization', loggedInToken) | ||
.send({ status: 'rejected' }) | ||
.end((err, res) => { | ||
expect(res).to.have.status(403); | ||
expect(res.body).to.have.property('message'); | ||
expect(res.body.message).eqls('Forbidden. Only Managers can perform this action'); | ||
done(); | ||
}); | ||
}); | ||
it('Should return status code of 400 for invalid requestId parameter', (done) => { | ||
chai.request(app) | ||
.patch('/api/requests/gkkk') | ||
.set('Authorization', managerToken1) | ||
.send({ status: 'rejected' }) | ||
.end((err, res) => { | ||
expect(res).to.have.status(400); | ||
expect(res.body).to.have.property('message'); | ||
expect(res.body.message[0]).eqls('requestId must be a number'); | ||
done(); | ||
}); | ||
}); | ||
it('Should return status code of 404 for requestId which does not exist', (done) => { | ||
chai.request(app) | ||
.patch('/api/requests/44') | ||
.set('Authorization', managerToken1) | ||
.send({ status: 'rejected' }) | ||
.end((err, res) => { | ||
expect(res).to.have.status(404); | ||
expect(res.body).to.have.property('message'); | ||
expect(res.body.message).eqls('This request does not exist'); | ||
done(); | ||
}); | ||
}); | ||
it('Should return status code of 403 for different request line manager', (done) => { | ||
chai.request(app) | ||
.patch(`/api/requests/${request.id}`) | ||
.set('Authorization', managerToken2) | ||
.send({ status: 'rejected' }) | ||
.end((err, res) => { | ||
expect(res).to.have.status(403); | ||
expect(res.body).to.have.property('message'); | ||
expect(res.body.message).eqls('Forbidden. you are not line manager of this request'); | ||
done(); | ||
}); | ||
}); | ||
it('Should return status code of 422 for request which is already rejected', (done) => { | ||
chai.request(app) | ||
.patch(`/api/requests/${request.id}`) | ||
.set('Authorization', managerToken1) | ||
.send({ status: 'rejected' }) | ||
.end((err, res) => { | ||
expect(res).to.have.status(422); | ||
expect(res.body).to.have.property('message'); | ||
expect(res.body.message).eqls('This request is already rejected'); | ||
done(); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,14 +3,15 @@ import ResponseService from '../services/response.service'; | |
import JwtService from '../services/jwt.service'; | ||
import UserService from '../services/user.service'; | ||
import TripService from '../services/trip.service'; | ||
import RequestService from '../services/request.service'; | ||
|
||
/** | ||
* @param {req} req | ||
* @param {req} res | ||
* @param {next} next | ||
* @returns {validation} this function validate request route | ||
*/ | ||
async function requestValidation(req, res, next) { | ||
export async function requestValidation(req, res, next) { | ||
const signInUser = JwtService.verifyToken(req.headers.authorization); | ||
This comment has been minimized.
Sorry, something went wrong. |
||
const { userId } = req.params; | ||
|
||
|
@@ -50,4 +51,37 @@ async function requestValidation(req, res, next) { | |
next(); | ||
} | ||
|
||
export default requestValidation; | ||
export const validateChangingRequestStatus = async (req, res, next) => { | ||
const schema = Joi.object({ | ||
requestId: Joi.number().required(), | ||
status: Joi.string().valid('approved', 'rejected').trim() | ||
.messages({ | ||
'any.only': 'status" must be one of approved or rejected' | ||
}) | ||
.required() | ||
}).options({ abortEarly: false }); | ||
|
||
const results = schema.validate({ ...req.params, ...req.body }); | ||
if (results.error) { | ||
const errorMessages = []; | ||
results.error.details.forEach((error) => { | ||
This comment has been minimized.
Sorry, something went wrong.
higustave-ops
Contributor
|
||
errorMessages.push(error.message.replace(/[^a-zA-Z0-9 .-]/g, '')); | ||
}); | ||
ResponseService.setError(400, errorMessages); | ||
return ResponseService.send(res); | ||
} | ||
const isRequestExist = await RequestService.findTypeByProperty({ id: req.params.requestId }); | ||
if (!isRequestExist) { | ||
ResponseService.setError(404, 'This request does not exist'); | ||
return ResponseService.send(res); | ||
} | ||
if (isRequestExist.dataValues.lineManagerId !== req.userData.id) { | ||
ResponseService.setError(403, 'Forbidden. you are not line manager of this request'); | ||
return ResponseService.send(res); | ||
} | ||
if (req.body.status === isRequestExist.dataValues.status) { | ||
ResponseService.setError(422, `This request is already ${req.body.status}`); | ||
return ResponseService.send(res); | ||
} | ||
next(); | ||
}; |
@gadishimwe You have used
authMiddleware.checkUserLoggedIn
no need to verify token here as that middleware has all checks fortoken
validation