Skip to content

Commit

Permalink
Merge branch 'develop' into ft-api-reading-stats-167313420
Browse files Browse the repository at this point in the history
  • Loading branch information
Anguandia committed Aug 29, 2019
2 parents b2f93ac + aa9dee6 commit 008f5c0
Show file tree
Hide file tree
Showing 17 changed files with 553 additions and 26 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"undoseeds": "babel-node node_modules/.bin/sequelize db:seed:undo:all",
"migration": "babel-node node_modules/.bin/sequelize db:migrate",
"undomigration": "babel-node node_modules/.bin/sequelize db:migrate:undo:all",
"runmigrations": "npm run undoseeds && npm run migration && npm run seeds",
"runmigrations": " npm run undomigration && npm run migration && npm run seeds",
"coveralls": "nyc report --reporter=text-lcov | coveralls",
"test": "export NODE_ENV=test && npm run undomigration && npm run migration && npm run seeds && nyc --reporter=html --reporter=text mocha ./test --exit --require @babel/register",
"dev": "nodemon --exec babel-node ./src/app.js"
Expand Down
1 change: 0 additions & 1 deletion src/controllers/articles.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import NotificationServices from '../services/notification.service';
import cloudinaryHelper from '../helpers/cloudinaryHelper';
import OpenUrlHelper from '../helpers/share.article.helper';
import Util from '../helpers/util';

import statsService from '../services/db.service';

const { notifyViaEmailAndPush } = NotificationServices;
Expand Down
101 changes: 101 additions & 0 deletions src/controllers/comments.controller.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import commentsService from '../services/comments.service';
import UserService from '../services/user.service';
import models from '../models';
import Helper from '../helpers/helper';
import NotificationServices from '../services/notification.service';
import Util from '../helpers/util';
import StatsService from '../services/db.service';


const util = new Util();

const { notifyUsersWhoFavorited } = NotificationServices;
Expand Down Expand Up @@ -144,5 +146,104 @@ class Comments {
await util.setSuccess(200, 'Update is successfully', updateComment);
return util.send(res);
}

/**
*
*
* @static
* @param {*} req
* @param {*} res
* @returns {Object} return json object
* @memberof Comments
*/
static async likeComment(req, res) {
const { id } = req.params;
const { username } = req.auth;
const comment = await commentsService.findOne(id);

if (!comment) {
util.setError(404, `Comment with id: ${id} does not exist.`);
return util.send(res);
}
let { likesCount, likeInfo } = comment;
const userHasLikedBefore = likeInfo.search(username);
if (userHasLikedBefore >= 0) {
util.setError(400, 'You liked this comment already');
return util.send(res);
}

likesCount += 1;
likeInfo = `${username}, ${likeInfo}`;
await commentsService.updateComment(id, { likesCount, likeInfo });

const formattedLikeInfo = Helper.formatLikeInfo(likeInfo);
util.setSuccess(201, { likesCount, formattedLikeInfo });
return util.send(res);
}

/**
*
*
* @static
* @param {*} req
* @param {*} res
* @returns {Object} return json object
* @memberof Comments
*/
static async updateLikeComment(req, res) {
const { id } = req.params;
const { username } = req.auth;
const comment = await commentsService.findOne(id);
if (!comment) {
util.setError(404, `Comment with id: ${id} does not exist.`);
return util.send(res);
}

let { likesCount, likeInfo } = comment;
const userHasLikedBefore = likeInfo.search(username);

if (userHasLikedBefore === -1) {
util.setError(400, 'You did not like this comment before');
return util.send(res);
}

likesCount -= 1;
likeInfo = likeInfo.replace(`${username}, `, '');
await commentsService.updateComment(id, { likesCount, likeInfo });

util.setSuccess(200, 'You unliked this comment successfully');
return util.send(res);
}

