Skip to content

Commit

Permalink
Merge ce52b45 into eae3bfd
Browse files Browse the repository at this point in the history
  • Loading branch information
AJAkimana committed May 29, 2019
2 parents eae3bfd + ce52b45 commit 2aa52da
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 16 deletions.
16 changes: 16 additions & 0 deletions controllers/comment.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,22 @@ class Comments {
return res.status(200).send({ comment: oneComment });
}

/**
* @function getCommentHistories
* @param {Object} req
* @param {Object} res
* @returns {array} An array of comments histories
*/
static async getCommentHistories(req, res) {
const commentId = req.params.id;

const histories = await commentHelper.getCommentsHistories(commentId);
return res.status(200).json({
status: 200,
commentsHistories: histories.rows
});
}

/**
* @function deleteOneComment
* @param {Object} req
Expand Down
44 changes: 43 additions & 1 deletion helpers/commentHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import joi from 'joi';
import model from '../models';

const {
User, Article, Comment, CommentFeedback
User, Article, Comment, CommentFeedback, CommentHistory
} = model;

/**
Expand Down Expand Up @@ -81,6 +81,12 @@ class CommentHelper {
if (!fetchedComments[0]) {
return { errors: { body: ['no commemts found on this article'] } };
}
await Promise.all(fetchedComments.map(async (currentComment) => {
const commentId = currentComment.dataValues.id;
const commentHistories = await this.getCommentsHistories(commentId);
currentComment.dataValues.histories = commentHistories;
return currentComment;
}));
return fetchedComments;
}

Expand All @@ -100,6 +106,9 @@ class CommentHelper {
if (!fetchedComment) {
return { errors: { body: ['commemt not found'] } };
}
const commentId = fetchedComment.dataValues.id;
const commentHistories = await this.getCommentsHistories(commentId);
fetchedComment.dataValues.histories = commentHistories;
return fetchedComment;
}

Expand Down Expand Up @@ -136,6 +145,7 @@ class CommentHelper {
await Comment.destroy({ where: { titleSlug: slug, id } });
const destroyed = await Comment.findOne({ where: { titleSlug: slug, id } });
if (destroyed === null) {
await CommentHistory.destroy({ where: { parentComment: id } });
return { message: `comment with id ${id} have been deleted` };
}
return { message: `comment with id ${id} have failed to be deleted` };
Expand All @@ -152,7 +162,12 @@ class CommentHelper {
const { body } = req.body;
const { comment } = req.body;
await Comment.update({ body: body || comment.body }, { where: { titleSlug: slug, id } });
await this.saveCommentHistory({ body: comment, parentComment: id });

const updatedComment = await Comment.findOne({ where: { id } });
const commentHistories = await this.getCommentsHistories(id);
updatedComment.dataValues.histories = commentHistories;

return { response: updatedComment };
}

Expand Down Expand Up @@ -269,7 +284,10 @@ class CommentHelper {
const { body } = req.body;
const { reply } = req.body;
await Comment.update({ body: body || reply.body }, { where: { replyid: id, id: replyId } });
await this.saveCommentHistory({ body: reply, parentComment: id });
const updatedReply = await Comment.findOne({ where: { id: replyId } });
const commentHistories = await this.getCommentsHistories(id);
updatedReply.dataValues.histories = commentHistories;
return { response: updatedReply };
}

Expand Down Expand Up @@ -402,6 +420,30 @@ class CommentHelper {
CommentFeedback.destroy({ where: { id }, returning: true });
return deleteFeedback;
}

/**
* Save previous comment before editing
* @param {object} comment - an object
*@return {object} Return saved history
*/
static async saveCommentHistory(comment) {
const history = await CommentHistory.create(comment);
return history;
}

/**
* Get all comment edits
* @param {number} commentId - an object
*@return {array} Return an array of all comments
*/
static async getCommentsHistories(commentId) {
const histories = await CommentHistory.findAndCountAll({
where: { parentComment: commentId },
attributes: ['body', 'createdAt'],
order: [['createdAt', 'DESC']]
});
return histories;
}
}

export default CommentHelper;
11 changes: 11 additions & 0 deletions middlewares/catch.errors.middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* @exports catchErrors
* @description This chains a catch method to a function and calls the next error handler
*
* */

const catchErrors = fn => (req, res, next) => {
Promise.resolve(fn(req, res, next))
.catch(next);
};
export default catchErrors;
33 changes: 33 additions & 0 deletions migrations/20190526205547-create-comment-history.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const commentHistoryMigration = {
up: (queryInterface, Sequelize) => queryInterface.createTable('CommentHistories', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
body: {
type: Sequelize.STRING
},
parentComment: {
type: Sequelize.INTEGER,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
references: {
model: 'Comments',
key: 'id'
}
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
}),
down: queryInterface => queryInterface.dropTable('CommentHistories')
};

