Skip to content

Commit

Permalink
Merge c39cfb9 into da24335
Browse files Browse the repository at this point in the history
  • Loading branch information
rafmme committed Jan 28, 2019
2 parents da24335 + c39cfb9 commit e5b99fc
Show file tree
Hide file tree
Showing 11 changed files with 454 additions and 77 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
"methods": "^1.1.2",
"mocha-lcov-reporter": "^1.3.0",
"morgan": "^1.9.1",
"node-boolify": "^1.0.5",
"passport": "^0.4.0",
"passport-facebook": "^2.1.1",
"passport-google-oauth20": "^1.0.0",
Expand Down
178 changes: 128 additions & 50 deletions server/controllers/ArticleController.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Boolify } from 'node-boolify';
import { Sequelize } from 'sequelize';
import db from '../models';
import ArticleHelper from '../helpers/ArticleHelper';
import Util from '../helpers/Util';
Expand All @@ -8,6 +8,7 @@ import SearchController from './SearchController';
import pagination from '../helpers/pagination';

const { Article, Tag, User } = db;
const { Op } = Sequelize;

/**
* @class ArticleController
Expand Down Expand Up @@ -35,29 +36,27 @@ class ArticleController {
content,
banner: banner || 'https://unsplash.com/photos/Q7wDdmgCBFg',
tagsList: tagsArray,
isPublished: Boolify(isPublished) || true,
isPublished: Boolean(isPublished),
isReported: false
};

let article = await Article.create(articleData);
article = article.toJSON();
article.tags = articleData.tagsList;
const { createdAt, updatedAt } = article;

if (article) {
article = article.toJSON();
article.tags = articleData.tagsList;
const { createdAt, updatedAt } = article;
await TagHelper.findOrAddTag(article.id, tagsArray);
article.createdAt = Util.formatDate(createdAt);
article.updatedAt = Util.formatDate(updatedAt);
await TagHelper.findOrAddTag(article.id, tagsArray);
article.createdAt = Util.formatDate(createdAt);
article.updatedAt = Util.formatDate(updatedAt);

return response(
res,
201,
'success',
'New article has been successfully created',
null,
article
);
}
return response(
res,
201,
'success',
'New article has been successfully created',
null,
article
);
} catch (error) {
return response(
res,
Expand Down Expand Up @@ -157,25 +156,28 @@ class ArticleController {
static async fetchOne(req, res) {
try {
const { slug } = req.params;
const userId = req.user !== undefined ? req.user.userId : null;

let article = await Article.findOne({
where: {
slug
slug,
[Op.or]: [{ isPublished: true }, { userId }],
},
attributes: { exclude: ['userId'] },
include: [
{
model: User,
as: 'author',
attributes: ['userName', 'bio', 'img']
},
{
model: Tag,
as: 'tags',
attributes: ['name'],
through: { attributes: [] }
}
include: [{
model: User,
as: 'author',
attributes: ['userName', 'bio', 'img'],
},
{
model: Tag,
as: 'tags',
attributes: ['name'],
through: { attributes: [] }
},
]
});

if (article) {
article = article.toJSON();
const tags = article.tags.map(tag => tag.name);
Expand All @@ -184,30 +186,21 @@ class ArticleController {
article.updatedAt = Util.formatDate(article.updatedAt);

return response(
res,
200,
'success',
res, 200, 'success',
'Article was fetched successfully',
null,
article
null, article
);
}
return response(
res,
404,
'failure',
res, 404, 'failure',
'not found error',
{ message: 'Article not found' },
null
{ message: 'Article not found' }
);
} catch (error) {
return response(
res,
500,
'failure',
res, 500, 'failure',
'server error',
{ message: 'Something went wrong on the server' },
null
{ message: 'Something went wrong on the server' }
);
}
}
Expand All @@ -230,10 +223,9 @@ class ArticleController {
}
});
if (result) {
const articleSlug =
result.title.toLowerCase() === req.body.title.toLowerCase()
? result.slug
: ArticleHelper.generateArticleSlug(req.body.title);
const articleSlug = result.title.toLowerCase() === req.body.title.toLowerCase()
? result.slug
: ArticleHelper.generateArticleSlug(req.body.title);

req.body.slug = articleSlug;
let article = await result.update(req.body);
Expand Down Expand Up @@ -316,6 +308,92 @@ class ArticleController {
return response(res, 400, 'failure', 'No search parameters supplied', null, null);
}
}

/**
* @static
* @description this handles fetching of a particular articles for a user
* @param {object} req HTTP request object
* @param {object} res HTTP response object
* @returns {object} api route response with the articles
*/
static async fetchAllUserArticles(req, res) {
try {
const { userId } = req.user;
const { tag, drafts, published, page } = req.query;

const limit = Number(req.query.limit) || 20;
const currentPage = Number(page) || 1;
const offset = (currentPage - 1) * limit;

const articlesCount = await Article.findAndCountAll({
where: { userId },
include: [
{
model: User,
as: 'author',
attributes: ['userName', 'bio', 'img']
},
],
});
const totalArticles = articlesCount.count;

const articles = await Article.findAndCountAll({
where: { userId },
include: [
{
model: User,
as: 'author',
attributes: ['userName', 'bio', 'img']
},
{
model: Tag,
as: 'tags',
attributes: ['name'],
through: { attributes: [] }
}
],
limit,
offset
});


if (articles.count > 0) {
let articleList = articles.rows.map((article) => {
article = article.toJSON();
article.tags = article.tags.map(tag => tag.name);
return article;
});

if (tag) {
articleList = ArticleHelper.filterAuthorArticle(articleList, 'tag', tag);
} else if (drafts === '') {
articleList = ArticleHelper.filterAuthorArticle(articleList, 'drafts');
} else if (published === '') {
articleList = ArticleHelper.filterAuthorArticle(articleList, 'published');
}

const paginatedData = pagination(articleList.length, limit, currentPage, totalArticles);
const data = {
articles: articleList,
paginatedData
};

return response(res, 200, 'success', 'All User articles', null, data);
}
return response(res, 200, 'success', 'All User articles', null, {
message: 'No articles posted yet'
});
} catch (error) {
return response(
res,
500,
'failure',
'server error',
{ message: 'Something went wrong on the server' },
null
);
}
}
}

