Skip to content

Commit

Permalink
feat(employees): get employee list
Browse files Browse the repository at this point in the history
- create controller to get employees

- only accessible by manager and super admin

[Finishes (#168427812)]
  • Loading branch information
Mcdavid95 committed Sep 17, 2019
1 parent cad36b5 commit 2ace848
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 12 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,4 @@
"sourceMap": false,
"instrument": false
}
}
}
10 changes: 8 additions & 2 deletions src/controllers/requestController.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,18 @@ const requestTrip = async (req, res) => {
*/
const getUserRequest = async (req, res) => {
try {
const { decoded: { id, roleId }, query: { page, perPage, userId, approvalStatus } } = req;
const {
decoded: { id, roleId }, query: {
page, perPage, userId, approvalStatus
}
} = req;
if (userId && (userId !== id && roleId !== roles.SUPER_ADMIN)) {
return response(res, 403, 'error', { message: unauthorizedUserRequest });
}
const { limit, offset } = calculateLimitAndOffset(page, perPage);
const options = { where: { userId: userId || id }, order: [['updatedAt', 'ASC']], limit, offset };
const options = {
where: { userId: userId || id }, order: [['updatedAt', 'ASC']], limit, offset
};
if (approvalStatus) {
options.where.approvalStatus = approvalStatus;
}
Expand Down
27 changes: 24 additions & 3 deletions src/controllers/userController.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@ import roleEmailMessage from '../utils/templates/roleEmailMessage';
import createTemplate from '../utils/createTemplate';
import sendMail from '../utils/sendMail';
import DbServices from '../services/dbServices';
import { calculateLimitAndOffset, paginate } from '../utils/pagination';

const { User, Role, Tokenblacklist } = models;
const { getById, update, getByOptions } = DbServices;
const {
unauthorizedUserProfile, serverError, phoneExists, roleChanged, unauthorizedUserRequest
getById, update, getByOptions, getAll
} = DbServices;
const {
unauthorizedUserProfile, serverError, phoneExists, roleChanged, unauthorizedUserRequest, noUser
} = messages;
const { FRONTEND_BASE_URL } = process.env;

Expand Down Expand Up @@ -273,6 +276,23 @@ const resetPassword = async (req, res) => {
}
};

const getEmployeeList = async (req, res) => {
try {
const { decoded: { id, roleId }, query: { page, perPage } } = req;
const { limit, offset } = calculateLimitAndOffset(page, perPage);
const options = { limit, offset };
if (roleId === roles.MANAGER) {
options.where = { lineManager: id };
}
const { rows, count } = await getAll(User, options);
if (rows.length === 0) return response(res, 200, 'success', { message: noUser });
const meta = paginate(page, perPage, count, rows);
return response(res, 200, 'success', { employees: rows, meta });
} catch (error) {
return response(res, 500, 'error', { message: serverError });
}
};

export default {
signUp,
socialAuth,
Expand All @@ -282,5 +302,6 @@ export default {
updateUserDetails,
forgotPassword,
resetPassword,
setUserRole
setUserRole,
getEmployeeList
};
10 changes: 10 additions & 0 deletions src/database/seeders/20190819153902-user.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ export default {
verified: true,
roleId: roles.MANAGER,
},
{
id: '68eb202e-3f67-4eed-b7ac-9c31bc226e0c',
firstName: 'manna',
lastName: 'from',
email: 'mannafrom@heaven.com',
password: hashPassword('Password'),
phoneNo: '2347033510645',
verified: true,
roleId: roles.MANAGER,
},
{
id: '122a0d86-8b78-4bb8-b28f-8e5f7811c456',
firstName: 'James',
Expand Down
7 changes: 7 additions & 0 deletions src/models/accommodation.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ module.exports = (sequelize, DataTypes) => {
defaultValue: ['https://res.cloudinary.com/kola-c-1/image/upload/v1568114881/barefootnomad-images/default-accomodation-image_iqbuvj.svg']
}
});
Accommodation.associate = (models) => {
// associations can be defined here
Accommodation.hasMany(models.AccommodationLike, {
foreignKey: 'accommodationId',
as: 'likes'
});
};

Accommodation.associate = (models) => {
Accommodation.hasMany(models.Rating, {
Expand Down
40 changes: 38 additions & 2 deletions src/routes/api/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import userController from '../../controllers/userController';
import validate from '../../middlewares/validator';
import {
signUpSchema, signInSchema, updateUserSchema, getUserSchema,
setUserRoleSchema, emailSchema, passwordSchema
setUserRoleSchema, emailSchema, passwordSchema, getEmployeesSchema
} from '../../validation/userSchema';
import checkBlacklist from '../../middlewares/blacklistMiddleware';
import verifyEmailController from '../../controllers/emailVerificationController';
Expand All @@ -12,6 +12,8 @@ import roles from '../../utils/roles';
import multerUploads from '../../middlewares/multer';
import uploadImage from '../../middlewares/imageUploader';

const { MANAGER, SUPER_ADMIN } = roles;

const {
signUp,
signIn,
Expand All @@ -21,6 +23,7 @@ const {
forgotPassword,
resetPassword,
setUserRole,
getEmployeeList
} = userController;

const {
Expand Down Expand Up @@ -459,7 +462,40 @@ const userRoute = (router) => {
* - bearerAuth: []
*/
.patch(checkToken, checkBlacklist, validate(setUserRoleSchema),
authorize([roles.SUPER_ADMIN]), checkUserId, setUserRole);
authorize([SUPER_ADMIN]), checkUserId, setUserRole);

router.route('/employees')
/**
* @swagger
* paths:
* /api/v1/employees:
* get:
* tags:
* - Users
* summary: Get list of employees
* parameters:
* - in: query
* name: page
* schema:
* type: number
* required: false
* - in: query
* name: perPage
* schema:
* type: number
* required: false
* responses:
* 200:
* description: employees fetched successfully
* 404:
* description: User not found
* 500:
* description: Internal Server error
* security:
* - bearerAuth: [ ]
*/
.get(checkToken, checkBlacklist, authorize([SUPER_ADMIN, MANAGER]),
validate(getEmployeesSchema), getEmployeeList);
};

export default userRoute;
3 changes: 2 additions & 1 deletion src/test/mockData/userMock.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,6 @@ export default {
requesterId: '83b2a3e7-9ba4-4d3f-b3a3-d31940ee2edc',
noLineManager: '38eb202c-3f67-4eed-b7ac-9c31bc226e0c',
validLineManager: '38eb202c-3f67-4eed-b7ac-9c31bc226e0c',
editRequesterUserId: 'c1b0a0fc-7536-4152-8837-6a5348ba9566'
editRequesterUserId: 'c1b0a0fc-7536-4152-8837-6a5348ba9566',
newManager: '68eb202e-3f67-4eed-b7ac-9c31bc226e0c'
};
50 changes: 48 additions & 2 deletions src/test/routes/user.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ const { User } = models;

const BACKEND_BASE_URL = '/api/v1';

let token, invalidToken, managerToken;
let token, invalidToken, managerToken, newManagerToken, requesterToken;

before(async () => {
const jwtToken = generateToken({ id: userMock.userId, roleId: roles.SUPER_ADMIN });
token = jwtToken;
invalidToken = generateToken({ id: userMock.wrongId });
managerToken = generateToken({ id: userMock.anotherUserId });
requesterToken = generateToken({ id: userMock.requesterId, roleId: roles.REQUESTER });
managerToken = generateToken({ id: userMock.anotherUserId, roleId: roles.MANAGER });
newManagerToken = generateToken({ id: userMock.newManager, roleId: roles.MANAGER });
});

describe('User route', () => {
Expand All @@ -30,6 +32,20 @@ describe('User route', () => {
expect(response.status).to.equal(200);
expect(response.body.status).to.equal('success');
});

it('should get user details', async () => {
const response = await chai.request(app).get(`${BACKEND_BASE_URL}/users`)
.set('authorization', token);
expect(response.status).to.equal(200);
expect(response.body.status).to.equal('success');
});

it('should return 403 for unauthorized access', async () => {
const response = await chai.request(app).get(`${BACKEND_BASE_URL}/users/?userId=${userMock.userId}`)
.set('authorization', requesterToken);
expect(response.status).to.equal(403);
expect(response.body.status).to.equal('error');
});
});

describe('PUT /users/:userId', () => {
Expand Down Expand Up @@ -217,4 +233,34 @@ describe('User route', () => {
stub.restore();
});
});
describe('GET: /employees', () => {
it('should get list of employees for a manager', async () => {
const response = await chai.request(app).get(`${BACKEND_BASE_URL}/employees`)
.set('Content-Type', 'application/json')
.set('authorization', managerToken);
expect(response.status).to.equal(200);
});

it('should get list of employees for a super admin', async () => {
const response = await chai.request(app).get(`${BACKEND_BASE_URL}/employees`)
.set('Content-Type', 'application/json')
.set('authorization', token);
expect(response.status).to.equal(200);
});

it('should return a message if list of employees is empty', async () => {
const { status, body: { data: { message } } } = await chai.request(app).get(`${BACKEND_BASE_URL}/employees`)
.set('Content-Type', 'application/json')
.set('authorization', newManagerToken);
expect(status).to.equal(200);
expect(message).to.equal(messages.noUser);
});

it('should get list of employees for a super admin paginated', async () => {
const { status } = await chai.request(app).get(`${BACKEND_BASE_URL}/employees?page=2&perPage=2`)
.set('Content-Type', 'application/json')
.set('authorization', token);
expect(status).to.equal(200);
});
});
});
1 change: 1 addition & 0 deletions src/utils/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const messages = {
notificationsCleared: 'Notifications cleared!',
noLocation: 'Office Location not found',
imageError: 'Error proccessing image',
noUser: 'No user to display',
};

export default messages;
8 changes: 7 additions & 1 deletion src/validation/userSchema.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Joi from '@hapi/joi';
import JoiValidator from './JoiValidator';

const validNum = JoiValidator.validateNumber().min(1);

const signUpSchema = Joi.object({
email: JoiValidator.validateEmail().required(),
Expand Down Expand Up @@ -41,6 +42,11 @@ const getUserSchema = Joi.object({
userId: JoiValidator.validateUuidV4(),
});

const getEmployeesSchema = Joi.object({
page: validNum,
perPage: validNum
});

const setUserRoleSchema = Joi.object({
userId: JoiValidator.validateUuidV4().required(),
role: JoiValidator.validateString()
Expand All @@ -49,5 +55,5 @@ const setUserRoleSchema = Joi.object({

export {
signUpSchema, signInSchema, updateUserSchema, getUserSchema,
setUserRoleSchema, emailSchema, passwordSchema
setUserRoleSchema, emailSchema, passwordSchema, getEmployeesSchema
};

0 comments on commit 2ace848

Please sign in to comment.