export default commentHistoryMigration;
1 change: 1 addition & 0 deletions models/comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const comments = (sequelize, DataTypes) => {
});
Comment.hasMany(models.Comment, { foreignKey: 'replyid' });
Comment.hasMany(models.CommentFeedback, { as: 'like', foreignKey: 'commentId' });
Comment.hasMany(models.CommentHistory, { as: 'parent', foreignKey: 'parentComment' });
};
return Comment;
};
Expand Down
19 changes: 19 additions & 0 deletions models/commenthistory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const commentHistory = (sequelize, DataTypes) => {
const CommentHistory = sequelize.define('CommentHistory', {
parentComment: DataTypes.INTEGER,
body: DataTypes.STRING,
}, {});
CommentHistory.associate = (models) => {
// associations can be defined here
CommentHistory.belongsTo(models.Comment, {
foreignKey: 'parentComment',
as: 'parent',
targetKey: 'id',
onDelete: 'CASCADE',
onupdate: 'CASCADE'
});
};
return CommentHistory;
};

export default commentHistory;
15 changes: 9 additions & 6 deletions models/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ fs.readdirSync(__dirname)
const model = sequelize.import(path.join(__dirname, file));
db[model.name] = model;
});

Object.keys(db).forEach((modelName) => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
try {
Object.keys(db).forEach((modelName) => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
} catch (err) {
// console.log(err)
}

db.sequelize = sequelize;
db.Sequelize = Sequelize;
Expand Down
20 changes: 11 additions & 9 deletions routes/api/comment/comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ import express from 'express';
import Auth from '../../../middlewares/auth';
import comment from '../../../controllers/comment.controller';
import commentHelper from '../../../helpers/commentHelper';
import catchErrors from '../../../middlewares/catch.errors.middleware';

const router = express.Router();

router.post('/:slug/comments', Auth, commentHelper.isValid, comment.addComment);
router.get('/:slug/comments', Auth, comment.getComments);
router.get('/:slug/comments/:id', Auth, comment.getOneComment);
router.delete('/:slug/comments/:id', Auth, commentHelper.isCommentExist, comment.deleteOneComment);
router.put('/:slug/comments/:id', Auth, commentHelper.isCommentExist, comment.updateOneComment);
router.post('/comments/:id/reply', Auth, commentHelper.commentExist, comment.replyComment);
router.get('/comments/:id/replies', Auth, comment.getCommentReplies);
router.delete('/comments/:id/replies/:replyId', Auth, commentHelper.isReplytExist, comment.deleteOneReply);
router.put('/comments/:id/replies/:replyId', Auth, commentHelper.isReplytExist, comment.updateOneReply);
router.post('/:slug/comments', catchErrors(Auth), catchErrors(commentHelper.isValid), catchErrors(comment.addComment));
router.get('/:slug/comments', catchErrors(Auth), catchErrors(comment.getComments));
router.get('/:slug/comments/:id', catchErrors(Auth), catchErrors(comment.getOneComment));
router.get('/:slug/comments/:id/histories', catchErrors(Auth), catchErrors(comment.getCommentHistories));
router.delete('/:slug/comments/:id', catchErrors(Auth), catchErrors(commentHelper.isCommentExist), catchErrors(comment.deleteOneComment));
router.put('/:slug/comments/:id', catchErrors(Auth), catchErrors(commentHelper.isCommentExist), catchErrors(comment.updateOneComment));
router.post('/comments/:id/reply', catchErrors(Auth), catchErrors(commentHelper.commentExist), catchErrors(comment.replyComment));
router.get('/comments/:id/replies', catchErrors(Auth), catchErrors(comment.getCommentReplies));
router.delete('/comments/:id/replies/:replyId', catchErrors(Auth), catchErrors(commentHelper.isReplytExist), catchErrors(comment.deleteOneReply));
router.put('/comments/:id/replies/:replyId', catchErrors(Auth), catchErrors(commentHelper.isReplytExist), catchErrors(comment.updateOneReply));


export default router;
10 changes: 10 additions & 0 deletions tests/comment.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,16 @@ describe('Test likes of a comment', () => {
done();
});
});
it('should get comment edit histories', (done) => {
chai.request(app)
.get(`/api/v1/article/this-is-new/comments/${comment}/histories`)
.set('authorization', userToken)
.end((err, res) => {
res.should.have.status(200);
res.body.commentsHistories.should.be.a('array');
done();
});
});
it('User should be able to like a comment', (done) => {
chai.request(app)
.post(`/api/v1/comments/${comment}/feedback/like`)
Expand Down

0 comments on commit 2aa52da

Please sign in to comment.