/**
*
*
* @static
* @param {*} req
* @param {*} res
* @returns {Object} return json object
* @memberof Comments
*/
static async getLikesComments(req, res) {
const { id } = req.params;
const { username } = req.auth;
const comment = await commentsService.findOne(id);

if (!comment) {
util.setError(404, `Comment with id: ${id} does not exist.`);
return util.send(res);
}
const { likesCount, likeInfo } = comment;

const userHasLikedBefore = likeInfo.search(username);

if (userHasLikedBefore === -1) {
util.setError(200, { data: { likesCount, likeInfo } });
return util.send(res);
}
const formattedLikeInfo = Helper.formatLikeInfo(likeInfo.replace(`${username}, `, ''));
util.setSuccess(200, { data: { likesCount, formattedLikeInfo } });
return util.send(res);
}
}
export default Comments;
30 changes: 30 additions & 0 deletions src/helpers/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,35 @@ class Helper {
const formatedReadTime = `${readTime} min read`;
return formatedReadTime;
}

/**
*
*
* @static
* @param {*} likeInfo
* @returns {string} formarted comment like information
* @memberof Helper
*/
static formatLikeInfo(likeInfo) {
let formattedOutput = 'You';
const usernames = likeInfo.split(', ');

if (usernames.length === 2) {
formattedOutput += ' like this comment';
return formattedOutput;
}
for (let i = 1; i < (usernames.length - 1); i += 1) {
if (i === 5) break;
formattedOutput += `, ${usernames[i]} `;
}

if (usernames.length < 6) {
formattedOutput += ' like this comment';
return formattedOutput;
}

formattedOutput += `and ${(usernames.length - 6)} more people like this comment`;
return formattedOutput;
}
}
export default Helper;
24 changes: 16 additions & 8 deletions src/migrations/20190816101310-create-comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,18 @@ module.exports = {
type: Sequelize.STRING,
allowNull: true
},
parentCommentId: {
type: Sequelize.INTEGER,
allowNull: true
},
parentCommentId: {
type: Sequelize.INTEGER,
allowNull: true
},
likesCount: {
type: Sequelize.INTEGER,
defaultValue: 0
},
likeInfo: {
type: Sequelize.TEXT,
defaultValue: ''
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
Expand All @@ -35,14 +43,14 @@ module.exports = {
allowNull: false,
type: Sequelize.DATE
}
}) .then(() => sequelize.query(`ALTER TABLE "Comments"
}).then(() => sequelize.query(`ALTER TABLE "Comments"
ADD CONSTRAINT fk_parentReference FOREIGN KEY ("parentCommentId")
REFERENCES "Comments" (id) ON DELETE CASCADE`),(`ALTER TABLE "Comments"
REFERENCES "Comments" (id) ON DELETE CASCADE`), (`ALTER TABLE "Comments"
ADD CONSTRAINT fk_parentReference FOREIGN KEY ("commentRevisions")
REFERENCES "Comments" (id) ON DELETE CASCADE`));

},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Comments');
}
};
};
12 changes: 7 additions & 5 deletions src/models/comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module.exports = (sequelize, DataTypes) => {
onUpdate: 'CASCADE',
onDelete: 'CASCADE'
},
commentRevisions:{
commentRevisions: {
type: DataTypes.STRING,
allowNull: true,
references: {
Expand All @@ -28,12 +28,14 @@ module.exports = (sequelize, DataTypes) => {
allowNull: true
},
body: DataTypes.STRING,
likesCount: DataTypes.INTEGER,
likeInfo: DataTypes.TEXT
}, {});
Comment.associate = function(models) {
Comment.associate = function (models) {
// associations can be defined here
Comment.belongsTo(models.user,{
foreignKey:'id',as:'commentAuthor'
Comment.belongsTo(models.user, {
foreignKey: 'id', as: 'commentAuthor'
});
};
return Comment;
};
};
1 change: 1 addition & 0 deletions src/routes/api/article/article.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ router.get('/', checkQuery, articleController.getAllArticles);
router.get('/:slug', StatsWare.saveStat, articleController.getOneArticle);
router.delete('/:slug', [auth, confirmEmailAuth], articleController.deleteArticle);
router.patch('/:slug', [auth, confirmEmailAuth], imageUpload.array('images', 10), articleController.UpdateArticle);
router.post('/:slug/share/:channel', [auth, confirmEmailAuth], articleController.shareArticle);


// Highlight
Expand Down
35 changes: 28 additions & 7 deletions src/routes/api/article/doc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,31 @@
$ref: "#/responses/BadRequest"
404:
$ref: "#/responses/Notfound"
/articles/{slug}/share/{channel}:
post:
description: >
Share an article on mail and social media channels
parameters:
- name: slug
in: path
description: Slug for article
type: string
required: true
- name: channel
in: path
description: Channel to share to
type: string
required: true
- name: x-access-token
in: header
schema:
type: string
required:
- authorization
responses:
200:
description: Article successfully shared
$ref: "#/responses/Notfound"
/articles:
post:
summary: Create an article
Expand Down Expand Up @@ -436,8 +461,6 @@ definitions:
description: Tag with name has been removed
400:
$ref: "#/responses/BadRequest"
404:
$ref: "#/responses/Notfound"
/articles/{slug}/highlight:
post:
produces:
Expand Down Expand Up @@ -532,8 +555,6 @@ definitions:
description: you are ready to share
404:
description: Sorry, you can not share





$ref: '#/responses/Notfound'


5 changes: 5 additions & 0 deletions src/routes/api/comment/comments.route.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ import express from 'express';
import Comments from '../../../controllers/comments.controller';
import auth from '../../../middlewares/auth';
import CommentsValidation from '../../../middlewares/validators/comments.body';
import confirmEmailAuth from '../../../middlewares/emailVarification.middleware';

const router = express.Router();
router.post('/:slug', [auth, CommentsValidation], Comments.createComment);
router.get('/', [auth], Comments.getComments);
router.delete('/:id', [auth], Comments.deleteComment);
router.put('/:id', [auth, CommentsValidation], Comments.updateComment);
router.get('/like/:id', [auth, confirmEmailAuth], Comments.getLikesComments);
router.post('/like/:id', [auth, confirmEmailAuth], Comments.likeComment);
router.put('/like/:id', [auth, confirmEmailAuth], Comments.updateLikeComment);

export default router;
73 changes: 73 additions & 0 deletions src/routes/api/comment/doc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,79 @@
$ref: '#responses/BadRequest'
404:
$ref: '#/responses/Notfound'
/comments/like/{id}:
get:
summary: get all likes of a comment
description: >
gets a specific comment like
tags:
- Comment
produces:
- application/json
parameters:
- name: x-access-token
in: header
schema:
type: string
required:
- authorization
responses:
200:
description: Successfully retrieved comment likes
schema:
$ref: '#definitions/Comment'
400:
$ref: '#responses/BadRequest'
404:
$ref: '#/responses/Notfound'
put:
summary: unlike a specific comment
description: >
unlike a specific comment
tags:
- Comment
produces:
- application/json
parameters:
- name: x-access-token
in: header
schema:
type: string
required:
- authorization
responses:
200:
description: unlike a specific comment
schema:
$ref: '#definitions/Comment'
400:
$ref: '#responses/BadRequest'
404:
$ref: '#/responses/Notfound'
post:
summary: like a specific comment
description: >
like a specific comment
tags:
- Comment
produces:
- application/json
parameters:
- name: x-access-token
in: header
schema:
type: string
required:
- authorization
responses:
200:
description: like a specific comment
schema:
$ref: '#definitions/Comment'
400:
$ref: '#responses/BadRequest'
404:
$ref: '#/responses/Notfound'
tags:
- name: Comment
description: Operations related to Comment
Expand Down
Loading

0 comments on commit 008f5c0

Please sign in to comment.