Skip to content

Commit a99d5e5

Browse files
committed
Added Book Add/Update/List/Detail
1 parent b4a2757 commit a99d5e5

File tree

11 files changed

+225
-22
lines changed

11 files changed

+225
-22
lines changed

.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
MONGODB_URL=YourConnectionString
22
JWT_SECRET=YourSecret
3-
JWT_TIMEOUT_DURATION=2
3+
JWT_TIMEOUT_DURATION="2 hours"

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,6 @@ typings/
5959

6060
# next.js build output
6161
.next
62+
63+
#vs code configurations
64+
.vscode/

app.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,10 @@ app.all("*", function(req, res) {
3838
return apiResponse.notFoundResponse(res, 'Page not found');
3939
});
4040

41+
app.use((err, req, res, next) => {
42+
if(err.name == "UnauthorizedError"){
43+
return apiResponse.unauthorizedResponse(res, err.message);
44+
}
45+
});
46+
4147
module.exports = app;

controllers/BookController.js

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
const Book = require("../models/BookModel");
2+
const { body,validationResult } = require('express-validator');
3+
const { sanitizeBody } = require('express-validator');
4+
const apiResponse = require('../helpers/apiResponse');
5+
const auth = require('../middlewares/jwt');
6+
var moment = require('moment');
7+
var mongoose = require('mongoose');
8+
9+
function BookData(data) {
10+
this.title= data.title;
11+
this.description = data.description;
12+
this.isbn = data.isbn;
13+
this.createdAt = data.createdAt;
14+
}
15+
16+
/**
17+
* Book List.
18+
*
19+
* @returns {Object}
20+
*/
21+
exports.bookList = [
22+
auth,
23+
function (req, res) {
24+
try {
25+
Book.find({user: req.user._id},'title description isbn createdAt').then((books)=>{
26+
if(books.length > 0){
27+
return apiResponse.successResponseWithData(res, 'Operation success', books);
28+
}else{
29+
return apiResponse.successResponseWithData(res, "Operation success", {});
30+
}
31+
});
32+
} catch (err) {
33+
//throw error in json response with status 500.
34+
return apiResponse.ErrorResponse(res, err);
35+
}
36+
}
37+
];
38+
39+
/**
40+
* Book Detail.
41+
*
42+
* @returns {Object}
43+
*/
44+
exports.bookDetail = [
45+
auth,
46+
function (req, res) {
47+
if(!mongoose.Types.ObjectId.isValid(req.params.id)){
48+
return apiResponse.successResponseWithData(res, "Operation success", {});
49+
}
50+
try {
51+
Book.findOne({_id: req.params.id,user: req.user._id},'title description isbn createdAt').then((book)=>{
52+
if(book !== null){
53+
let bookData = new BookData(book);
54+
return apiResponse.successResponseWithData(res, 'Operation success', bookData);
55+
}else{
56+
return apiResponse.successResponseWithData(res, "Operation success", {});
57+
}
58+
});
59+
} catch (err) {
60+
//throw error in json response with status 500.
61+
return apiResponse.ErrorResponse(res, err);
62+
}
63+
}
64+
];
65+
66+
/**
67+
* Store book.
68+
*
69+
* @param {string} title
70+
* @param {string} description
71+
* @param {string} isbn
72+
*
73+
* @returns {Object}
74+
*/
75+
exports.bookStore = [
76+
auth,
77+
body('title', 'Title must not be empty.').isLength({ min: 1 }).trim(),
78+
body('description', 'Description must not be empty.').isLength({ min: 1 }).trim(),
79+
body('isbn', 'ISBN must not be empty').isLength({ min: 1 }).trim().custom(value => {
80+
return Book.findOne({isbn : value,user: req.user._id}).then(book => {
81+
if (book) {
82+
return Promise.reject('Book already exist with this ISBN no.');
83+
}
84+
});
85+
}),
86+
sanitizeBody('*').escape(),
87+
(req, res, next) => {
88+
try {
89+
const errors = validationResult(req);
90+
var book = new Book(
91+
{ title: req.body.title,
92+
user: req.user,
93+
description: req.body.description,
94+
isbn: req.body.isbn
95+
});
96+
97+
if (!errors.isEmpty()) {
98+
return apiResponse.validationErrorWithData(res, 'Validation Error.', errors.array());
99+
}
100+
else {
101+
//Save book.
102+
book.save(function (err) {
103+
if (err) { return apiResponse.ErrorResponse(res, err); }
104+
let bookData = new BookData(book);
105+
return apiResponse.successResponseWithData(res,'Book add Success.', bookData);
106+
});
107+
}
108+
} catch (err) {
109+
//throw error in json response with status 500.
110+
return apiResponse.ErrorResponse(res, err);
111+
}
112+
}
113+
];
114+
115+
/**
116+
* Store book.
117+
*
118+
* @param {string} title
119+
* @param {string} description
120+
* @param {string} isbn
121+
*
122+
* @returns {Object}
123+
*/
124+
exports.bookUpdate = [
125+
auth,
126+
body('title', 'Title must not be empty.').isLength({ min: 1 }).trim(),
127+
body('description', 'Description must not be empty.').isLength({ min: 1 }).trim(),
128+
body('isbn', 'ISBN must not be empty').isLength({ min: 1 }).trim(),
129+
sanitizeBody('*').escape(),
130+
(req, res, next) => {
131+
try {
132+
const errors = validationResult(req);
133+
var book = new Book(
134+
{ title: req.body.title,
135+
description: req.body.description,
136+
isbn: req.body.isbn,
137+
_id:req.params.id
138+
});
139+
140+
if (!errors.isEmpty()) {
141+
return apiResponse.validationErrorWithData(res, 'Validation Error.', errors.array());
142+
}
143+
else {
144+
if(!mongoose.Types.ObjectId.isValid(req.params.id)){
145+
return apiResponse.validationErrorWithData(res, 'Invalid Error.', "Invalid ID");
146+
}
147+
Book.findOne({isbn : req.body.isbn,user: req.user._id, _id: { "$ne": req.params.id }}).then(book => {
148+
if (book) {
149+
return apiResponse.validationErrorWithData(res, 'Validation Error.', "Book already exist with this ISBN no.");
150+
}
151+
});
152+
//Check authorized user
153+
Book.findById(req.params.id, function (err, book) {
154+
if(book.user.toString() !== req.user._id){
155+
return apiResponse.unauthorizedResponse(res, 'You are not authorized to do this operation.');
156+
}
157+
});
158+
//Save book.
159+
Book.findByIdAndUpdate(req.params.id, book, {},function (err) {
160+
if (err) { return apiResponse.ErrorResponse(res, err); }
161+
let bookData = new BookData(book);
162+
return apiResponse.successResponseWithData(res,'Book update Success.', bookData);
163+
});
164+
}
165+
} catch (err) {
166+
//throw error in json response with status 500.
167+
return apiResponse.ErrorResponse(res, err);
168+
}
169+
}
170+
];

