Last active
August 8, 2024 07:07
-
-
Save encikpulasan/4f8f01f5b4d9a21b2bbcf2be8895a15c to your computer and use it in GitHub Desktop.
Procurement API using Express JS
This file contains hidden or 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
const express = require("express"); | |
const fs = require("fs"); | |
const path = require("path"); | |
const multer = require("multer"); | |
const { v4: uuidv4 } = require("uuid"); | |
const bcrypt = require("bcrypt"); | |
const jwt = require("jsonwebtoken"); | |
const cors = require("cors"); | |
const app = express(); | |
const PORT = 3000; | |
const SECRET_KEY = "your-secret-key"; | |
app.use(express.json()); | |
app.use(cors()); | |
app.use("/uploads", express.static("uploads")); | |
// Set up multer for file uploads | |
const storage = multer.diskStorage({ | |
destination: (req, file, cb) => { | |
cb(null, "uploads/"); | |
}, | |
filename: (req, file, cb) => { | |
cb(null, Date.now() + path.extname(file.originalname)); | |
}, | |
}); | |
const upload = multer({ storage: storage }); | |
// Load data from JSON files | |
let procurements = []; | |
let users = []; | |
let projects = []; | |
const dataPath = "procurements.json"; | |
const usersPath = "users.json"; | |
const projectsPath = "projects.json"; | |
if (fs.existsSync(dataPath)) { | |
const data = fs.readFileSync(dataPath, "utf8"); | |
procurements = JSON.parse(data); | |
} | |
if (fs.existsSync(usersPath)) { | |
const data = fs.readFileSync(usersPath, "utf8"); | |
users = JSON.parse(data); | |
} | |
if (fs.existsSync(projectsPath)) { | |
const data = fs.readFileSync(projectsPath, "utf8"); | |
projects = JSON.parse(data); | |
} | |
// Helper functions to save data to JSON files | |
const saveProcurements = () => { | |
fs.writeFileSync(dataPath, JSON.stringify(procurements, null, 2)); | |
}; | |
const saveUsers = () => { | |
fs.writeFileSync(usersPath, JSON.stringify(users, null, 2)); | |
}; | |
const saveProjects = () => { | |
fs.writeFileSync(projectsPath, JSON.stringify(projects, null, 2)); | |
}; | |
// Middleware for authentication | |
const authenticateToken = (req, res, next) => { | |
const authHeader = req.headers["authorization"]; | |
const token = authHeader && authHeader.split(" ")[1]; | |
if (token == null) return res.sendStatus(401); | |
jwt.verify(token, SECRET_KEY, (err, user) => { | |
if (err) return res.sendStatus(403); | |
req.user = user; | |
next(); | |
}); | |
}; | |
// User registration | |
app.post("/register", async (req, res) => { | |
try { | |
const { email, password, userType } = req.body; | |
if (users.find((u) => u.email === email)) { | |
return res.status(400).json({ message: "User already exists" }); | |
} | |
const hashedPassword = await bcrypt.hash(password, 10); | |
const newUser = { | |
id: uuidv4(), | |
email, | |
password: hashedPassword, | |
userType, | |
}; | |
users.push(newUser); | |
saveUsers(); | |
res.status(201).json({ message: "User created successfully" }); | |
} catch (error) { | |
res.status(500).json({ message: "Error registering user" }); | |
} | |
}); | |
// User login | |
app.post("/login", async (req, res) => { | |
const { email, password } = req.body; | |
const user = users.find((u) => u.email === email); | |
if (user == null) { | |
return res.status(400).json({ message: "Cannot find user" }); | |
} | |
try { | |
if (await bcrypt.compare(password, user.password)) { | |
const accessToken = jwt.sign( | |
{ id: user.id, email: user.email, userType: user.userType }, | |
SECRET_KEY, | |
{ | |
expiresIn: "1h", | |
} | |
); | |
res.json({ accessToken: accessToken }); | |
} else { | |
res.status(401).json({ message: "Invalid credentials" }); | |
} | |
} catch (error) { | |
res.status(500).json({ message: "Error logging in" }); | |
} | |
}); | |
// Create a new project (client only) | |
app.post("/projects", authenticateToken, (req, res) => { | |
if (req.user.userType !== "client") { | |
return res | |
.status(403) | |
.json({ message: "Only clients can create projects" }); | |
} | |
const { name, description } = req.body; | |
const newProject = { | |
id: uuidv4(), | |
name, | |
description, | |
clientId: req.user.id, | |
createdAt: new Date().toISOString(), | |
}; | |
projects.push(newProject); | |
saveProjects(); | |
res.status(201).json(newProject); | |
}); | |
// Get all projects (client only) | |
app.get("/projects", authenticateToken, (req, res) => { | |
if (req.user.userType !== "client") { | |
return res | |
.status(403) | |
.json({ message: "Only clients can view all projects" }); | |
} | |
const clientProjects = projects.filter((p) => p.clientId === req.user.id); | |
res.json(clientProjects); | |
}); | |
// CREATE - Add a new procurement (vendor only) | |
app.post( | |
"/procurements", | |
authenticateToken, | |
upload.single("pdf"), | |
(req, res) => { | |
if (req.user.userType !== "vendor") { | |
return res | |
.status(403) | |
.json({ message: "Only vendors can submit procurements" }); | |
} | |
const { title, description, amount, projectId } = req.body; | |
const newProcurement = { | |
id: uuidv4(), | |
title, | |
description, | |
amount: parseFloat(amount), | |
pdfPath: req.file ? req.file.path : null, | |
createdAt: new Date().toISOString(), | |
vendorId: req.user.id, | |
projectId, | |
comments: [], | |
}; | |
procurements.push(newProcurement); | |
saveProcurements(); | |
res.status(201).json(newProcurement); | |
} | |
); | |
// READ - Get all procurements for a project (client only) | |
app.get("/projects/:projectId/procurements", authenticateToken, (req, res) => { | |
if (req.user.userType !== "client") { | |
return res.status(403).json({ | |
message: "Only clients can view all procurements for a project", | |
}); | |
} | |
const projectProcurements = procurements.filter( | |
(p) => p.projectId === req.params.projectId | |
); | |
res.json(projectProcurements); | |
}); | |
// READ - Get vendor's own procurements | |
app.get("/vendor/procurements", authenticateToken, (req, res) => { | |
if (req.user.userType !== "vendor") { | |
return res | |
.status(403) | |
.json({ message: "Only vendors can view their own procurements" }); | |
} | |
const vendorProcurements = procurements.filter( | |
(p) => p.vendorId === req.user.id | |
); | |
res.json(vendorProcurements); | |
}); | |
// UPDATE - Update a procurement (vendor only) | |
app.put( | |
"/procurements/:id", | |
authenticateToken, | |
upload.single("pdf"), | |
(req, res) => { | |
if (req.user.userType !== "vendor") { | |
return res | |
.status(403) | |
.json({ message: "Only vendors can update procurements" }); | |
} | |
const index = procurements.findIndex( | |
(p) => p.id === req.params.id && p.vendorId === req.user.id | |
); | |
if (index !== -1) { | |
const { title, description, amount } = req.body; | |
procurements[index] = { | |
...procurements[index], | |
title: title || procurements[index].title, | |
description: description || procurements[index].description, | |
amount: amount ? parseFloat(amount) : procurements[index].amount, | |
pdfPath: req.file ? req.file.path : procurements[index].pdfPath, | |
updatedAt: new Date().toISOString(), | |
}; | |
saveProcurements(); | |
res.json(procurements[index]); | |
} else { | |
res.status(404).json({ | |
message: | |
"Procurement not found or you do not have permission to edit it", | |
}); | |
} | |
} | |
); | |
// SEARCH - Search procurements (client only) | |
app.get("/procurements/search", authenticateToken, (req, res) => { | |
if (req.user.userType !== "client") { | |
return res | |
.status(403) | |
.json({ message: "Only clients can search procurements" }); | |
} | |
const { query, companyName, projectName, status } = req.query; | |
let results = procurements; | |
if (query) { | |
results = results.filter( | |
(p) => | |
p.title.toLowerCase().includes(query.toLowerCase()) || | |
p.description.toLowerCase().includes(query.toLowerCase()) | |
); | |
} | |
if (companyName) { | |
const vendor = users.find( | |
(u) => | |
u.userType === "vendor" && | |
u.companyName.toLowerCase() === companyName.toLowerCase() | |
); | |
if (vendor) { | |
results = results.filter((p) => p.vendorId === vendor.id); | |
} | |
} | |
if (projectName) { | |
const project = projects.find( | |
(p) => p.name.toLowerCase() === projectName.toLowerCase() | |
); | |
if (project) { | |
results = results.filter((p) => p.projectId === project.id); | |
} | |
} | |
if (status === "available") { | |
results = results.filter((p) => !p.awarded); | |
} | |
res.json(results); | |
}); | |
// Add comment to procurement (client only) | |
app.post("/procurements/:id/comments", authenticateToken, (req, res) => { | |
if (req.user.userType !== "client") { | |
return res.status(403).json({ message: "Only clients can add comments" }); | |
} | |
const index = procurements.findIndex((p) => p.id === req.params.id); | |
if (index !== -1) { | |
const { text } = req.body; | |
const newComment = { | |
id: uuidv4(), | |
text, | |
createdAt: new Date().toISOString(), | |
clientId: req.user.id, | |
}; | |
procurements[index].comments.push(newComment); | |
saveProcurements(); | |
res.status(201).json(newComment); | |
} else { | |
res.status(404).json({ message: "Procurement not found" }); | |
} | |
}); | |
app.listen(PORT, () => { | |
console.log(`Server is running on port ${PORT}`); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment