-
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 #155 from dali-lab/dev
Add blog endpoints
- Loading branch information
Showing
19 changed files
with
1,449 additions
and
62 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,169 @@ | ||
import mongoose from 'mongoose'; | ||
import { RESPONSE_CODES } from '../constants'; | ||
import { Blog } from '../models'; | ||
import { uploadFileToFirebase } from '../utils'; | ||
|
||
/** | ||
* @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; | ||
if (uploadedFile) { | ||
const filePath = await uploadFileToFirebase( | ||
uploadedFile.path, | ||
`uploads/${uploadedFile.filename}`, | ||
); | ||
post.image = filePath; | ||
} | ||
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); | ||
|
||
if (uploadedFile) { | ||
const filePath = await uploadFileToFirebase( | ||
uploadedFile.path, | ||
`uploads/${uploadedFile.filename}`, | ||
); | ||
|
||
await Blog.updateOne({ _id: postId }, { ...fields, image: filePath }); | ||
} else { | ||
await Blog.updateOne({ _id: postId }, fields); | ||
} | ||
|
||
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.