Skip to content

Commit

Permalink
#159987732 Users can get their reading stats (#52)
Browse files Browse the repository at this point in the history
* fix uncaught error in category controller

* ft(user-reading-stats): users can get their reading stats

- user's view should be logged everytime they get an article
- users should be able to see the number of articles read
- users should be able to get the articles they have read

[Delivers 159987732]

* ft(users'-reading-stats): users can get their reading stats

- log user's view to the ArticleView model when they view an article
- users can get all the articles they have viewed
- users can get articles that users have liked
- users can get their most read category
- add more tests to Article model
- add tests to the ArticleView model
- sanitize category name before processing the request

[Delivers 159987732]

* ft(user-reading-stats):

- refactor mode function to use more descriptive variables
- add jsdoc comment to mode util function
- change getSpecific method name to getArticle in articles controller
- change getAll method name to getAllArticles in articles controller

[Delivers 159987732]

* ft(user-reading-stats): fix failing travis build

[Delivers 159987732]

* ft(user-reading-stats): fix failing travis build

[Delivers 159987732]

* ft(user-reading-stats): update swagger documentation

- update swagger documentation
- change the route for adding articles to a category

[Delivers 159987732]

* ft(user-reading-stats): users should be able to get their reading stats

- change the name of saveArticleView method to postArticleHistory
- change the name of ArticleView model to ArticleViewHistory

[Delivers 159987732]

* Fix merge conflicts in article.js file

* ft(swagger-documentation): fix swagger docummentation error

[Fixes 159987732]

* fix hound errors
  • Loading branch information
emmaadesile authored and aknwosu committed Sep 17, 2018
1 parent 7d8a850 commit 71b32ab
Show file tree
Hide file tree
Showing 24 changed files with 986 additions and 113 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"name": "express-authorshaven",
"version": "1.0.0",
"engines": {
"node": "10.8.0"
},
"description": "A Social platform for the creative at heart",
"main": "index.js",
"scripts": {
Expand Down
38 changes: 27 additions & 11 deletions server/controllers/article.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import db from '../models';
import {
Article,
User,
Tag,
Comment,
ReportsOnArticle
} from '../models';
import articleValidation from '../utils/articles';
import paginateArticle from '../utils/articlesPaginate';
import Notification from './notifications';
import Search from './search';
import ReportInputValidation from '../utils/validateReportInput';

const {
Article, User, Tag, Comment, ReportsOnArticle
} = db;

/**
* Article controller function
*/
Expand Down Expand Up @@ -132,7 +134,7 @@ class ArticleController {
* @return {json} res
* @description returns all article.
*/
static getAll({ query }, res) {
static getAllArticles({ query }, res) {
const limit = Number(query.limit) || 4;
const currentPage = Number(query.page) || 1;
const offset = (currentPage - 1) * limit;
Expand Down Expand Up @@ -175,10 +177,11 @@ class ArticleController {
* @static
* @param {object} req
* @param {object} res
* @param {object} next
* @return {json} res
* @description returns specific article that has the slug passes as req param (article_slug).
*/
static getSpecific(req, res) {
static getArticle(req, res, next) {
return Article.findOne({
where: {
slug: req.params.article_slug,
Expand All @@ -200,10 +203,23 @@ class ArticleController {
}],
attributes: ['id', 'slug', 'title', 'description', 'body', 'createdAt', 'updatedAt']
})
.then(article => res.status(200).json({
article,
status: 'success'
}))
.then((article) => {
if (!article) {
return res.status(404).json({
status: 'error',
error: 'Article does not exist'
});
}
// Save the view in the Article view table
const articleId = article.id;
const { userId } = req;
res.locals = { userId, articleId };
next();
return res.status(200).json({
article,
status: 'success',
});
})
.catch(error => res.status(400).json({
error,
status: 'error'
Expand Down
19 changes: 11 additions & 8 deletions server/controllers/categoryController.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Category, Article, ArticleCategory } from '../models';
import sanitizeString from '../utils/sanitize';

/**
*
Expand Down Expand Up @@ -38,8 +39,8 @@ class CategoryController {
*/
static createCategory(req, res) {
const name = req.body.name.trim();
const newCategory = `${name.substr(0, 1).toUpperCase()}${name.slice(1).toLowerCase()}`;
if (newCategory === '') {
const newCategory = sanitizeString(name);
if (!newCategory) {
return res.status(400).json({
status: 'error',
error: 'Name field cannot be empty'
Expand Down Expand Up @@ -250,14 +251,16 @@ class CategoryController {
* @memberof CategoryController
*/
static getAllArticlesForACategory(req, res, next) {
const { categoryName } = req.params.categoryName;
const { categoryName } = req.params;
Category.findOne({
where: { name: categoryName },
include: [{
model: Article,
as: 'category',
attributes: { exclude: ['createdAt', 'updatedAt'] }
}],
include: [
{
model: Article,
as: 'category',
attributes: { exclude: ['createdAt', 'updatedAt'] }
},
],
})
.then((category) => {
if (!category) {
Expand Down
3 changes: 2 additions & 1 deletion server/controllers/emailVerificationController.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ dotenv.config();

const secret = process.env.JWT_KEY;
const baseURL = process.env.BASE_URL;
const mailKey = process.env.MAIL_API_KEY;

/**
*
Expand All @@ -30,7 +31,7 @@ class EmailVerificationController {

const url = `${baseURL}/api/users/confirmation/${emailToken}`;

sgMail.setApiKey(process.env.SENDGRID_API_KEY);
sgMail.setApiKey(mailKey);
const msg = {
to: user.email,
from: 'noreply@authorshaven.com',
Expand Down
109 changes: 109 additions & 0 deletions server/controllers/readingStatsController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import {
Article,
ArticleViewHistory,
Category,
LikesDislikes,
ArticleCategory,
} from '../models';
import mode from '../utils/modeValue';

/**
*
* @description controller class with methods for getting user's reading stats
* @class RedingStatsController
*/
class ReadingStatsController {
/**
* @description Get all categories
* @param {object} req body of the user's request
* @param {function} res response from the server
* @param {function} next response from the server
* @returns {object} The body of the response message
* @memberof ReadingStatsController
*/
static getAllReadingStats(req, res, next) {
const { userId } = req;
ArticleViewHistory.findAll({
where: { userId },
attributes: ['articleId'],
include: [
{
model: Article,
as: 'article',
attributes: ['title', 'body', 'description', 'authorId']
}
]
})
.then((articles) => {
const articleCount = articles.map(article => article.articleId);
return LikesDislikes.findAll({
where: { userId },
attributes: ['articleId', 'reaction'],
include: [
{
model: Article,
as: 'article',
attributes: ['title', 'body', 'description']
}
]
})
.then((reaction) => {
ArticleCategory.findAll({
where: { articleId: articleCount }
})
.then((result) => {
const categoryIds = result.map(article => article.categoryId);
return Category.findAll({
where: { id: categoryIds },
attributes: ['name']
})
.then((categoryNames) => {
let mostReadCategory;
if (categoryNames.length === 0) {
mostReadCategory = 'Articles have not been added to any category';
}
const names = categoryNames.map(category => category.name);
mostReadCategory = mode(names);
return res.status(200).json({
status: 'success',
articlesRead: articles.length === 0 ? 'No articles found' : articles,
numberOfArticlesRead: articleCount.length,
articleReactions: reaction.length === 0 ? 'No reactions found' : reaction,
mostReadCategory
});
})
.catch(error => next(error));
})
.catch(error => next(error));
})
.catch(error => next(error));
})
.catch(error => next(error));
}

/**
* @description Get all categories
* @param {object} req body of the user's request
* @param {function} res response from the server
* @param {function} next response from the server
* @returns {object} The body of the response message
* @param {string} articleId body of the user's request
* @memberof ReadingStatsController
*/
static postArticleViewHistory(req, res, next) {
const { userId, articleId } = res.locals;
ArticleViewHistory.findOne({
where: { userId, articleId },
})
.then((userView) => {
if (!userView) {
ArticleViewHistory.create({ articleId, userId })
.then(() => res.status(201).send())
.catch(next);
}
})
.catch(next);
}
}

export default ReadingStatsController;
Loading

0 comments on commit 71b32ab

Please sign in to comment.