Skip to content

Commit

Permalink
ft(edit/delete comment):user can edit/delet his comment
Browse files Browse the repository at this point in the history
add editcomment function
add deleteComment function
[finishes #168781696]
  • Loading branch information
sabin18 committed Oct 31, 2019
1 parent fc0753a commit 2bffdf8
Show file tree
Hide file tree
Showing 12 changed files with 292 additions and 101 deletions.
132 changes: 66 additions & 66 deletions package-lock.json

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions src/controllers/commentsController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import strings from '../utils/stringsUtil';
import commentsHelper from '../helpers/commentsHelper';

const { COMMENT_UPDATED, COMMENT_DELETED } = strings.comments.success;

export default class CommentsController {
static editComment(req, res) {
const { id } = req.params;
const { comment } = req.body;

commentsHelper.findComment(req).then(async comments => {
await commentsHelper.checkComment(
req, comments, res, { comment }, id,
COMMENT_UPDATED, comments
);
});
}

static deleteComment(req, res) {
const { id } = req.params;

commentsHelper.findComment(req).then(async comments => {
await commentsHelper.checkComment(
req, comments, res, { deleted: true }, id,
COMMENT_DELETED, comments
);
});
}
}
36 changes: 36 additions & 0 deletions src/database/migrations/20191029094125-create-comments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'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
},
userId: {
type: Sequelize.INTEGER
},
requestId: {
type: Sequelize.INTEGER
},
deleted: {
type: Sequelize.BOOLEAN
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('comments');
}
};
13 changes: 1 addition & 12 deletions src/database/models/comments.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,10 @@ module.exports = (sequelize, DataTypes) => {
comment: DataTypes.STRING,
userId: DataTypes.INTEGER,
requestId: DataTypes.INTEGER,
deleted: {
type: DataTypes.BOOLEAN,
defaultValue: false
}
deleted: DataTypes.BOOLEAN
}, {});
comments.associate = function(models) {
// associations can be defined here
comments.belongsTo(models.users, {
as: 'commenter',
foreignKey: 'userId',
});
comments.belongsTo(models.requests, {
as: 'requestComment',
foreignKey: 'requestId',
});
};
return comments;
};
32 changes: 15 additions & 17 deletions src/database/seeders/20191029103632-comments.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
'use strict';

module.exports = {
up: (queryInterface, Sequelize) => Promise.all([
queryInterface.bulkInsert('comments', [
{
comment: 'i want to go to andela kigali',
userId: 2,
requestId: 3,
deleted: false,
createdAt: new Date(),
updatedAt: new Date()
}
])
]),

down: (queryInterface, Sequelize) => Promise.all([
queryInterface.bulkDelete('comments', null, {})
])
up: (queryInterface, Sequelize) => Promise.all([
queryInterface.bulkInsert('comments', [
{
comment: 'i want to go to andela kigali',
userId: 3,
requestId: 3,
deleted: false,
createdAt: new Date(),
updatedAt: new Date()
}
])
]),
down: (queryInterface, Sequelize) => Promise.all([
queryInterface.bulkDelete('comments', null, {})
])
};
34 changes: 34 additions & 0 deletions src/helpers/commentsHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import sequelize from 'sequelize';
import models from '../database/models';
import strings from '../utils/stringsUtil';
import responseUtil from '../utils/responseUtil';

const findComment = req => {
const { Op } = sequelize;
const { id } = req.params;
const comment = models.comments.findOne({
where: {
[Op.and]: [{ id },
{ deleted: false }]
},
});
return comment;
};

const checkComment = async (req, comments, res, data, id, message) => {
const ownerId = req.user.payload.id;

if (!comments) {
return responseUtil(res, 404, strings.comments.error.COMMENT_NOT_FOUND);
}
if (comments.userId !== ownerId) {
return responseUtil(res, 403, strings.comments.error.NOT_OWNER);
}
await models.comments.update(data, { where: { id, }, });
const commentData = await models.comments.findOne({ where: { id, }, attributes: { exclude: ['userId', 'requestId', 'deleted', 'createdAt', 'updatedAt'] }, });
return responseUtil(res, 200, message, commentData);
};

export default {
findComment, checkComment
};
9 changes: 9 additions & 0 deletions src/middlewares/inputValidation.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,13 @@ export default class InputValidation {
});
validation(req, res, schema, next);
}

static validateComment(req, res, next) {
const schema = Joi.object({
comment: Joi.string().min(1).max(250)
.message('comment should be at least 1 character and not more than 250 characters!')
.required(),
});
validation(req, res, schema, next);
}
}
10 changes: 6 additions & 4 deletions src/routes/api/requests.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Router } from 'express';
import requestController from '../../controllers/requestController';
import commentsController from '../../controllers/commentsController';
import validateToken from '../../middlewares/auth/validateToken';
import verifyRelationships from '../../middlewares/requests/relationVerification';
import checkId from '../../middlewares/checkId';
Expand All @@ -18,11 +19,11 @@ const {
} = requestController;

const {
validateSearchRequestUser,
validateSearchRequestManager,
validateRequest,
validateSearchRequestUser, validateSearchRequestManager,
validateComment, validateRequest,
} = InputValidation;
const { checkManagerRole, supplierNotAllowed } = checkRole;
const { editComment, deleteComment } = commentsController;

