Skip to content

Commit

Permalink
feat(search): implement search and filter functionality
Browse files Browse the repository at this point in the history
- adds a route for searching for articles
- cater for search filtering with tags, author name, and date range

[Finishes #164139695]
  • Loading branch information
codinger41 committed Mar 19, 2019
2 parents 73f3842 + 7637815 commit f8a178a
Show file tree
Hide file tree
Showing 12 changed files with 698 additions and 15 deletions.
71 changes: 70 additions & 1 deletion controllers/articles.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Article, User } from '../models';
* @export
*/
export default class ArticleController {
/**
/**
* @description - Create a new article
* @static
* @param {Object} req - the request object
Expand Down Expand Up @@ -41,6 +41,74 @@ export default class ArticleController {
}
}

/**
* @description - Update an article
* @static
* @param {Object} req - the request object
* @param {Object} res - the response object
* @memberof ArticleController
* @returns {Object} class instance
*/
static async updateArticle(req, res) {
const images = req.images || [];
const {
title, description, body
} = req.body;

const {
params: { slug }
} = req;
try {
const result = await Article.update({
title,
description,
body,
images
}, {
where: {
slug
}
});
return res.status(200).json({
success: true,
message: 'Article updated successfully',
article: result
});
} catch (error) {
return res.status(500).json({
success: false,
errors: [error.message]
});
}
}

/**
* @description - Deletes an article
* @static
* @param {Object} req - the request object
* @param {Object} res - the response object
* @memberof ArticleController
* @returns {Object} class instance
*/
static async deleteArticle(req, res) {
try {
await Article.destroy({
where: {
slug: req.params.slug
}
});
return res.status(200).json({
success: true,
message: 'Article deleted successfully'
});
} catch (error) {
return res.status(500).json({
success: false,
errors: [error.message]
});
}
}

/**
* @description - Search for articles
* @static
Expand All @@ -53,6 +121,7 @@ export default class ArticleController {
try {
const searchTerms = ArticleController.generateSearchQuery(req.query);
const results = await Article.findAll({
raw: true,
where: {
...searchTerms,
},
Expand Down
87 changes: 84 additions & 3 deletions doc.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"/auth/google": {
"get": {
"tags": [
"authentication"
"Authentication"
],
"summary": "User registration or login",
"description": "A Social platform for the creative at heart",
Expand All @@ -80,7 +80,7 @@
"/auth/twitter": {
"get": {
"tags": [
"authentication"
"Authentication"
],
"summary": "User registration or login",
"description": "A Social platform for the creative at heart",
Expand All @@ -100,7 +100,7 @@
"/auth/facebook": {
"get": {
"tags": [
"authentication"
"Authentication"
],
"summary": "User registration or login",
"description": "A Social platform for the creative at heart",
Expand Down Expand Up @@ -382,7 +382,88 @@
"description": "Invalid title/description/body supplied"
}
}
},
"put": {
"tags": [
"Articles"
],
"summary": "Update an article",
"description": "",
"operationId": "updateArticle",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"parameters": [
{
"name": "authorization",
"in": "header",
"description": "A token to verify the user",
"required": true,
"type": "string"
},
{
"in": "body",
"name": "body",
"description": "Updates article",
"required": true,
"schema": {
"$ref": "#/definitions/articles"
}
}
],
"responses": {
"201": {
"description": "Article updated successfully"
},
"422": {
"description": "Invalid title/description/body supplied"
}
}
},
"delete": {
"tags": [
"Articles"
],
"summary": "Delete an article",
"description": "",
"operationId": "deleteArticle",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"parameters": [
{
"name": "authorization",
"in": "header",
"description": "A token to verify the user",
"required": true,
"type": "string"
},
{
"in": "body",
"name": "body",
"description": "Deletes article",
"required": true,
"schema": {
"$ref": "#/definitions/articles"
}
}
],
"responses": {
"201": {
"description": "Article deleted successfully"
},
"422": {
"description": "Invalid title/description/body supplied"
}
}
}

}
},
"definitions": {
Expand Down
32 changes: 32 additions & 0 deletions middleware/validation.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import ExpressValidator from 'express-validator/check';
import { Article } from '../models';

const { check, validationResult } = ExpressValidator;

Expand Down Expand Up @@ -84,6 +85,37 @@ export const validateLogin = [
.withMessage('Please provide a valid password.'),
];

export const validateArticleAuthor = async (req, res, next) => {
const {
user,
params: { slug }
} = req;
try {
const article = await Article.findOne({
where: {
slug
}
});
if (!article) {
return res.status(404).json({
success: false,
errors: ['Article not found']
});
}
if (!(article.userId === user.id)) {
return res.status(403).json({
success: false,
errors: ['You are unauthorized to perform this action']
});
}
return next();
} catch (error) {
return res.status(500).json({
success: false,
errors: ['Article does not exist']
});
}
};
export const validateCategory = [
check('category')
.exists()
Expand Down
Loading

0 comments on commit f8a178a

Please sign in to comment.