Skip to content

Commit

Permalink
ft(approve request):Add approve request endpoint
Browse files Browse the repository at this point in the history
[Finishes #167727484]
  • Loading branch information
G-Chilie committed Sep 12, 2019
1 parent 3d6c5d0 commit 7c98d9c
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 1 deletion.
30 changes: 30 additions & 0 deletions src/controllers/request.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,4 +217,34 @@ export default class RequestController {
next(new Error('Internal server error'));
}
}

/**
* @param {object} req
* @param {object} res
* @returns {json} request
*/
static async approveRequest(req, res) {
try {
const request = await Request.update(
{
status: 'approved'
}, { returning: true, where: { id: req.params.id } }
);
const requestResult = request[1][0];
const user = await User.findOne({ where: { id: requestResult.user_id } });
const { first_name: firstName, email } = user;
// parameter(s) to be passed to the sendgrid email template
await sender.sendEmail(process.env.SENDER_EMAIL, email, 'request_approved', { firstName, email });
return res.status(201).json({
status: 'success',
data: requestResult
});
} catch (error) {
return res.status(500)
.json({
status: 'error',
error: 'Internal server error',
});
}
}
}
1 change: 1 addition & 0 deletions src/routes/api/requests.router.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ router.get('/requests/:request_id', Auth.verifyToken, RequestController.getSingl

router.post('/request/multi-city', auth.verifyUserToken, RequestController.createMultiCityRequest);
router.get('/requests', Auth.verifyToken, RequestMiddleware.prepareRequestQuery, RequestController.findAll);
router.patch('/requests/approve/:id', auth.verifyUserToken, auth.verifyManager, validateRequests.validateRequestsID, RequestMiddleware.validateRequests, RequestController.approveRequest);

export default router;
3 changes: 2 additions & 1 deletion src/services/email.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ const templates = {
travel_request_notification: 'd-963a476c77a34f318895713712b4d6bb',
signup_template: 'd-1ae0bd2e62c742e9a78009512bd1b5b8',
request_rejected: 'd-ccd25aa2dd9f47cb9d746d909787db59',
passord_reset: 'd-0e43d73f3e3048bba2d124ff5f384107'
passord_reset: 'd-0e43d73f3e3048bba2d124ff5f384107',
request_approved: 'd-ba9b6d3c27d1452f88bc0cf4351cca22'

};

Expand Down
225 changes: 225 additions & 0 deletions src/test/request/approve-request.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
import chai from 'chai';
import chaiHttp from 'chai-http';
import sinon from 'sinon';
import Sinonchai from 'sinon-chai';
import bcrypt from 'bcrypt';
import app from '../../index';
import models from '../../db/models';
import Response from '../../utils/response.utils';

import RequestController from '../../controllers/request.controller';

chai.use(Sinonchai);
chai.use(chaiHttp);
chai.should();

const { expect } = chai;
const { User, Request } = models;

const newUser = {
first_name: 'Linda',
last_name: 'Chinwe',
email: 'linda@gmail.com',
password: 'password124'
};

let testUser;
let adminToken;
const wrongToken = 'TY3MTE4NzEzLCJleHAiOjE1Njc3MjM1MTN9.zjTooik6NGz258I67aIMri4ML78w2pHprL7dVmPwg';

const manager = {
email: 'superadmin@barefootnomad.com',
password: 'superadmin'
};

before((done) => {
bcrypt.hash(newUser.password, 10)
.then((hash) => User.create({
first_name: newUser.first_name,
last_name: newUser.last_name,
email: newUser.email,
password: hash
}))
.then((user) => {
testUser = user;
done();
})
.catch((e) => done(e));
chai
.request(app)
.post('/api/v1/auth/signin')
.send(manager)
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.an('object');
res.body.should.have.property('status').eql('success');
res.body.should.have.property('data');
res.body.data.should.have.property('token');
adminToken = res.body.data.token;
});
});

after((done) => {
User.destroy({
where: {
email: newUser.email
}
})
.then(() => done())
.catch((e) => done(e));
});