export default ArticleController;
28 changes: 28 additions & 0 deletions server/helpers/ArticleHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,34 @@ class ArticleHelper {
return slug;
}
}

/**
* @static
* @description a function for filtering an array of articles
* @param {array} arrayOfArticles
* @param {string} filteringOption { tag or drafts or published }
* @param {string} tagKeyword tag word
* @returns {array} returns the the filtered array
*/
static filterAuthorArticle(arrayOfArticles, filteringOption, tagKeyword) {
let filteredArray = [];
switch (filteringOption) {
case 'tag':
filteredArray = arrayOfArticles
.filter(articleArray => articleArray.tags
.map(tag => tag.toLowerCase())
.indexOf(tagKeyword.toLowerCase()) !== -1);
return filteredArray;
case 'drafts':
filteredArray = arrayOfArticles.filter(articleArray => articleArray.isPublished === false);
return filteredArray;
case 'published':
filteredArray = arrayOfArticles.filter(articleArray => articleArray.isPublished === true);
return filteredArray;
default:
return arrayOfArticles;
}
}
}

export default ArticleHelper;
14 changes: 7 additions & 7 deletions server/middlewares/validations/ArticleValidation.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/* eslint-disable no-useless-escape */
/* eslint-disable no-unused-expressions */
/* eslint-disable prefer-const */

