diff --git a/.gitignore b/.gitignore index f14cc4d..4b3d9eb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ node_modules -package-lock.json \ No newline at end of file +package-lock.json + +.env \ No newline at end of file diff --git a/README.md b/README.md index 0213848..2a7b253 100644 --- a/README.md +++ b/README.md @@ -48,4 +48,22 @@ npm init npm i express npm i nodemon --save-dev -npm run dev \ No newline at end of file +npm run dev + +npm i mongoose + +mongodb+srv://advaitsreekumar:@cluster0.sqitt49.mongodb.net/?appName=Cluster0 + + + +mongodb+srv://advaitsreekumar:@cluster0.sqitt49.mongodb.net/?appName=Cluster0 + +npm i dotenv + + +## MVC architecture + >> M: Model (structure of our MongoDb) + >> V: View (Frontend) + >> C: Controller (Brain/Logic of a route) + +## DTO(Data Transfer Object) \ No newline at end of file diff --git a/controllers/book-controller.js b/controllers/book-controller.js new file mode 100644 index 0000000..e162a5a --- /dev/null +++ b/controllers/book-controller.js @@ -0,0 +1,144 @@ +const {BookModel, UserModel} = require("../models") +const IssuedBook = require("../dto/book-dto"); + +// const getAllBooks = ()=>{ + +// } + +// const getSingleBookById = ()=>{ + +// } + + + + +// module.exports= { +// getAllBooks, +// getSingleBookById +// } + + + +exports.getAllBooks = async(req,res)=>{ + const books= await BookModel.find() + + if(books.length===0){ + return res.status.json({ + success:false, + message: "No books in the system" + }) + } + res.status(200).json({ + success:true, + data:books + }) +} + +exports.getSingleBookById = async(req,res)=>{ + const {id} =req.params; + const book = await BookModel.findById(id); + + if(!book){ + return res.status(404).json({ + success:false, + message:"Book not found" + }) + } + + res.status(200).json({ + success:true, + data:book + }) +} + + +exports.getAllIssuedBooks = async(req,res)=>{ + const users = await BookModel.find({ + issuedBook:{$exists:true} + }).populate("issuedBook") + + const issuedBook= users.map((each)=>{ + return new issuedBook(each); + }); + + if(issuedBook.length===0){ + return res.status(404).json({ + success:false, + message:"No issued books found" + }) + } + res.status(200).json({ + success:true, + data:issuedBook + }) +} + +exports.addNewBook = async(req,res)=>{ + const {data}= req.body; + + if(!data || Object.keys(data).length===0){ + return res.status(404).json({ + success:false, + message:"Data not recieved" + }) + } + + await BookModel.create(data); + + const allBooks= await BookModel.find(); + res.status(201).json({ + success:true, + message:"Book added", + data:allBooks + }) +} + +exports.updateOneBook= async(req,res)=>{ + const {id}= req.params; + const {data}= req.body; + + if(!data || Object.keys(data).length===0){ + return res.status(404).json({ + success:false, + message:"Data not recieved" + }) + } + + const updatedBook = await BookModel.findOneAndUpdate( + {_id:id}, + data, + {new:true} + ); + + if(!updatedBook){ + return res.status(404).json({ + success:false, + message: `Book not found for id: ${id}` + }) + } + + res.status(200).json({ + success: true, + message : "Book updated successfully", + data: updatedBook + }) +} + + +exports.deleteBookById = async(req,res)=>{ + const {id}= req.params; + + const book= await BookModel.findById(id); + if(!book){ + return res.status(404).json({ + success: false, + message: " Book not found at id" + }) + } + + await BookModel.findByIdAndDelete(id); + res.status(200).json({ + success: true, + message : "Book deleted successfully" + }) +} \ No newline at end of file diff --git a/controllers/user-controller.js b/controllers/user-controller.js new file mode 100644 index 0000000..189519a --- /dev/null +++ b/controllers/user-controller.js @@ -0,0 +1,146 @@ +const {BookModel, UserModel} = require("../models") +const { find } = require("../models/user-model") + + +exports.getAllUsers = async(req,res)=>{ + const books = await UserModel.find(); + + if(books.length===0){ + res.status(400).json({ + success: true, + message:"No users in the database" + }) + } +} + +exports.getUserById = async(req,res)=>{ + const {id}= req.params; + + const user = await UserModel.findById(id); + if(user.length===0){ + return res.status(400).json({ + success: false, + message:"No such user" + }) + } + + res.status(200).json({ + success: true, + message:" User added succesfully" + }) +} + +exports.addNewUser = async(req,res)=>{ + const {data} = req.body; + + if(!data || Object.keys(data).length===0){ + res.status(404).json({ + success:true, + message:"Please give all the required data" + }) + } + + await UserModel.create(data); + res.status(200).json({ + success: true, + message: " User added successfully", + data:data + }) +} + +exports.updateUserById= async(req,res)=>{ + const {id}= req.params; + const {data}= req.body; + + if(!data || Object.keys(data).length===0){ + res.status(404).json({ + success:true, + message:"Please give all the required data for updating" + }) + } + + const updatedUser= await UserModel.findByIdAndUpdate(id,data,{new:true}) + + if(!updatedUser){ + return res.status(400).json({ + success:false, + message:"Please provide details" + }) + } + + res.status(200).json({ + success:true, + message:"User updated", + data: updatedUser + }) +} + +exports.deleteUserById = async(req,res)=>{ + const {id}= req.params; + + const user= UserModel.findById(id); + + if(!user){ + return res.status(404).json({ + success:false, + message:"No such user" + }) + } + res.status(200).json({ + success: true, + message:"User deleted" + }) +} + +exports.subscriptionDetailsById = async(req,res)=>{ + const {id}= req.params; + + const user= UserModel.findById(id); + + if(!user){ + return res.status(404).json({ + success:false, + message:"No such user" + }) + } + const getDateInDays=(data= '')=>{ + let date; + if(data){ + date = new Date(data); + }else{ + date= new Date(); + } + let days= Math.floor(date/(1000*60*60*24)); + return days; + } + + const subscriptionType= (date)=>{ + if(user.subscriptionType==="Basic"){ + date= date+90; + }else if(user.subscriptionType==="Standard"){ + date=date+180 + }else if(user.subscriptionType==="Premium"){ + date+=365 + } + return date; + } + + let returnDate= getDateInDays(user.returnDate); + let currentDate= getDateInDays(); + let subscriptionDate= getDateInDays(user.subscriptionDate); + let subscriptionExpiration= subscriptionType(subscriptionDate) + + const data={ + ...user, + subscriptionExpired: subscriptionExpiration < currentDate, + subscriptionDaysLeft: subscriptionExpiration-currentDate, + daysLeftForExpiration: returnDate - currentDate ? "Book is overdue" : returnDate, + fine: returnDate< currentDate ? subscriptionExpiration <= currentDate ?200 :100: 0 + } + + res.status(200).json({ + success:true, + data:data + }); + +} \ No newline at end of file diff --git a/dataBaseConnection.js b/dataBaseConnection.js new file mode 100644 index 0000000..33ebcd5 --- /dev/null +++ b/dataBaseConnection.js @@ -0,0 +1,20 @@ +const mongoose = require("mongoose"); + +function DbConnection() { + const DB_URL = process.env.MONGO_URI; + + // FIX: Remove the options object entirely. + // Modern Mongoose handles newUrlParser and unifiedTopology by default. + mongoose.connect(DB_URL); + + const db = mongoose.connection; + + // Optional: Fixed typo "Erro" to "Error" + db.on("error", console.error.bind(console, "Connection Error")); + + db.once("open", () => { + console.log('DB connected'); + }); +} + +module.exports = DbConnection; \ No newline at end of file diff --git a/dto/book-dto.js b/dto/book-dto.js new file mode 100644 index 0000000..7235d60 --- /dev/null +++ b/dto/book-dto.js @@ -0,0 +1,17 @@ +class issuedBook{ + _id; + name; + price; + author; + + constructor(user){ + this._id = user.issuedBook._id; + this.name = user.issuedBook.name; + this.price = user.issuedBook.price; + this.author = user.issuedBook.author; + this.issuedBy = user.name; + this.issuedDate = user.issuedDate; + this.returnDate = user.returnDate; + + } +} \ No newline at end of file diff --git a/index.js b/index.js index 4ce17d4..3721df9 100644 --- a/index.js +++ b/index.js @@ -1,12 +1,22 @@ const express=require("express"); -const {users}=require("./data/users.json") +// const {users}=require("./data/users.json") +const dotenv= require("dotenv") + + + + +//import database connection +const DbConnection = require('./dataBaseConnection.js') const userRoutes=require('./routes/users.js') const booksRoutes=require('./routes/books.js') +dotenv.config(); + const app=express(); +DbConnection(); const PORT=8081; app.use(express.json()); diff --git a/models/book-model.js b/models/book-model.js new file mode 100644 index 0000000..4d7f22c --- /dev/null +++ b/models/book-model.js @@ -0,0 +1,21 @@ +const mongoose = require("mongoose") + +const Schema=mongoose.Schema; + +const bookSchema= new Schema({ + name:{ + type: String, + required: true + }, + price:{ + type: String, + required: true + }, + author:{ + type: String, + required: true + } + +},{timestamps:true}) + +module.exports=mongoose.model("Book",bookSchema) \ No newline at end of file diff --git a/models/index.js b/models/index.js new file mode 100644 index 0000000..ec1c63c --- /dev/null +++ b/models/index.js @@ -0,0 +1,7 @@ +const UserModel= require("./user-model"); +const BookModel= require("./book-model"); + +module.exports = { + UserModel, + BookModel +} \ No newline at end of file diff --git a/models/user-model.js b/models/user-model.js new file mode 100644 index 0000000..d1c94f4 --- /dev/null +++ b/models/user-model.js @@ -0,0 +1,37 @@ +const mongoose= require("mongoose") + +const Schema= mongoose.Schema; + +const userSchema= new Schema({ + name:{ + type: String, + required: true + }, + email:{ + type: String, + required: true + }, + issuedBook:{ + type: mongoose.Schema.Types.ObjectId, + ref:"Book", + required: false + }, + issuedDate:{ + type: String, + required: false + }, + returnDate:{ + type: String, + required: false + }, + subscriptionType:{ + type: String, + required: true + }, + subscriptionDate:{ + type: String, + required: true + }, +},{timestamps:true}) + +module.exports= mongoose.model("User",userSchema) \ No newline at end of file diff --git a/package.json b/package.json index c5dc6f3..17dcae3 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "This is a library management API backend fro the mangement of user and books", "main": "index.js", "scripts": { - "start":"node index.js", - "dev":"nodemon index.js" + "start": "node index.js", + "dev": "nodemon index.js" }, "repository": { "type": "git", @@ -18,7 +18,10 @@ }, "homepage": "https://github.com/Advait-Sreekumar/library-management#readme", "dependencies": { + "dotenv": "^17.2.3", "express": "^5.2.1", + "mongodb": "^7.0.0", + "mongoose": "^9.1.5", "nodemon": "^3.1.11" } } diff --git a/routes/books.js b/routes/books.js index d73ffb8..d67f1a0 100644 --- a/routes/books.js +++ b/routes/books.js @@ -2,6 +2,10 @@ const express=require("express"); const {books}=require("../data/books.json") const {users}= require("../data/users.json"); +const {UserModel, BookModel} = require("../models/index") +const {getAllBooks, getSingleBookById, getAllIssuedBooks,addNewBook, updateOneBook, deleteBookById} = require("../controllers/book-controller") + + const router =express.Router(); @@ -12,44 +16,50 @@ const router =express.Router(); * Access:Public * Parameters:None */ -router.get('/',(req,res)=>{ - res.status(200).json({ - success: true, - data:books, - }) -}) - - -router.post('/',(req,res)=>{ - // "id":"1", - // "name":"BBT", - // "price":"300", - // "author":"Ram" - const {id,name,price,author}= req.body; - if(!id || !name || !price || !author){ - return res.status(400).json({ - success: false, - message:"Please provide all the details" - }) - } - const book =books.find((each)=>each.id ===id) - if(book){ - res.status(409).json({ - success:false, - message:"Books already exists" - }) - } - books.push({ - id, - name, - price, - author - - }) - res.status(201).json({ - success:"Book created successfully" - }) -}) +// router.get('/',(req,res)=>{ +// res.status(200).json({ +// success: true, +// data:books, +// }) +// }) + +router.get('/',getAllBooks) + + + + +// router.post('/',(req,res)=>{ +// // "id":"1", +// // "name":"BBT", +// // "price":"300", +// // "author":"Ram" +// const {id,name,price,author}= req.body; +// if(!id || !name || !price || !author){ +// return res.status(400).json({ +// success: false, +// message:"Please provide all the details" +// }) +// } +// const book =books.find((each)=>each.id ===id) +// if(book){ +// res.status(409).json({ +// success:false, +// message:"Books already exists" +// }) +// } +// books.push({ +// id, +// name, +// price, +// author + +// }) +// res.status(201).json({ +// success:"Book created successfully" +// }) +// }) + +router.post('/',addNewBook) /** @@ -59,52 +69,28 @@ router.post('/',(req,res)=>{ * Access:Public * Parameters:None */ -router.put('/:id',(req,res)=>{ - const {id}=req.params; - const {data}=req.body; - const book =books.find((each)=>each.id === id) - - if(!book){ - return res.status(404).json({ - success:false, - message:"Book not found" - }) - } - - const updatedBook= books.map((each)=>{ - if(each.id===id){ - return{ - ...each, - ...data, - } - } - return each - }) - res.status(201).json({ - success:true, - data:updatedBook, - message:"Updated successfully" - }) -}) - - -router.get('/:id',(req,res)=>{ +router.put('/:id',updateOneBook) + + +// router.get('/:id',(req,res)=>{ - const {id}=req.params; - const book =books.find((each)=>each.id === id) +// const {id}=req.params; +// const book =books.find((each)=>each.id === id) - if(!book){ - return res.status(404).json({ - success:false, - message:"Book not found" - }) - } - - res.status(200).json({ - success:true, - data:book - }) -}) +// if(!book){ +// return res.status(404).json({ +// success:false, +// message:"Book not found" +// }) +// } + +// res.status(200).json({ +// success:true, +// data:book +// }) +// }) + +router.get('/:id',getSingleBookById) /** * Route:/books: ID @@ -113,26 +99,7 @@ router.get('/:id',(req,res)=>{ * Access:Public * Parameters:None */ -router.delete('/:id',(req,res)=>{ - const {id}= req.params; - const book=books.find((each)=>each.id===id) - - if(!book){ - return res.status(404).json({ - success:false, - message:"Id not found in system" - }) - } - const updatedBook=books.filter((each)=>each.id!==id); - - - res.status(200).json({ - success:true, - data:updatedBook, - message:"Id has been deleted" - }) - -}) +router.delete('/:id',deleteBookById) /** * Route:/issued @@ -142,44 +109,7 @@ router.delete('/:id',(req,res)=>{ * Parameters:None */ -router.get('/issued/for-user',(req,res)=>{ - const UserWithIssuedBooks=users.filter((each)=>{ - if(each.issuedBook){ - return each; - } - }) - - const issuedBooks=[]; - - UserWithIssuedBooks.forEach((each)=>{ - const book =books.find((book)=> book.id ===each.issuedBook); - - if(book){ - const bookWithUser ={ - ...book, - issuedBy :each.name, - issuedDate : each.issuedDate, - returnDate :each.returnDate, - }; - issuedBooks.push(bookWithUser); - } - }); - - - if(!issuedBooks.length===0){ - return res.status(404).json({ - success:false, - message: " No books issued yet" - }); - } - - res.status(200).json({ - success:true, - data:issuedBooks - }); - -}); - +router.get('/issued/for-user',getAllIssuedBooks); module.exports= router; \ No newline at end of file diff --git a/routes/users.js b/routes/users.js index b5a79ec..cc47efe 100644 --- a/routes/users.js +++ b/routes/users.js @@ -1,5 +1,10 @@ const express = require("express"); -const {users}= require("../data/users.json") +const {users}= require("../data/users.json"); + + + +const {UserModel,Bookmodel}= require("../models"); +const {getAllUsers, getUserById, addNewUser, updateUserById, deleteUserById, subscriptionDetailsById}= require("../controllers/user-controller") const router = express.Router(); @@ -11,13 +16,14 @@ const router = express.Router(); * Access:Public * Parameters:None */ -router.get('/',(req,res)=>{ - res.status(200).json({ - success: true, - data:users, - }) -}) +// router.get('/',(req,res)=>{ +// res.status(200).json({ +// success: true, +// data:users, +// }) +// }) +router.get('/',getAllUsers) /** * Route:/users @@ -26,39 +32,40 @@ router.get('/',(req,res)=>{ * Access:Public * Parameters:None */ -router.post('/',(req,res)=>{ - // "id": 4, - // "name": "Rakesh", - // "email": "rakesh@example.com" - // "subscriptionType":"Standard", - // "subscriptionDate":"05/08/2022" - const {id,name,email,subscriptionType,subscriptionDate}= req.body; - if(!id || !name || !email || !subscriptionType || !subscriptionDate ){ - return res.status(400).json({ - success: false, - message:"Please provide all the details" - }) - } - const user=users.find((each)=>each.id ===id) - if(user){ - res.status(409).json({ - success:false, - message:"User already exists" - }) - } - users.push({ - id, - name, - email, - subscriptionType, - subscriptionDate - - }) - res.status(201).json({ - success:true, - message:"User created successfully" - }) -}) +// router.post('/',(req,res)=>{ +// // "id": 4, +// // "name": "Rakesh", +// // "email": "rakesh@example.com" +// // "subscriptionType":"Standard", +// // "subscriptionDate":"05/08/2022" +// const {id,name,email,subscriptionType,subscriptionDate}= req.body; +// if(!id || !name || !email || !subscriptionType || !subscriptionDate ){ +// return res.status(400).json({ +// success: false, +// message:"Please provide all the details" +// }) +// } +// const user=users.find((each)=>each.id ===id) +// if(user){ +// res.status(409).json({ +// success:false, +// message:"User already exists" +// }) +// } +// users.push({ +// id, +// name, +// email, +// subscriptionType, +// subscriptionDate + +// }) +// res.status(201).json({ +// success:true, +// message:"User created successfully" +// }) +// }) +router.post('/',addNewUser) /** * Route:/users: ID @@ -67,33 +74,35 @@ router.post('/',(req,res)=>{ * Access:Public * Parameters:None */ -router.put('/:id',(req,res)=>{ - const {id}=req.params; - const {data}=req.body; - const user =users.find((each)=>each.id === Number(id)) +// router.put('/:id',(req,res)=>{ +// const {id}=req.params; +// const {data}=req.body; +// const user =users.find((each)=>each.id === Number(id)) - if(!user){ - return res.status(404).json({ - success:false, - message:"User not found" - }) - } - - const updatedUser= users.map((each)=>{ - if(each.id===Number(id)){ - return{ - ...each, - ...data, - } - } - return each - }) - res.status(201).json({ - success:true, - data:updatedUser, - message:"Updated successfully" - }) -}) +// if(!user){ +// return res.status(404).json({ +// success:false, +// message:"User not found" +// }) +// } + +// const updatedUser= users.map((each)=>{ +// if(each.id===Number(id)){ +// return{ +// ...each, +// ...data, +// } +// } +// return each +// }) +// res.status(201).json({ +// success:true, +// data:updatedUser, +// message:"Updated successfully" +// }) +// }) + +router.put('/:id',updateUserById) /** @@ -103,23 +112,25 @@ router.put('/:id',(req,res)=>{ * Access:Public * Parameters:None */ -router.get('/:id',(req,res)=>{ +// router.get('/:id',(req,res)=>{ - const {id}=req.params; - const user =users.find((each)=>each.id === Number(id)) +// const {id}=req.params; +// const user =users.find((each)=>each.id === Number(id)) - if(!user){ - return res.status(404).json({ - success:false, - message:"User not found" - }) - } +// if(!user){ +// return res.status(404).json({ +// success:false, +// message:"User not found" +// }) +// } - res.status(200).json({ - success:true, - data:user - }) -}) +// res.status(200).json({ +// success:true, +// data:user +// }) +// }) + +router.get('/:id',getUserById); @@ -131,26 +142,28 @@ router.get('/:id',(req,res)=>{ * Access:Public * Parameters:None */ -router.delete('/:id',(req,res)=>{ - const {id}= req.params; - const user=users.find((each)=>each.id===Number(id)) +// router.delete('/:id',(req,res)=>{ +// const {id}= req.params; +// const user=users.find((each)=>each.id===Number(id)) + +// if(!user){ +// return res.status(404).json({ +// success:false, +// message:"Id not found in system" +// }) +// } +// const updatedUser=users.filter((each)=>each.id!==Number(id)); - if(!user){ - return res.status(404).json({ - success:false, - message:"Id not found in system" - }) - } - const updatedUser=users.filter((each)=>each.id!==Number(id)); +// res.status(200).json({ +// success:true, +// data:updatedUser, +// message:"Id has been deleted" +// }) - res.status(200).json({ - success:true, - data:updatedUser, - message:"Id has been deleted" - }) +// }) -}) +router.delete('/:id',deleteUserById) /** @@ -160,56 +173,58 @@ router.delete('/:id',(req,res)=>{ * Access:Public * Parameters:None */ -router.get('/subscription-details/:id',(req,res)=>{ - const {id}=req.params; - const user = users.find((each) => each.id === Number(id)); - - if(!user){ - return res.status(404).json({ - success:false, - message:"No such user in the database" - }) - } - - const getDateInDays=(data= '')=>{ - let date; - if(data){ - date = new Date(data); - }else{ - date= new Date(); - } - let days= Math.floor(date/(1000*60*60*24)); - return days; - } - - const subscriptionType= (date)=>{ - if(user.subscriptionType==="Basic"){ - date= date+90; - }else if(user.subscriptionType==="Standard"){ - date=date+180 - }else if(user.subscriptionType==="Premium"){ - date+=365 - } - return date; - } - - let returnDate= getDateInDays(user.returnDate); - let currentDate= getDateInDays(); - let subscriptionDate= getDateInDays(user.subscriptionDate); - let subscriptionExpiration= subscriptionType(subscriptionDate) - - const data={ - ...user, - subscriptionExpired: subscriptionExpiration < currentDate, - subscriptionDaysLeft: subscriptionExpiration-currentDate, - daysLeftForExpiration: returnDate - currentDate ? "Book is overdue" : returnDate, - fine: returnDate< currentDate ? subscriptionExpiration <= currentDate ?200 :100: 0 - } - - res.status(200).json({ - success:true, - data:data - }); -}) +// router.get('/subscription-details/:id',(req,res)=>{ +// const {id}=req.params; +// const user = users.find((each) => each.id === Number(id)); + +// if(!user){ +// return res.status(404).json({ +// success:false, +// message:"No such user in the database" +// }) +// } + +// const getDateInDays=(data= '')=>{ +// let date; +// if(data){ +// date = new Date(data); +// }else{ +// date= new Date(); +// } +// let days= Math.floor(date/(1000*60*60*24)); +// return days; +// } + +// const subscriptionType= (date)=>{ +// if(user.subscriptionType==="Basic"){ +// date= date+90; +// }else if(user.subscriptionType==="Standard"){ +// date=date+180 +// }else if(user.subscriptionType==="Premium"){ +// date+=365 +// } +// return date; +// } + +// let returnDate= getDateInDays(user.returnDate); +// let currentDate= getDateInDays(); +// let subscriptionDate= getDateInDays(user.subscriptionDate); +// let subscriptionExpiration= subscriptionType(subscriptionDate) + +// const data={ +// ...user, +// subscriptionExpired: subscriptionExpiration < currentDate, +// subscriptionDaysLeft: subscriptionExpiration-currentDate, +// daysLeftForExpiration: returnDate - currentDate ? "Book is overdue" : returnDate, +// fine: returnDate< currentDate ? subscriptionExpiration <= currentDate ?200 :100: 0 +// } + +// res.status(200).json({ +// success:true, +// data:data +// }); +// }) +router.get('/subscription-details/:id',subscriptionDetailsById) + module.exports= router; \ No newline at end of file