Skip to content

Commit

Permalink
feat(cooment): Add user/manager comment on trip request
Browse files Browse the repository at this point in the history
- add POST user comment on trip request
- add GET comments on a specific trip request

[Start #169258644]
  • Loading branch information
victkarangwa committed Nov 28, 2019
1 parent fe8689d commit e964364
Show file tree
Hide file tree
Showing 15 changed files with 471 additions and 12 deletions.
69 changes: 69 additions & 0 deletions src/controllers/CommentController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { comments, users } from '../database/models';
import Customize from '../helpers/Customize';


/**
* @exports
* @class CommentController
*/
class CommentController {
/**
* users or managers can comment on a travel request
* @static
* @description POST /api/users/:tripRequestId/comment
* @param {object} req request object
* @param {object} res response object
* @memberof CommentController
* @returns {object} data
*/
static async createComment(req, res) {
try {
const { tripRequestId } = req.params;
const { id } = req.user;
const { comment } = req.body;
const userComment = await comments.create({
userId: id,
tripRequestId,
comment

});
if (userComment) {
return Customize.successMessage(req, res, 'Your comment was posted successfully', comment, 201);
}
} catch (e) {
return Customize.errorMessage(req, res, 'Server error', 500);
}
}

/**
* users or managers can view comment thread
* @static
* @description POST /api/users/:tripRequestId/comments
* @param {object} req request object
* @param {object} res response object
* @memberof CommentController
* @returns {object} data
*/
static async getComments(req, res) {
try {
const { tripRequestId } = req.params;
const tripComments = await comments.findAll({
attributes: ['comment', 'updatedAt'],
include: [{
model: users,
attributes: ['firstName', 'lastName']
}],
where: {
tripRequestId,
}
});
if (tripComments[0]) {
return Customize.successMessage(req, res, 'All comments about this trip request have been retrieved successfuly!', tripComments, 200);
}
return Customize.errorMessage(req, res, 'No comments for this trip yet!', 200);
} catch (e) {
Customize.errorMessage(req, res, 'Server error', 500);
}
}
}
export default CommentController;
46 changes: 46 additions & 0 deletions src/database/migrations/20191119162300-create-comments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('comments', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
comment: {
type: Sequelize.STRING,
allowNull: false
},
userId: {
type: Sequelize.INTEGER,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
references: {
model: 'users',
key: 'id',
}
},
tripRequestId: {
type: Sequelize.INTEGER,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
references: {
model: 'tripRequests',
key: 'id',
}
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('comments');
}
};
23 changes: 23 additions & 0 deletions src/database/models/comments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use strict';
module.exports = (sequelize, DataTypes) => {
const comments = sequelize.define('comments', {
comment: DataTypes.STRING,
userId: DataTypes.INTEGER,
tripRequestId: DataTypes.INTEGER,
}, { freezeTableName: true });
comments.associate = function (models) {
comments.belongsTo(models.users, {
foreignKey: 'userId',
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
});

comments.belongsTo(models.tripRequests,{
foreignKey: 'tripRequestId',
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
}
);
};
return comments;
};
6 changes: 3 additions & 3 deletions src/database/seeders/20191115043919-super-admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ module.exports = {
updatedAt: new Date()
},
{
firstName: 'Brian',
lastName: 'Maiyo',
email: 'maiyo.brian@andela.com',
firstName: 'mailer',
lastName: 'manager',
email: 'manager.email@gmail.com',
password: '$2b$10$/Zh5Kwn95d/LPBwjL2VRc.Hpef/XZ2spe6U0eLksDgcxDuroB4XSq',
isVerified: true,
signupType: 'Barefoot',
Expand Down
3 changes: 1 addition & 2 deletions src/helpers/ControllerHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ class ControllerHelper {
const newTrip = await tripRequests.create({
userId, statusId: 1, tripTypeId
});
const request = 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,
Expand Down
20 changes: 20 additions & 0 deletions src/middlewares/Exists.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +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 isTripRequestExist(req, res, next) {
return DataEngine.findOne(
req,
res,
next,
tripRequests,
{ id: req.params.tripRequestId },
'The trip request doen\'t exist'
);
}
}


Expand Down
23 changes: 23 additions & 0 deletions src/middlewares/Validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,5 +145,28 @@ class Validate {
check('bio', 'Please your bio is needed to complete your profile(at least 15 characters)').isLength({ min: 15 })
];
}

/**
* Validate user comment post
* @static
* @returns {object} errors
*/
static commentPostRules() {
return [
check('comment', 'Comment should be of at least two characters').isLength({ min: 2 }),
check('tripRequestId', 'Trip Request Id shopuld be of integer').isInt()
];
}

/**
* Validate user view comments
* @static
* @returns {object} errors
*/
static getCommentsRules() {
return [
check('tripRequestId', 'Trip Request Id shopuld be of integer type').isInt()
];
}
}
export default Validate;
23 changes: 22 additions & 1 deletion src/middlewares/findUsers.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { users } from '../database/models';
import { users, tripRequests } from '../database/models';
import Customize from '../helpers/Customize';