describe('REQUESTS', () => {
// Test for approving a request
describe('/PATCH Approve a user\'s Request', () => {
it('it should return unauthorized if user is not logged in', (done) => {
chai.request(app)
.patch('/api/v1/requests/approve/1')
.end((error, res) => {
res.should.have.status(401);
res.body.should.be.an('object');
res.body.should.have.property('status').eql('error');
res.body.should.have.property('error').eql('No token provided!');
done();
});
});

it('it should return error if user trying to login does not exist', (done) => {
chai.request(app)
.post('/api/v1/auth/signin')
.send({ email: 'chinwe@getMaxListeners.com', password: 'emeka@98glob' })
.end((error, res) => {
res.should.have.status(401);
res.body.should.be.an('object');
res.body.should.have.property('status').eql('error');
done();
});
});

it('it should return an error if user is not an admin or manager', (done) => {
chai.request(app)
.post('/api/v1/auth/signin')
.send({
email: newUser.email,
password: newUser.password
})
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.an('object');
res.body.should.have.property('status').eql('success');
res.body.should.have.property('data');
res.body.data.should.have.property('token');
expect(res.body.data.first_name).to.equal(testUser.first_name);
expect(res.body.data.last_name).to.equal(testUser.last_name);
expect(res.body.data.email).to.equal(testUser.email);
const { token } = res.body.data;

chai.request(app)
.patch('/api/v1/requests/approve/2')
.set('x-access-token', token)
.end((error, data) => {
data.should.have.status(401);
data.body.should.have.property('status').eql('error');
data.body.should.have.property('error').eql('Hi! You are not permitted to perform this action');
done();
});
});
});

it('it should return an error if no token is provided', (done) => {
chai.request(app)
.post('/api/v1/auth/signin')
.send({
email: newUser.email,
password: newUser.password
})
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.an('object');
res.body.should.have.property('status').eql('success');
res.body.should.have.property('data');
res.body.data.should.have.property('token');
expect(res.body.data.first_name).to.equal(testUser.first_name);
expect(res.body.data.last_name).to.equal(testUser.last_name);
expect(res.body.data.email).to.equal(testUser.email);

chai.request(app)
.patch('/api/v1/requests/approve/2')
.end((error, data) => {
data.should.have.status(401);
data.body.should.be.an('object');
data.body.should.have.property('status').eql('error');
data.body.should.have.property('error').eql('No token provided!');
done();
});
});
});

it('it should return invalid id if id of the request is not a number', (done) => {
chai
.request(app)
.patch('/api/v1/requests/approve/p')
.set('token', adminToken)
.end((error, data) => {
data.should.have.status(422);
data.body.should.be.an('object');
data.body.should.have.property('status').eql('error');
data.body.should.have.property('error').eql('This id is invalid. ID must be a number!');
done();
});
});

it('it should return an error if a request does not exist', (done) => {
chai
.request(app)
.patch('/api/v1/requests/approve/10')
.set('x-access-token', adminToken)
.end((error, data) => {
data.should.have.status(404);
data.body.should.have.property('status').eql('error');
data.body.should.have.property('error').eql('This request does not exist');
done();
});
});

it('it should fail to authenticate incorrect token', (done) => {
chai
.request(app)
.patch('/api/v1/requests/approve/1')
.set('x-access-token', wrongToken)
.end((error, data) => {
data.should.have.status(401);
data.body.should.have.property('status').eql('error');
data.body.should.have.property('error').eql('Invalid authentication token.');
done();
});
});

it('it should login and allow a manager to approve a user\'s request', (done) => {
chai.request(app)
.patch('/api/v1/requests/approve/1')
.set('authorization', adminToken)
.end((error, data) => {
data.should.have.status(201);
data.body.should.have.property('status').eql('success');
data.body.should.have.property('data');
data.body.data.should.be.an('object');
done();
});
});

it('fakes server error for approve request', (done) => {
const req = { body: {} };
const res = {
status() {},
send() {}
};

sinon.stub(res, 'status').returnsThis();

RequestController.approveRequest(req, res);
(res.status).should.have.callCount(1);
done();
});
});
});

0 comments on commit 7c98d9c

Please sign in to comment.