middlewares/jwt.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const jwt = require('express-jwt');
2+
const secret = process.env.JWT_SECRET;
3+
4+
const authenticate = jwt({
5+
secret: secret
6+
});
7+
8+
module.exports = authenticate;

models/BookModel.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
var mongoose = require('mongoose');
2+
var moment = require('moment');
3+
4+
var Schema = mongoose.Schema;
5+
6+
var BookSchema = new Schema({
7+
title: {type: String, required: true},
8+
description: {type: String, required: true},
9+
isbn: {type: String, required: true},
10+
user: { type: Schema.ObjectId, ref: 'User', required: true },
11+
}, {timestamps: true});
12+
13+
module.exports = mongoose.model('Book', BookSchema);

models/UserModel.js

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,11 @@
11
var mongoose = require('mongoose');
22

33
var UserSchema = new mongoose.Schema({
4-
firstName: {
5-
type: String,
6-
required: true
7-
},
8-
lastName: {
9-
type: String,
10-
required: true
11-
},
12-
email: {
13-
type: String,
14-
required: true
15-
},
16-
password: {
17-
type: String,
18-
required: true
19-
},
20-
status: {
21-
type: Boolean,
22-
required: true,
23-
default: 1,
24-
}
4+
firstName: {type: String, required: true},
5+
lastName: {type: String, required: true},
6+
email: {type: String, required: true},
7+
password: {type: String, required: true},
8+
status: {type: Boolean, required: true, default: 1}
259
}, {timestamps: true});
2610

2711
// Virtual for user's full name

package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"express-jwt": "^5.3.1",
1616
"express-validator": "^6.1.1",
1717
"jsonwebtoken": "^8.5.1",
18+
"moment": "^2.24.0",
1819
"mongoose": "^5.6.6",
1920
"morgan": "~1.9.0"
2021
},

routes/api.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
var express = require('express');
22
var usersRouter = require('./users');
33
var authRouter = require('./auth');
4+
var bookRouter = require('./book');
45

56
var app = express();
67

78
app.use('/users/', usersRouter);
89
app.use('/auth/', authRouter);
10+
app.use('/book/', bookRouter);
911

1012
module.exports = app;

0 commit comments

Comments
 (0)