-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
29 changed files
with
1,183 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,9 @@ | |
"retainLines": true, | ||
"env": { | ||
"test": { | ||
"plugins": [ | ||
"istanbul" | ||
] | ||
} | ||
} | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,180 @@ | ||
import models from '../models'; | ||
import randomString from '../helpers/randomString'; | ||
import dashReplace from '../helpers/replaceDash'; | ||
|
||
const { | ||
Article | ||
} = models; | ||
/** | ||
* This class contains all the methods responsible for creating and querying | ||
* articles on the app | ||
* It is made up static methods which can be called from anywhere in the app. | ||
*/ | ||
* This class contains all the methods responsible for creating and querying | ||
* articles on the app | ||
* It is made up static methods which can be called from anywhere in the app. | ||
*/ | ||
export default class ArticleController { | ||
/** | ||
* Create an article and returns it. | ||
* @param {object} req the request object | ||
* @param {object} res the response object | ||
* @returns {object} the article that was created. | ||
*/ | ||
static createArticle() { | ||
// to be implemented | ||
* Create an article and return the Data. | ||
* @param {object} req the request object | ||
* @param {object} res the response object | ||
* @returns {object} the article that was created. | ||
*/ | ||
static createArticle(req, res) { | ||
const { | ||
id, | ||
username | ||
} = req.user; | ||
const slug = `${dashReplace(req.body.title)}-${randomString(10)}`; | ||
const { | ||
title, | ||
body, | ||
imageUrl, | ||
categoryId | ||
} = req.body; | ||
|
||
Article.create({ | ||
slug: slug.toLowerCase(), | ||
title, | ||
body, | ||
imageUrl, | ||
categoryId, | ||
userId: id, | ||
createdAt: Date.now(), | ||
}) | ||
.then(newArticle => res.status(200).json({ | ||
status: 200, | ||
success: true, | ||
message: 'Article has been created', | ||
article: { | ||
slug: newArticle.slug, | ||
authorId: newArticle.userId, | ||
categoryId: newArticle.categoryId, | ||
title: newArticle.title, | ||
body: newArticle.body, | ||
imageUrl: newArticle.imageUrl, | ||
Author: username, | ||
createdAt: new Date(newArticle.createdAt).toLocaleString('en-GB', { hour12: true }), | ||
}, | ||
})) | ||
.catch(() => { | ||
res.status(400).json({ | ||
status: 400, | ||
success: false, | ||
error: 'Request was not successfully created', | ||
}); | ||
}); | ||
} | ||
/** | ||
* Update an article and return the Data. | ||
* @param {object} req the request object | ||
* @param {object} res the response object | ||
* @returns {object} the article that was updated. | ||
*/ | ||
|
||
static updateArticle(req, res) { | ||
const { | ||
slug | ||
} = req.params; | ||
const { | ||
title, | ||
body, | ||
imageUrl, | ||
categoryId, | ||
createdAt | ||
} = req.body; | ||
Article.findOne({ | ||
where: { | ||
slug | ||
}, | ||
attributes: ['title', 'slug', 'body', 'imageUrl', 'categoryId', 'createdAt'], | ||
}) | ||
.then((foundArticle) => { | ||
if (!foundArticle) { | ||
return res.status(404).json({ | ||
status: 404, | ||
success: false, | ||
message: 'The specified artcile does not exist', | ||
}); | ||
} | ||
|
||
Article.update({ | ||
slug: foundArticle.slug, | ||
title: title || foundArticle.title, | ||
body: body || foundArticle.body, | ||
imageUrl: imageUrl || foundArticle.imageUrl, | ||
categoryId: categoryId || foundArticle.categoryId, | ||
createdAt, | ||
updatedAt: Date.now() | ||
}, { | ||
returning: true, | ||
where: { | ||
slug | ||
} | ||
}) | ||
.then(([, [updatedArticle]]) => res.status(200).json({ | ||
status: 200, | ||
success: true, | ||
message: `Article with ${slug} has been updated`, | ||
newArticle: { | ||
slug: updatedArticle.slug, | ||
title: updatedArticle.title, | ||
body: updatedArticle.body, | ||
imageUrl: updatedArticle.imageUrl, | ||
categoryId: updatedArticle.categoryId, | ||
createdAt: new Date(updatedArticle.createdAt).toLocaleString('en-GB', { hour12: true }), | ||
updatedAt: new Date(updatedArticle.updatedAt).toLocaleString('en-GB', { hour12: true }) | ||
} | ||
})) | ||
.catch(() => { | ||
res.status(400).json({ | ||
status: 400, | ||
success: false, | ||
error: 'Request not successfully updated', | ||
}); | ||
}); | ||
}); | ||
} | ||
|
||
/** | ||
* Delet an article and return the Data. | ||
* @param {object} req the request object | ||
* @param {object} res the response object | ||
* @returns {object} the article that was deleted. | ||
*/ | ||
|
||
static removeArticle(req, res) { | ||
const { | ||
slug | ||
} = req.params; | ||
Article.findOne({ | ||
where: { | ||
slug | ||
}, | ||
attributes: ['title', 'slug', 'body', 'imageUrl', 'categoryId', 'createdAt'], | ||
}) | ||
.then((foundArticle) => { | ||
if (!foundArticle) { | ||
return res.status(404).json({ | ||
status: 404, | ||
success: false, | ||
message: 'The specified artcile does not exist', | ||
}); | ||
} | ||
Article.destroy({ | ||
where: { | ||
slug | ||
}, | ||
}) | ||
.then(() => { | ||
res.status(200).json({ | ||
status: 200, | ||
success: true, | ||
message: `Article with ${slug} has been successfully deleted`, | ||
}); | ||
}); | ||
}) | ||
.catch(() => res.status(400).json({ | ||
status: 400, | ||
success: false, | ||
Error: 'Article can not be deleted' | ||
})); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/* eslint-disable no-plusplus */ | ||
const randomString = (length) => { | ||
let result = ''; | ||
const alphaNumeric = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; | ||
for (let i = length; i > 0; i--) { | ||
result += alphaNumeric[Math.floor(Math.random() * alphaNumeric.length)]; | ||
} | ||
return result; | ||
}; | ||
|
||
export default randomString; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
const dashReplace = string => string.replace(/[\W_]+/g, '-'); | ||
|
||
export default dashReplace; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/* eslint-disable class-methods-use-this */ | ||
import Validator from 'validatorjs'; | ||
|
||
/** | ||
* @export | ||
* @class Validation | ||
*/ | ||
export default class ArticleValidation { | ||
/** | ||
* Validate create Article Data | ||
* | ||
* @param {object} req - HTTP Request | ||
* @param {object} res - HTTP Response | ||
* @param {function} next | ||
* @returns {object} Class instance | ||
* @memberof Validation | ||
*/ | ||
static validateCreateArticle(req, res, next) { | ||
const articleRules = { | ||
categoryId: 'required|integer|max:5', | ||
title: 'required|string', | ||
body: 'required|string', | ||
}; | ||
|
||
const validate = new Validator(req.body, articleRules); | ||
if (validate.passes()) return next(); | ||
|
||
const error = {}; | ||
const categoryId = validate.errors.first('categoryId'); | ||
const title = validate.errors.first('title'); | ||
const body = validate.errors.first('body'); | ||
|
||
if (categoryId) { | ||
error.categoryId = categoryId; | ||
} | ||
if (title) { | ||
error.title = title; | ||
} | ||
if (body) { | ||
error.body = body; | ||
} | ||
|
||
return res.status(400).json({ | ||
message: 'A Required Field is Missing', | ||
status: 400, | ||
error, | ||
}); | ||
} | ||
|
||
/** | ||
* Validate create Article Data | ||
* | ||
* @param {object} req - HTTP Request | ||
* @param {object} res - HTTP Response | ||
* @param {function} next | ||
* @returns {object} Class instance | ||
* @memberof Validation | ||
*/ | ||
static validateUpdateArticle(req, res, next) { | ||
const articleRules = { | ||
categoryId: 'integer|max:5', | ||
title: 'string', | ||
body: 'string', | ||
}; | ||
|
||
const validate = new Validator(req.body, articleRules); | ||
if (validate.passes()) return next(); | ||
|
||
const error = {}; | ||
const categoryId = validate.errors.first('categoryId'); | ||
const title = validate.errors.first('title'); | ||
const body = validate.errors.first('body'); | ||
|
||
if (categoryId) { | ||
error.categoryId = categoryId; | ||
} | ||
if (title) { | ||
error.title = title; | ||
} | ||
if (body) { | ||
error.body = body; | ||
} | ||
|
||
return res.status(400).json({ | ||
message: 'A Required Field is Missing', | ||
status: 400, | ||
error, | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
|
||
module.exports = { | ||
up: (queryInterface, Sequelize) => queryInterface.createTable('Categories', { | ||
id: { | ||
allowNull: false, | ||
autoIncrement: true, | ||
primaryKey: true, | ||
type: Sequelize.INTEGER | ||
}, | ||
title: { | ||
type: Sequelize.STRING, | ||
allowNull: false | ||
}, | ||
createdAt: { | ||
allowNull: true, | ||
type: Sequelize.DATE | ||
}, | ||
updatedAt: { | ||
allowNull: true, | ||
type: Sequelize.DATE | ||
} | ||
}), | ||
down: queryInterface => queryInterface.dropTable('Categories') | ||
}; |
Oops, something went wrong.