Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#166241013 Implement articles reading statistics #62

Merged
merged 1 commit into from
Jul 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
432 changes: 0 additions & 432 deletions src/api/controllers/Article.js

This file was deleted.

27 changes: 20 additions & 7 deletions src/api/controllers/articlesController.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ const {
User,
LikeDislike,
ReportedArticles,
BlockedArticles
BlockedArticles,
Share
} = models;
// eslint-disable-next-line no-array-constructor
const days = new Array(
Expand Down Expand Up @@ -55,7 +56,8 @@ class articlesController {
author,
updatedAt,
createdAt,
readtime
readtime,
views
} = dataValues;
const userInfo = await findUser(author.username);
eventEmitter.emit('publishArticle', userInfo.id, slug);
Expand All @@ -69,7 +71,8 @@ class articlesController {
updatedAt,
createdAt,
author,
readtime
readtime,
views
};
res.status(201).send({
article: result
Expand Down Expand Up @@ -102,11 +105,14 @@ class articlesController {

// @check if the article's slug exist
const result = await Article.findOne({ where: { slug } });
if (result === null) {
return res.status(404).send({ error: 'This Slug Not found!' });
}

if (result === null) { return res.status(404).send({ error: 'This Slug Not found!' }); }
const oneArticle = await articles.getOneSlug(slug);
await Article.update(
{
views: oneArticle.dataValues.views += 1,
},
{ where: { slug } }
);
res.status(200).send({
status: 200,
article: oneArticle
Expand Down Expand Up @@ -480,6 +486,13 @@ class articlesController {

// eslint-disable-next-line require-jsdoc
static async share(req, res) {
const { slug, provider } = req.share;
const { id } = req.user;
await Share.create({
userId: id,
slug,
provider
});
return res.status(200).json({
message: 'Thanks for sharing!',
article: req.article
Expand Down
11 changes: 9 additions & 2 deletions src/api/controllers/comments.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ export default class comments {
static async getComment(req, res) {
const { slug } = req.params;
const findSlug = await models.Article.findAll({
attributes: ['id'],
attributes: ['id', 'views'],
where: {
slug
}
Expand All @@ -186,6 +186,12 @@ export default class comments {
message: 'Not found!'
});
}
await models.Article.update(
{
views: findSlug[0].dataValues.views += 1,
},
{ where: { slug } }
);
await models.Article.findAll({
attributes: [
'title',
Expand All @@ -200,7 +206,8 @@ export default class comments {
model: models.Comment,
attributes: ['comment'],
where: {
articleId: findSlug[0].dataValues.id
articleId: findSlug[0].dataValues.id,
commentId: null
},
include: [
{
Expand Down
162 changes: 162 additions & 0 deletions src/api/controllers/stats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import models from '../../sequelize/models';

const {
Article,
Comment,
Share
} = models;

/**
* @Author - Mireille Niwemuhuza
*/
class statsController {
/**
* @description - Users should be able to view how many times an article has been viewed
* @param {object} req - Request object
* @param {object} res - Response object
* @return {object} - Response object
*/
static async getViews(req, res) {
const { slug } = req.params;
const articleViews = await Article.findAll({
attributes: ['title', 'views'],
where: {
slug
}
});
const { title, views } = articleViews[0];
return res.status(200).json({
data: { title, views }

});
}

/**
* @description - Users should be able to view the number of comments on an article
* @param {Object} req - Request Object
* @param {Object} res - Response Object
* @returns {Object} - Response object
*/
static async commentNumber(req, res) {
const { slug } = req.params;

// Count comments
const countComment = await Comment.count({
where: {
slug
}
});

return res.status(200).json({
status: 200,
data: {
slug,
countComment
}
});
}

/**
* @description - Users should be able to view the number of shares on facebook
* @param {Object} req - Request Object
* @param {Object} res - Response Object
* @returns {Object} - Response object
*/
static async facebookShares(req, res) {
const { slug } = req.params;

// Count facebook shares
const shares = await Share.count({
where: {
slug,
provider: 'facebook'
}
});

return res.status(200).json({
status: 200,
data: {
slug,
shares
}
});
}

/**
* @description - Users should be able to view the number of shares on twitter
* @param {Object} req - Request Object
* @param {Object} res - Response Object
* @returns {Object} - Response object
*/
static async twitterShares(req, res) {
const { slug } = req.params;

// Count shares on twitter
const shares = await Share.count({
where: {
slug,
provider: 'twitter'
}
});

return res.status(200).json({
status: 200,
data: {
slug,
shares
}
});
}

/**
* @description - Users should be able to view the number of shares on email
* @param {Object} req - Request Object
* @param {Object} res - Response Object
* @returns {Object} - Response object
*/
static async emailShares(req, res) {
const { slug } = req.params;

// Count shares on email
const shares = await Share.count({
where: {
slug,
provider: 'email'
}
});

return res.status(200).json({
status: 200,
data: {
slug,
shares
}
});
}

/**
* @description - Users should be able to view the number of shares on email
* @param {Object} req - Request Object
* @param {Object} res - Response Object
* @returns {Object} - Response object
*/
static async shares(req, res) {
const { slug } = req.params;

// Count shares on email
const shares = await Share.count({
where: {
slug
}
});

return res.status(200).json({
status: 200,
data: {
slug,
shares
}
});
}
}
export default statsController;
23 changes: 20 additions & 3 deletions src/api/routes/articlesRouter.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Router } from 'express';
import articlesController from '../controllers/Article';
import articlesController from '../controllers/articlesController';
import Auth from '../../middleware/auth';
import check from '../../middleware/checkOwner';
import validateBody from '../../middleware/validateBody';
Expand All @@ -14,9 +14,14 @@ import isThisArticleBlocked from '../../middleware/isThisArticleBlocked';
import bookmarkController from '../controllers/bookmark';
import checkLikesandDislikes from '../../middleware/checkLikesDislikes';
import paginate from '../../middleware/paginate';
import shareArticle from '../../helpers/shareArticle';
import shareArticle from '../../middleware/shareArticle';
import stats from '../controllers/stats';


const articlesRouter = Router();
const {
getViews, commentNumber, facebookShares, twitterShares, emailShares, shares
} = stats;
const {
createArticle,
getAllArticle,
Expand All @@ -39,7 +44,7 @@ const { bookmark } = bookmarkController;
const { searchForArticle } = search;
const {
createComment, editComment, deleteComment, getComment, commentAcomment,
likeComment, dislikeComment, countLikes, countDislikes
likeComment, dislikeComment, countLikes, countDislikes, commentHistory
} = commentsController;
const { checkComment, checkParameter, articleExists } = comment;
const { liked, disliked } = checkLikesandDislikes;
Expand Down Expand Up @@ -91,6 +96,18 @@ articlesRouter.get('/:slug/share/email', verifyToken, slugExist, shareArticle, s
articlesRouter.post('/:slug/bookmark', verifyToken, slugExist, bookmark);

articlesRouter.post('/:slug/report', verifyToken, validateBody('checkComment'), slugExist, reportArticle);
// get comment edit history

articlesRouter.get('/comments/:commentId/history', verifyToken, checkParameter, commentHistory);

// articles reading stats

articlesRouter.get('/:slug/comments/count', slugExist, commentNumber);
articlesRouter.get('/:slug/views', slugExist, getViews);
articlesRouter.get('/:slug/shares/facebook', slugExist, facebookShares);
articlesRouter.get('/:slug/shares/twitter', slugExist, twitterShares);
articlesRouter.get('/:slug/shares/email', slugExist, emailShares);
articlesRouter.get('/:slug/shares', slugExist, shares);

// block reported articles
articlesRouter.post('/:slug/block', verifyToken, checkIsModerator, validateBody('checkDescription'), slugExist, isAlreadBlocked, blockArticle);
Expand Down
5 changes: 3 additions & 2 deletions src/helpers/articlesHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ class ArticlesHelper {
body,
tagList: tagList.split(','),
authorId: parseInt(id, 10),
readtime
readtime,
views: 0,
});
const userInfo = await this.getUserInfo(id);
const { username, bio, image } = userInfo;
Expand Down Expand Up @@ -77,7 +78,7 @@ class ArticlesHelper {
model: User,
attributes: ['username', 'bio', 'image']
}],
attributes: ['slug', 'title', 'description', 'readtime', 'body', 'tagList', 'updatedAt', 'createdAt']
attributes: ['slug', 'title', 'description', 'readtime', 'body', 'tagList', 'views', 'updatedAt', 'createdAt']
});
return result;
}
Expand Down
29 changes: 0 additions & 29 deletions src/helpers/shareArticle.js

This file was deleted.

32 changes: 32 additions & 0 deletions src/middleware/shareArticle.js
Original file line number Diff line number Diff line change
@@ -1 +1,33 @@
import open from 'open';
import dotenv from 'dotenv';
import share from 'social-share';
import db from '../sequelize/models';

dotenv.config();
const { Article } = db;
const { APP_URL_FRONTEND } = process.env;

export default async (req, res, next) => {
let provider;
const { slug } = req.params;
const { title } = await Article.findOne({ where: { slug } });
if (req.url.search(/\/twitter/g) > 0) {
const url = share('twitter', { url: `${APP_URL_FRONTEND}/api/articles/${slug}` });
await open(`${url}`, { wait: false });
provider = 'twitter';
} else if (req.url.search(/\/facebook/g) > 0) {
const url = share('facebook', { url: `${APP_URL_FRONTEND}/api/articles/${slug}` });
await open(`${url}`, { wait: false });
provider = 'facebook';
} else if (req.url.search(/\/email/g) > 0) {
await open(
`mailto:?subject=${title}&body=${APP_URL_FRONTEND}/articles/${slug}`,
{
wait: false
}
);
provider = 'email';
}
req.share = { slug, provider };
next();
};
7 changes: 7 additions & 0 deletions src/sequelize/migrations/20190627181513-add-views-article.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
up: (queryInterface, Sequelize) => queryInterface.addColumn('Articles', 'views', {
type: Sequelize.INTEGER
}),

down: queryInterface => queryInterface.removeColumn('Articles', 'views')
};
Loading