Skip to content

Commit

Permalink
ft(avail request for approval): Add feature that avails requests made…
Browse files Browse the repository at this point in the history
… by users to the manager they report to

- Add get requests route
- Add validations
- Add tests
[Finishes #169258643]
  • Loading branch information
nziokaivy committed Nov 28, 2019
1 parent fe8689d commit 4a1e7c8
Show file tree
Hide file tree
Showing 22 changed files with 236 additions and 75 deletions.
29 changes: 27 additions & 2 deletions src/controllers/TripController.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import Customize from '../helpers/Customize';
import { tripRequests, users } from '../database/models';
import {
tripRequests,
users,
} from '../database/models';
import ControllerHelper from '../helpers/ControllerHelper';
import emailHelper from '../helpers/EmailHelper';
import TripService from '../services/TripService';

const { tripRequestsToSpecificManager } = TripService;

/**
* @export
Expand Down Expand Up @@ -69,6 +74,26 @@ class TripController {
return Customize.errorMessage(req, res, err.message, 500);
}
}
}

/**
* Manager should be able to view requests for approvals
* @static
* @param {object} req request object
* @param {object} res response object
* @memberof TripController
* @returns {object} data
* @description PATCH api/v1/trips/requests
*/
static async getRequestsByManager(req, res) {
const { id } = req.user;
const result = await tripRequestsToSpecificManager(id);
try {
if (result) {
return Customize.successMessage(req, res, 'Requests fetched successfully', result, 200);
}
} catch (error) {
return Customize.errorMessage(req, res, 'Oops! internal server error', 500);
}
}
}
export default TripController;
2 changes: 0 additions & 2 deletions src/controllers/UserController.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,6 @@ class UserController {
Customize.errorMessage(req, res, 'Unable to update your profile', HttpStatus.BAD_REQUEST);
}
} catch (e) {
console.log(e);

Customize.errorMessage(req, res, e, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ module.exports = {
type: Sequelize.STRING
},
managerId: {
type: Sequelize.INTEGER
type: Sequelize.INTEGER,
},
bio: {
type: Sequelize.STRING
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ module.exports = {
onUpdate: 'CASCADE',
defaultValue: 1 ,
},

createdAt: {
allowNull: false,
type: Sequelize.DATE
Expand Down
2 changes: 1 addition & 1 deletion src/database/models/tripRequests.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ module.exports = (sequelize, DataTypes) => {
{onUpdate: 'cascade'});
tripRequests.hasMany(
models.trips,
{foreignKey: 'id'},
{targetKey: 'tripRequestId'},
{ onDelete: 'cascade'},
{onUpdate: 'cascade'});
};
Expand Down
7 changes: 6 additions & 1 deletion src/database/models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@ module.exports = (sequelize, DataTypes) => {
}, {});
users.associate = function(models) {
users.hasMany(models.tripRequests,
{foreignKey: 'id'},
{targetKey: 'userId'},
{ onDelete: 'cascade'},
{onUpdate: 'cascade'}
);
users.hasOne(models.userProfile,
{foreignKey: 'id'},
{ onDelete: 'cascade'},
{onUpdate: 'cascade'}
);
};
return users;
};
15 changes: 14 additions & 1 deletion src/database/seeders/20191114145912-users.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module.exports = {
lastName: 'Doe',
email: 'demo@gmail.com',
password: '$2b$10$Q9H0gYzslg.oIvqoiWBEfesJoe.HTQT0Ezg5itN/h0a5Mf9gxWWvq',
roleId: 3,
roleId: 6,
isVerified: true,
signupType:'default',
createdAt: new Date(),
Expand All @@ -21,6 +21,7 @@ module.exports = {
password: '$2b$10$EVp9ow6OlwEldRIaXTdOB.sqG3zqyMUnOzNuAvaiVqzk6OvPcmSDC',
signupType: 'Barefoot',
isVerified: true,
roleId: 3,
createdAt: new Date(),
updatedAt: new Date()
},
Expand All @@ -30,6 +31,18 @@ module.exports = {
email: 'mytest@myemail.com',
password: '$2b$10$EVp9ow6OlwEldRIaXTdOB.sqG3zqyMUnOzNuAvaiVqzk6OvPcmSDC',
signupType: 'Barefoot',
roleId: 3,
isVerified: true,
createdAt: new Date(),
updatedAt: new Date()
},
{
firstName: 'Mary',
lastName: 'Doe',
email: 'marydoe@gmail.com',
password: 'Merry@12345',
signupType: 'Barefoot',
roleId: 3,
isVerified: true,
createdAt: new Date(),
updatedAt: new Date()
Expand Down
2 changes: 1 addition & 1 deletion src/database/seeders/20191114145913-user-profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ module.exports = {
address: null,
imageURL:null,
department: null,
managerId: null,
managerId: 5,
bio: null,
createdAt: new Date(),
updatedAt: new Date()
Expand Down
2 changes: 1 addition & 1 deletion src/database/seeders/20191115043919-super-admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ module.exports = {
{
firstName: 'Brian',
lastName: 'Maiyo',
email: 'maiyo.brian@andela.com',
email: 'manager.email@gmail.com',
password: '$2b$10$/Zh5Kwn95d/LPBwjL2VRc.Hpef/XZ2spe6U0eLksDgcxDuroB4XSq',
isVerified: true,
signupType: 'Barefoot',
Expand Down
6 changes: 3 additions & 3 deletions src/helpers/ControllerHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ class ControllerHelper {
const newTrip = await tripRequests.create({
userId, statusId: 1, tripTypeId
});
const request = await tripRequests.findOne({ where: { userId } });
await tripRequests.findOne({ where: { userId } });
itinerary.forEach(async (item) => {
await trips.create({
tripRequestId: request.dataValues.id,
tripRequestId: newTrip.dataValues.id,
originId: item.originId,
destinationId: item.destinationId,
reason: item.reason,
startDate: item.startDate,
returnDate: item.returnDate
returnDate: item.returnDate,
});
});
emailHelper.approveEmailHelper(req, process.env.MANAGER_EMAIL);
Expand Down
27 changes: 23 additions & 4 deletions src/middlewares/Exists.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import DataEngine from './DataEngine';
import { tripRequests } from '../database/models';

import { tripRequests, userProfile } from '../database/models';
import Customize from '../helpers/Customize';
/**
* @export
* @class Exists
Expand All @@ -25,7 +25,26 @@ class Exists {
'The trip is either approved rejected or it doesn\'t exist'
);
}
}


/**
* check is the request exist
* @static
* @param {object} req request object
* @param {object} res response object
* @param {object} next next
* @memberof Exists
* @returns {object} data
*/
static async getLineManager(req, res, next) {
// const { managerId } = req.body;
const { id } = req.user;
const userIdProfile = await userProfile.findOne({ where: { userId: id } });
if (!userIdProfile.managerId) {
return Customize.errorMessage(req, res, 'Please update your line manager', 404);
}
const { managerId } = userProfile;
req.body.managerId = managerId;
return next();
}
}
export default Exists;
29 changes: 29 additions & 0 deletions src/middlewares/TripMiddlewares.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { userProfile } from '../database/models';
import Customize from '../helpers/Customize';

/**
* @export
* @class TripMiddleware
*/
class TripMiddleware {
/**
* Get line manager for trip requests
* @static
* @param {object} req request object
* @param {object} res response object
* @param {object} next next
* @memberof TripMiddleware
* @returns {object} data
*/
static async getLineManager(req, res, next) {
const { id } = req.user;
const userIdProfile = await userProfile.findOne({ where: { userId: id } });
if (!userIdProfile.managerId) {
return Customize.errorMessage(req, res, 'Please update your line manager', 404);
}
const { managerId } = userProfile;
req.body.managerId = managerId;
return next();
}
}
export default TripMiddleware;
14 changes: 0 additions & 14 deletions src/middlewares/Validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,20 +108,6 @@ class Validate {
];
}

/**
* Validate input
* @static
* @returns {object} errors
*/
static oneWayTripRules() {
return [
check('originId', 'originId should be an integer').isNumeric(),
check('destinationId', 'destinationId should be an integer').isNumeric(),
check('reason', 'Reason should be a minimum of 2 letters').isString().isLength({ min: 2 }),
check('startDate', 'Start date should be a valid date after today(YY-MM-DD) ').isAfter().isISO8601(),
];
}

/**
* Validate input
* @static
Expand Down
4 changes: 3 additions & 1 deletion src/middlewares/ValidateTrip.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ export default class ValidateTrip {
const userCitiesArr = [];

const AllCitiesArr = allCities.map((singleCity) => singleCity.id);
itinerary.forEach((singleCity) => userCitiesArr.push(singleCity.originId, singleCity.destinationId));
itinerary.forEach((singleCity) => userCitiesArr.push(
singleCity.originId, singleCity.destinationId
));

const cityExist = userCitiesArr.every((val) => AllCitiesArr.indexOf(val) !== -1);

Expand Down
1 change: 0 additions & 1 deletion src/middlewares/isRoledifferent.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ const isRoledifferent = async (req, res, next) => {
let status;

if (existingEmail === assignEmail) {

status = 403;
return Customize.errorMessage(req, res, 'you are not allowed to change your access', status);
}
Expand Down
38 changes: 33 additions & 5 deletions src/routes/api/tripRoute.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,26 @@ import ValidateTrip from '../../middlewares/ValidateTrip';
import Validate from '../../middlewares/Validate';
import checkInputDataError from '../../middlewares/checkInputDataError';
import Exists from '../../middlewares/Exists';

import TripMiddleware from '../../middlewares/TripMiddlewares';
import VerifyUserRoles from '../../middlewares/VerifyUserRoles';

const tripRouter = express.Router();
const { verifyToken } = AuthenticateToken;

const { returnTripController, OneWayTripController } = TripController;
const { getLineManager } = TripMiddleware;
const { returnTripController, OneWayTripController, getRequestsByManager } = TripController;

tripRouter.post('/oneway',
verifyToken,
Validate.requestOnewayTripRules(),
checkInputDataError,
getLineManager,
ValidateTrip.checkIfOriginDestinationExists,
ValidateTrip.checkIfOriginSameAsDestination,
ValidateTrip.checkMultiCityForSimilarRequests,
ValidateTrip.checkForSimilarRequests,
ValidateTrip.checkForSimilarRequestsDateRange,
OneWayTripController);


/**
* @swagger
*
Expand Down Expand Up @@ -68,6 +69,7 @@ tripRouter.post(
AuthenticateToken.verifyToken,
Validate.requestMultiTripRules(),
checkInputDataError,
getLineManager,
ValidateTrip.checkIfOriginDestinationExists,
ValidateTrip.checkIfOriginSameAsDestination,
ValidateTrip.checkMultiCityForSimilarRequests,
Expand Down Expand Up @@ -172,7 +174,7 @@ tripRouter.post('/twoWay',
verifyToken,
Validate.twoWayTripRules(),
checkInputDataError,

getLineManager,
ValidateTrip.checkIfOriginDestinationExists,
ValidateTrip.checkIfOriginSameAsDestination,
ValidateTrip.checkMultiCityForSimilarRequests,
Expand Down Expand Up @@ -239,4 +241,30 @@ tripRouter.post('/twoWay',
*
*/

tripRouter.get('/requests',
verifyToken,
VerifyUserRoles.isManager,
getRequestsByManager);

/**
* @swagger
*
* /trips/requests:
* get:
* summary: Available requests to manager for approval
* tags: [Trip]
* parameters:
* - name: token
* in: header
* description: enter token
* required: true
* schema:
* type: string
* responses:
* "200":
* description: Trip requests fetched successfuly
* "404":
* description: Trip requests are not found
*/

export default tripRouter;
43 changes: 43 additions & 0 deletions src/services/TripService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import database from '../database/models';

/**
* Find a specific user.
* @param {object} object The user object.
* @returns {object} A specific user object.
*/
class TripService {
/**
* Manager should be able to view approvals
* @static
* @param {object}id object
* @memberof UserController
* @returns {object} data
*/
static async tripRequestsToSpecificManager(id) {
return database.userProfile.findAll({
where: { managerId: id },
attributes: ['id', 'userId'],
include: [
{
model: database.users,
attributes: ['id', 'firstName', 'lastName'],
as: 'user',
include: [
{
model: database.tripRequests,
where: { statusId: 1 },
attributes: ['id', 'tripTypeId', 'statusId'],
include: [
{
model: database.trips
}
]
}
],
}
],
});
}
}

export default TripService;
Loading

0 comments on commit 4a1e7c8

Please sign in to comment.