-
Notifications
You must be signed in to change notification settings - Fork 8
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
18 changed files
with
956 additions
and
294 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
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,103 @@ | ||
/* eslint-disable prefer-const */ | ||
/* eslint-disable require-jsdoc */ | ||
/* eslint-disable no-console */ | ||
import articles from '../../helpers/articlesHelper'; | ||
import models from '../../sequelize/models'; | ||
|
||
const { article } = models; | ||
|
||
/** | ||
* @Author - Audace Uhiriwe | ||
*/ | ||
class articlesController { | ||
/** | ||
* creating a new article | ||
* @param {object} req - Request. | ||
* @param {object} res - Response. | ||
* @returns {object} - Contains an article information. | ||
*/ | ||
static async createArticle(req, res) { | ||
const dataValues = await articles.createNewArticle(req); | ||
const { | ||
slug, | ||
title, | ||
description, | ||
body, | ||
tagList, | ||
author, | ||
updatedAt, | ||
createdAt | ||
} = dataValues; | ||
|
||
const result = { | ||
slug, | ||
title, | ||
description, | ||
body, | ||
tagList, | ||
updatedAt, | ||
createdAt, | ||
author | ||
}; | ||
res.status(201).send({ | ||
article: result | ||
}); | ||
} | ||
|
||
static async getAllArticle(req, res) { | ||
const allArticle = await articles.getAllArticle(); | ||
res.status(200).send({ | ||
articles: allArticle | ||
}); | ||
} | ||
|
||
static async getOneArticle(req, res) { | ||
const { slug } = req.params; | ||
const oneArticle = await articles.getOneSlug(slug); | ||
res.status(200).send({ | ||
article: oneArticle | ||
}); | ||
} | ||
|
||
static async updateArticle(req, res) { | ||
const { slug } = req.params; | ||
const { title, body, description } = req.body; | ||
|
||
const updateSlug = { | ||
title: title || req.foundArticle.title, | ||
body: body || req.foundArticle.body, | ||
description: description || req.foundArticle.description | ||
}; | ||
|
||
// @updating the slug | ||
const updatedSlug = await articles.createSlug(updateSlug.title); | ||
|
||
// @Updating the article's data in Database | ||
await article.update( | ||
{ | ||
slug: updatedSlug, | ||
title: updateSlug.title, | ||
body: updateSlug.body, | ||
description: updateSlug.description | ||
}, | ||
{ where: { slug } } | ||
); | ||
|
||
// @returning the response | ||
res.status(200).send({ | ||
message: 'Article updated successfully', | ||
article: updateSlug | ||
}); | ||
} | ||
|
||
static async deleteArticle(req, res) { | ||
const { slug } = req.params; | ||
|
||
// @delete an article in Database | ||
await article.destroy({ where: { slug } }); | ||
|
||
// @returning the response | ||
res.status(200).send({ message: 'Article deleted successfully!' }); | ||
} | ||
} | ||
export default articlesController; |
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,22 @@ | ||
import { Router } from 'express'; | ||
import articlesController from '../controllers/articlesController'; | ||
import isAuth from '../../middleware/auth'; | ||
import check from '../../middleware/checkOwner'; | ||
import validate from '../../middleware/validations'; | ||
|
||
const articlesRouter = Router(); | ||
const { | ||
createArticle, getAllArticle, getOneArticle, updateArticle, deleteArticle | ||
} = articlesController; | ||
|
||
articlesRouter.post('/', isAuth.verifyToken, validate.createValidations, createArticle); | ||
|
||
articlesRouter.get('/', getAllArticle); | ||
|
||
articlesRouter.get('/:slug', getOneArticle); | ||
|
||
articlesRouter.put('/:slug', isAuth.verifyToken, check.articleOwner, validate.updateValidations, updateArticle); | ||
|
||
articlesRouter.delete('/:slug', isAuth.verifyToken, check.articleOwner, deleteArticle); | ||
|
||
export default articlesRouter; |
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,78 @@ | ||
/* eslint-disable require-jsdoc */ | ||
/* eslint-disable valid-jsdoc */ | ||
import slug from 'slug'; | ||
import uniqid from 'uniqid'; | ||
import models from '../sequelize/models'; | ||
|
||
const { article, User } = models; | ||
|
||
/** | ||
* @description Helpers for articles | ||
*/ | ||
class ArticlesHelper { | ||
/** | ||
* @param {title} | ||
* @returns {newSlug} return a new slug | ||
*/ | ||
static createSlug(title) { | ||
const newSlug = `${slug(title, { lower: true })}-${uniqid.process()}`; | ||
return newSlug; | ||
} | ||
|
||
/** | ||
* @param {object} req - Request. | ||
* @param {object} res - Response. | ||
* @returns {object} - Contains an article information. | ||
*/ | ||
static async createNewArticle(req) { | ||
const { | ||
title, body, description, tagList | ||
} = req.body; | ||
const { id } = req.user; | ||
const newSlug = this.createSlug(title); | ||
const { dataValues } = await article.create({ | ||
slug: newSlug, | ||
title, | ||
description, | ||
body, | ||
tagList: tagList.split(','), | ||
authorid: parseInt(id, 10) | ||
}); | ||
const userInfo = await this.getUserInfo(id); | ||
const { username, bio, image } = userInfo; | ||
const author = { username, bio, image }; | ||
dataValues.author = author; | ||
return dataValues; | ||
} | ||
|
||
static async getUserInfo(id) { | ||
const { dataValues } = await User.findOne({ where: { id } }); | ||
return dataValues; | ||
} | ||
|
||
static async getAllArticle() { | ||
const result = await article.findAll({ | ||
include: [{ | ||
as: 'author', | ||
model: User, | ||
attributes: ['username', 'bio', 'image'] | ||
}], | ||
attributes: ['slug', 'title', 'description', 'body', 'tagList', 'updatedAt', 'createdAt'] | ||
}); | ||
return result; | ||
} | ||
|
||
static async getOneSlug(newSlug) { | ||
const result = await article.findOne({ | ||
where: { slug: newSlug }, | ||
include: [{ | ||
as: 'author', | ||
model: User, | ||
attributes: ['username', 'bio', 'image'] | ||
}], | ||
attributes: ['slug', 'title', 'description', 'body', 'tagList', 'updatedAt', 'createdAt'] | ||
}); | ||
return result; | ||
} | ||
} | ||
export default ArticlesHelper; |
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,27 @@ | ||
/* eslint-disable require-jsdoc */ | ||
import Joi from 'joi'; | ||
/** | ||
* @description - validating the request | ||
*/ | ||
class validations { | ||
static createValidations(data) { | ||
const schema = { | ||
title: Joi.string().required(), | ||
body: Joi.string().required(), | ||
description: Joi.string().required(), | ||
tagList: Joi.string().required() | ||
}; | ||
return Joi.validate(data, schema); | ||
} | ||
|
||
static updateValidations(updatedData) { | ||
const schema = { | ||
title: Joi.string(), | ||
body: Joi.string(), | ||
description: Joi.string(), | ||
tagList: Joi.string() | ||
}; | ||
return Joi.validate(updatedData, schema); | ||
} | ||
} | ||
export default validations; |
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,31 @@ | ||
/* eslint-disable valid-jsdoc */ | ||
import models from '../sequelize/models'; | ||
|
||
const { article } = models; | ||
|
||
/** | ||
* @description Helpers for articles | ||
*/ | ||
class checkOwner { | ||
/** | ||
* @author Audace Uhiriwe | ||
* @param {req} - request | ||
* @param {res} - response | ||
*/ | ||
static async articleOwner(req, res, next) { | ||
const { id } = req.user; | ||
const { slug } = req.params; | ||
|
||
// @check if the article's slug exist | ||
const result = await article.findOne({ where: { slug } }); | ||
if (result === null) return res.status(404).send({ error: 'Slug Not found!' }); | ||
|
||
// @check if the user who logged in - is the owner of that slug | ||
const response = await article.findOne({ where: { slug, authorid: id } }); | ||
if (!response) return res.status(403).send({ error: 'Sorry!, you are not the owner of this slug' }); | ||
|
||
req.foundArticle = response.dataValues; | ||
return next(); | ||
} | ||
} | ||
export default checkOwner; |
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 @@ | ||
/* eslint-disable no-useless-escape */ | ||
/* eslint-disable require-jsdoc */ | ||
import validate from '../helpers/validationSchema'; | ||
/** | ||
* @description - Middleware for validating the request body | ||
*/ | ||
class validations { | ||
static createValidations(req, res, next) { | ||
const { error } = validate.createValidations(req.body); | ||
|
||
// @check if there is an error in the request sent | ||
if (error) return res.status(400).send({ error: error.details[0].message.replace(/[$\/\\#,+()$~%.'":*<>{}]/g, '') }); | ||
return next(); | ||
} | ||
|
||
static updateValidations(req, res, next) { | ||
const { error } = validate.updateValidations(req.body); | ||
|
||
// @check if there is an error in the request sent | ||
if (error) return res.status(400).send({ error: error.details[0].message.replace(/[$\/\\#,+()$~%.'":*<>{}]/g, '') }); | ||
return next(); | ||
} | ||
} | ||
export default validations; |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.