-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #150 from dali-lab/add-blog-endpoint
Add blog endpoint
- Loading branch information
Showing
17 changed files
with
584 additions
and
50 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 |
---|---|---|
@@ -1,27 +1,28 @@ | ||
{ | ||
extends: "airbnb-base", | ||
parser: "@babel/eslint-parser", | ||
env: { | ||
browser: false, | ||
node: true, | ||
es6: true | ||
"extends": "airbnb-base", | ||
"parser": "@babel/eslint-parser", | ||
"env": { | ||
"browser": false, | ||
"node": true, | ||
"es6": true | ||
}, | ||
rules: { | ||
strict: 0, | ||
quotes: [2, "single"], | ||
no-else-return: 0, | ||
new-cap: ["error", {"capIsNewExceptions": ["Router"]}], | ||
no-console: 0, | ||
import/no-unresolved: [2, { commonjs: true, caseSensitive: false}], | ||
no-unused-vars: ["error", { "vars": "all", "args": "none" }], | ||
no-underscore-dangle: 0, | ||
arrow-body-style: ["error", "always"], | ||
no-shadow: ["error", { "allow": ["done", "res", "cb", "err", "resolve", "reject"] }], | ||
no-use-before-define: ["error", { "functions": false }], | ||
max-len: 0, | ||
no-param-reassign: 0 | ||
"rules": { | ||
"strict": 0, | ||
"quotes": [2, "single"], | ||
"no-else-return": 0, | ||
"new-cap": ["error", {"capIsNewExceptions": ["Router"]}], | ||
"no-console": 0, | ||
"import/no-unresolved": [2, { "commonjs": true, "caseSensitive": false}], | ||
"import/no-extraneous-dependencies": ["error", {"devDependencies": true}], | ||
"no-unused-vars": ["error", { "vars": "all", "args": "none" }], | ||
"no-underscore-dangle": 0, | ||
"arrow-body-style": ["error", "always"], | ||
"no-shadow": ["error", { "allow": ["done", "res", "cb", "err", "resolve", "reject"] }], | ||
"no-use-before-define": ["error", { "functions": false }], | ||
"max-len": 0, | ||
"no-param-reassign": 0 | ||
}, | ||
plugins: [ | ||
'import' | ||
"plugins": [ | ||
"import" | ||
] | ||
} |
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,4 +4,6 @@ yarn-error.log | |
.DS_Store | ||
.env | ||
npm-debug.log | ||
build | ||
build | ||
public/uploads | ||
.vscode |
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,28 @@ | ||
# Blog Operations | ||
|
||
## `GET /blog` | ||
|
||
Returns all blog post objects in the database. | ||
|
||
## `GET /blog/:id` | ||
|
||
Returns blog post object of specified `id` in the database. | ||
|
||
## `PUT /blog/:id` | ||
|
||
Expects authorization header with Bearer token. | ||
Updates blog post object of specified `id` in the database with the fields supplied in a JSON body. | ||
|
||
## `DELETE /blog/:id` | ||
|
||
Expects authorization header with Bearer token. | ||
Deletes blog post object of specified `id` in the database | ||
|
||
## `POST /blog/create` | ||
|
||
Expects authorization header with Bearer token. | ||
Creates blog post with fields provided in multipart/form-data body. Requires `title` and `body`, has optional `image` field. `author` is fetched from the session info. | ||
|
||
## `GET /blog/user/:id` | ||
|
||
Returns blog post object of specified author `id` in the database. |
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
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
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,157 @@ | ||
import mongoose from 'mongoose'; | ||
import { RESPONSE_CODES } from '../constants'; | ||
import { Blog } from '../models'; | ||
|
||
/** | ||
* @description retrieves blog post object | ||
* @param {String} id blog post id | ||
* @returns {Promise<Blog>} promise that resolves to blog post object or error | ||
*/ | ||
export const getBlogPostById = async (id) => { | ||
try { | ||
const blogPost = await Blog.findById(id); | ||
|
||
if (blogPost) { | ||
return { | ||
...RESPONSE_CODES.SUCCESS, | ||
blogPost, | ||
}; | ||
} | ||
return RESPONSE_CODES.NOT_FOUND; | ||
} catch (error) { | ||
console.log(error); | ||
return RESPONSE_CODES.NOT_FOUND; | ||
} | ||
}; | ||
|
||
/** | ||
* @description retrieves blog all blog posts by given author | ||
* @param {String} id author id | ||
* @returns {Promise<Blog[]>} promise that resolves to blog post objects array or error | ||
*/ | ||
export const getBlogPostsByAuthorId = async (id) => { | ||
try { | ||
const blogPosts = await Blog.find({ authorId: id }); | ||
|
||
if (blogPosts) { | ||
return { | ||
...RESPONSE_CODES.SUCCESS, | ||
blogPosts, | ||
}; | ||
} | ||
return RESPONSE_CODES.NOT_FOUND; | ||
} catch (error) { | ||
console.error(error); | ||
return RESPONSE_CODES.NOT_FOUND; | ||
} | ||
}; | ||
|
||
/** | ||
* @description creates blog post object in database | ||
* @param {Object} fields blog post fields (title, body) | ||
* @param {File} uploadedFile the image that was uploaded by the user | ||
* @param {Object} user user who created the blog post | ||
* @returns {Promise<Blog>} promise that resolves to blog object or error | ||
*/ | ||
export const createBlogPost = async (fields, uploadedFile, user) => { | ||
const { title, body } = fields; | ||
|
||
const post = new Blog(); | ||
|
||
const { first_name: firstName, last_name: lastName, _id: id } = user; | ||
|
||
post.title = title; | ||
post.body = body; | ||
post.author = `${firstName} ${lastName}`; | ||
post.authorId = id; | ||
post.image = uploadedFile?.path || null; | ||
|
||
try { | ||
const savedPost = await post.save(); | ||
return savedPost.toJSON(); | ||
} catch (error) { | ||
if (error.name === 'ValidationError') { | ||
if (error.errors.title) { | ||
const errorToThrow = new Error(error.errors.title.properties.message); | ||
errorToThrow.code = RESPONSE_CODES.VALIDATION_ERROR; | ||
throw errorToThrow; | ||
} else if (error.errors.body) { | ||
const errorToThrow = new Error(error.errors.body.properties.message); | ||
errorToThrow.code = RESPONSE_CODES.VALIDATION_ERROR; | ||
throw errorToThrow; | ||
} | ||
} | ||
throw new Error({ | ||
code: RESPONSE_CODES.INTERNAL_ERROR, | ||
error, | ||
}); | ||
} | ||
}; | ||
|
||
/** | ||
* @description update blog post object | ||
* @param {Object} fields blog post fields (title, body, image) | ||
* @param {String} id blog post id | ||
* @returns {Promise<Blog>} promise that resolves to blog object or error | ||
*/ | ||
export const updateBlogPost = async (id, fields, uploadedFile) => { | ||
const { id: providedId, _id: providedUnderId } = fields; | ||
|
||
// reject update of id | ||
if (providedId || providedUnderId) { | ||
throw new Error({ | ||
code: RESPONSE_CODES.BAD_REQUEST, | ||
error: { message: 'Cannot update blog post id' }, | ||
}); | ||
} | ||
|
||
try { | ||
const postId = new mongoose.Types.ObjectId(id); | ||
|
||
await Blog.updateOne( | ||
{ _id: postId }, | ||
{ ...fields, image: uploadedFile?.path || null }, | ||
); | ||
|
||
const blogPost = await Blog.findById(postId); | ||
|
||
await blogPost.save(); | ||
|
||
return { | ||
...RESPONSE_CODES.SUCCESS, | ||
blogPost: blogPost.toJSON(), | ||
}; | ||
} catch (error) { | ||
if (error.name === 'ValidationError') { | ||
if (error.errors.title) { | ||
const errorToThrow = new Error(error.errors.title.properties.message); | ||
errorToThrow.code = RESPONSE_CODES.VALIDATION_ERROR; | ||
throw errorToThrow; | ||
} else if (error.errors.body) { | ||
const errorToThrow = new Error(error.errors.body.properties.message); | ||
errorToThrow.code = RESPONSE_CODES.VALIDATION_ERROR; | ||
throw errorToThrow; | ||
} | ||
} | ||
throw new Error({ | ||
code: RESPONSE_CODES.INTERNAL_ERROR, | ||
error, | ||
}); | ||
} | ||
}; | ||
|
||
/** | ||
* @description removes blog post with given id | ||
* @param {String} id blog post id | ||
* @param {String} userId id of a user who requests deletion | ||
* @returns {Promise<Blog>} promise that resolves to success object or error | ||
*/ | ||
export const deleteBlogPost = async (id, userId) => { | ||
try { | ||
await Blog.deleteOne({ authorId: userId, _id: id }); | ||
return RESPONSE_CODES.SUCCESS; | ||
} catch (error) { | ||
console.log(error); | ||
return 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
/* eslint-disable import/prefer-default-export */ | ||
import * as User from './user'; | ||
import * as Blog from './blog'; | ||
|
||
export { | ||
User, | ||
}; | ||
export { User, Blog }; |
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,35 @@ | ||
import mongoose, { Schema } from 'mongoose'; | ||
|
||
const BlogPostSchema = new Schema( | ||
{ | ||
title: { | ||
type: String, | ||
required: [true, 'A blog post must have a title'], | ||
}, | ||
body: { | ||
type: String, | ||
required: [true, 'A blog post must have a body'], | ||
}, | ||
author: { | ||
type: String, | ||
required: true, | ||
}, | ||
authorId: { | ||
type: mongoose.Schema.Types.ObjectId, | ||
ref: 'User', | ||
}, | ||
image: { | ||
type: String, | ||
}, | ||
}, | ||
{ | ||
toJSON: { | ||
virtuals: true, | ||
}, | ||
timestamps: { createdAt: 'date_created', updatedAt: 'date_edited' }, | ||
}, | ||
); | ||
|
||
const BlogModel = mongoose.model('Blog', BlogPostSchema); | ||
|
||
export default BlogModel; |
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,6 +1,8 @@ | ||
/* eslint-disable import/prefer-default-export */ | ||
import User from './user'; | ||
import Blog from './blog'; | ||
|
||
export { | ||
User, | ||
Blog, | ||
}; |
Oops, something went wrong.