const findOneUser = async (req, res, next) => {
const { email } = req.body;
Expand All @@ -9,4 +10,24 @@ const findOneUser = async (req, res, next) => {
}
next();
};
export const commentAccess = async (req, res, next) => {
const { id } = req.user;
const { tripRequestId } = req.params;
const isManager = await users.findOne({
where: {
id,
roleId: 6,
}
});
const isRequester = await tripRequests.findOne({
where: {
id: tripRequestId,
userId: id,
}
});
if (isManager || isRequester) {
return next();
}
Customize.errorMessage(req, res, 'You should be either a requester or a manager', 403);
};
export default findOneUser;
5 changes: 3 additions & 2 deletions src/middlewares/isManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ const isManager = async (req, res, next) => {
}
});

if (!manager) { Customize.errorMessage(req, res, 'Unknown line manager', 404); }
next();
if (manager) { return next(); }

Customize.errorMessage(req, res, 'Unknown line manager', 404);
};

export default isManager;
113 changes: 113 additions & 0 deletions src/routes/api/commentRoute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import express from 'express';
import Validate from '../../middlewares/Validate';
import checkInputDataError from '../../middlewares/checkInputDataError';
import { commentAccess } from '../../middlewares/findUsers';
import Exists from '../../middlewares/Exists';
import isUserVerified from '../../middlewares/isUserVerified';
import AuthenticateToken from '../../helpers/AuthenticateToken';
import CommentController from '../../controllers/CommentController';

const commentRoute = express.Router();

/**
* @swagger
*
* /trips/{tripRequestId}/comment:
* post:
* summary: User or manager can post a comment
* description: user/manager post comment
* tags:
* - Comment
* parameters:
* - name: token
* in: header
* required: true
* description: user token
* schema:
* type: string
* example: xxxxxxxxx.xxxxxxxxx.xxxxxxxxxx
* minimum: 1
* - name: tripRequestId
* in: path
* required: true
* description: Trip request id
* schema:
* type: integer
* example: 1
* minimum: 1
* requestBody:
* content:
* application/json:
* schema:
* type: object
* properties:
* comment:
* type: string
* responses:
* 201:
* description: Comment posted successfully
* 400:
* description: Unable to post comment
* 401:
* description: Unauthorized
* 403:
* description: Only requesters and managers can post comments
* 500:
* description: Internal server error
*/
commentRoute.post('/:tripRequestId/comment',
AuthenticateToken.verifyToken,
isUserVerified,
Validate.commentPostRules(),
checkInputDataError,
Exists.isTripRequestExist,
commentAccess,
CommentController.createComment);


/**
* @swagger
*
* /trips/{tripRequestId}/comments:
* get:
* summary: User or manager can get a comment
* description: user/manager get comment
* tags:
* - Comment
* parameters:
* - name: token
* in: header
* required: true
* description: user token
* schema:
* type: string
* example: xxxxxxxxx.xxxxxxxxx.xxxxxxxxxx
* minimum: 1
* - name: tripRequestId
* in: path
* required: true
* description: Trip request id
* schema:
* type: integer
* example: 1
* minimum: 1
* responses:
* 200:
* description: Comments retrieved successfully
* 401:
* description: Unauthorized
* 403:
* description: Only requesters and managers can get comments
* 500:
* description: Internal server error
*/
commentRoute.get('/:tripRequestId/comments',
AuthenticateToken.verifyToken,
isUserVerified,
Validate.getCommentsRules(),
checkInputDataError,
Exists.isTripRequestExist,
commentAccess,
CommentController.getComments);

export default commentRoute;
2 changes: 2 additions & 0 deletions src/routes/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import userRoute from './userRoute';
import socialRoute from './socialRoute';
import roleRoute from './roleRoute';
import locationRoute from './locationRoute';
import commentRoute from './commentRoute';

const router = Router();
router.use('/auth', authRoute);
router.use('/auth', socialRoute);
router.use('/trips', tripRoute);
router.use('/trips', commentRoute);
router.use('/users', roleRoute);
router.use('/location', locationRoute);
router.use('/users', userRoute);
Expand Down
Loading

0 comments on commit e964364

Please sign in to comment.