import { Boolify } from 'node-boolify';
import db from '../../models';
import Util from '../../helpers/Util';
import response from '../../helpers/response';
Expand Down Expand Up @@ -163,9 +161,9 @@ class ArticleValidation {
req.body.banner = req.body.banner
? Util.removeExtraWhitespace(req.body.banner) : article.banner;
req.body.isPublished = req.body.isPublished !== undefined
? Boolify(req.body.isPublished) : article.isPublished;
? Boolean(req.body.isPublished) : article.isPublished;
req.body.isReported = req.body.isReported !== undefined
? Boolify(req.body.isReported) : article.isReported;
? Boolean(req.body.isReported) : article.isReported;
return next();
}
return response(
Expand Down Expand Up @@ -198,7 +196,7 @@ class ArticleValidation {
return next();
}
if (!Number.isSafeInteger(parseInt(limit, 10))) {
response(res, 400, 'failure', 'There was an issue with your query');
return response(res, 400, 'failure', 'There was an issue with your query');
}
return next();
} catch (error) {
Expand All @@ -207,7 +205,8 @@ class ArticleValidation {
'server error',
{
message: 'Something went wrong on the server'
}, null);
}, null
);
}
}

Expand Down Expand Up @@ -238,7 +237,8 @@ class ArticleValidation {
'server error',
{
message: 'Something went wrong on the server'
}, null);
}
);
}
}
}
Expand Down
15 changes: 15 additions & 0 deletions server/routes/api/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import followController from '../../controllers/followController';
import AuthMiddleware from '../../middlewares/AuthMiddleware';
import handleValidationErrors from '../../middlewares/validations/handleValidationErrors';
import { signUpSchema, logInSchema, editProfileSchema } from '../../middlewares/validations/userValidation';
import ArticleController from '../../controllers/ArticleController';
import ArticleValidation from '../../middlewares/validations/ArticleValidation';

const userRoutes = Router();

Expand Down Expand Up @@ -38,4 +40,17 @@ userRoutes.delete(
AuthMiddleware.checkIfUserIsAuthenticated,
followController.unfollowUser
);
userRoutes.get(
'/myArticles',
AuthMiddleware.checkIfUserIsAuthenticated,
ArticleValidation.verifyLimitParams,
ArticleValidation.verifyPageParams,
ArticleController.fetchAllUserArticles
);
userRoutes.get(
'/myArticles/:slug',
AuthMiddleware.checkIfUserIsAuthenticated,
ArticleController.fetchOne
);

export default userRoutes;
8 changes: 6 additions & 2 deletions server/seeders/20190115151310-demoUser.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@

export default {
up: (queryInterface, Sequelize) => queryInterface.bulkInsert('Users', [{
id: '45745c60-7b1a-11e8-9c9c-2d42b21b1a3e',
fullName: 'Jesse',
userName: 'jesseinit',
email: 'jesseinit@now.com',
bio: 'Gitting Started',
isVerified: true,
password: '$2y$10$z7F4f33h3XJvw/ke6ncO3uY1KdFQJb0.pcwhVh5BRgdfyc0Itlz/i',
authTypeId: '15745c60-7b1a-11e8-9c9c-2d42b21b1a3e'
}, {
Expand All @@ -13,7 +15,8 @@ export default {
userName: 'kabir',
email: 'kabir@now.com',
bio: 'Learning life now',
password: '$2y$10$QCQ1uW0OWH7xKOvJ9gNWsewzoXSjvAmXw21mcZBEB52TN6T/f2Xfy',
isVerified: true,
password: 'Blahblah',
authTypeId: '15745c60-7b1a-11e8-9c9c-2d42b21b1a3e'
},
{
Expand All @@ -22,7 +25,8 @@ export default {
userName: 'steve',
email: 'steve@now.com',
bio: 'Gitting Started',
password: '$2y$10$5hj02gtnG2xxYHqpkrqeXOs3kj0t3uTKUMqdKBYGeHOKRNrZdTT9O',
password: 'Blahblah',
isVerified: false,
authTypeId: '15745c60-7b1a-11e8-9c9c-2d42b21b1a3e'
}
], {}),
Expand Down
Loading

0 comments on commit e5b99fc

Please sign in to comment.