/**
* @swagger
Expand Down Expand Up @@ -152,5 +153,6 @@ router.get('/', validateToken, viewMyRequests);
router.get('/manager', validateToken, checkManagerRole, viewManagerRequests);
router.patch('/manager/:action/:id', validateToken, checkManagerRole, checkId, wrongAction, isProcessed, changeStatus);
router.patch('/:id', validateToken, pendingRequest.requestOwner, pendingRequest.selectPending, validateRequest, pendingRequest.validateBody, updateRequest);

router.put('/comments/:id', validateToken, checkId, validateComment, editComment);
router.delete('/comments/:id', validateToken, checkId, deleteComment);
export default router;
4 changes: 2 additions & 2 deletions src/tests/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import defaultTests from './defaultTests.spec';
import signupTests from './signupTest.spec';
import profileTests from './profile.spec';
import loginTest from './loginTest.spec';
import requestTest from './requestTests/index.spec';
import requestTest from './requestTests/index.spec'
import requestTests from './requestTests.spec';
import accommodationTest from './accommodationTest.spec';
import editRequest from './editRequest.spec';
Expand All @@ -19,7 +19,7 @@ describe('Social Authentication Tests', authTests);
describe('Signup Tests', signupTests);
describe('Login Tests', loginTest);
describe('Request Test', requestTest);
describe('Request Tests', requestTests);
describe('Requests-Tests', requestTests);
describe('Accommodation Tests', accommodationTest);
describe('Setting Profile Test', profileTests);
describe('Social Authentication Tests', loginTest);
Expand Down
2 changes: 2 additions & 0 deletions src/tests/mockData/mockData.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@ const mockData = {
OutdateBookingDate:{checkInDate:'2019-02-22',checkOutDate:'2019-02-25',roomsNumber:3,accomodationId:3},
travelAdmin:{email: 'travelAdmin@caretbn.com', password: 'Pa55w0rd'},
activationInfo: {reasons: 'This is a valid reason to take action on your accommodation'},
commentData:{comment:'change dates'},
emptyComment:{comment:''}
};
export default mockData;
82 changes: 82 additions & 0 deletions src/tests/requestTests.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,86 @@ describe('Request Tests', () => {
done();
});
});
it('it Should be able to edit comment', (done) => {
chai.request(app)
.put('/api/v1/requests/comments/1')
.send(mockData.commentData)
.set('Authorization', `Bearer ${userToken}`)
.end((err, res) => {
const { status, body } = res;
expect(status).to.be.eql(200);
expect(body.message).to.be.eql('Comment Successfully Updated!');
done();
});
});
it('it Should not be able to edit comment with wrong id', (done) => {
chai.request(app)
.put('/api/v1/requests/comments/1677')
.send(mockData.commentData)
.set('Authorization', `Bearer ${userToken}`)
.end((err, res) => {
const { status, body } = res;
expect(status).to.be.eql(404);
expect(body.message).to.be.eql('Ooops! This comment does not exist!');
done();
});
});
it('it Should not be able to edit comment with empty comment', (done) => {
chai.request(app)
.put('/api/v1/requests/comments/1')
.send(mockData.emptyComment)
.set('Authorization', `Bearer ${userToken}`)
.end((err, res) => {
const { status } = res;
expect(status).to.be.eql(400);
done();
});
});
it('it Should not be able to edit comment with anauthorized user', (done) => {
chai.request(app)
.put('/api/v1/requests/comments/1')
.send(mockData.commentData)
.set('Authorization', `Bearer ${managerToken}`)
.end((err, res) => {
const { status, body } = res;
expect(status).to.be.eql(403);
expect(body.message).to.be.eql('Oops! You are not the owner of this comment!');
done();
});
});

it('it Should not be able to delete a comment with wrong id', (done) => {
chai.request(app)
.delete('/api/v1/requests/comments/15566')
.set('Authorization', `Bearer ${userToken}`)
.end((err, res) => {
const { status, body } = res;
expect(status).to.be.eql(404);
expect(body.message).to.be.eql('Ooops! This comment does not exist!');
done();
});
});

it('it Should not be able to delete a comment with anauthorized user', (done) => {
chai.request(app)
.delete('/api/v1/requests/comments/1')
.set('Authorization', `Bearer ${managerToken}`)
.end((err, res) => {
const { status, body } = res;
expect(status).to.be.eql(403);
expect(body.message).to.be.eql('Oops! You are not the owner of this comment!');
done();
});
});
it('it Should be able to delete a comment', (done) => {
chai.request(app)
.delete('/api/v1/requests/comments/1')
.set('Authorization', `Bearer ${userToken}`)
.end((err, res) => {
const { status, body } = res;
expect(status).to.be.eql(200);
expect(body.message).to.be.eql('Comment Successfully Deleted!');
done();
});
});
});
10 changes: 10 additions & 0 deletions src/utils/stringsUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@ const strings = {
ID_INVALID: 'Invalid id, id should be an integer',
},
},
comments: {
success: {
COMMENT_UPDATED: 'Comment Successfully Updated!',
COMMENT_DELETED: 'Comment Successfully Deleted!'
},
error: {
COMMENT_NOT_FOUND: 'Ooops! This comment does not exist!',
NOT_OWNER: 'Oops! You are not the owner of this comment!',
},
},
};

export default strings;

0 comments on commit 2bffdf8

Please sign in to comment.