Skip to content

Instantly share code, notes, and snippets.

@encikpulasan
Last active August 8, 2024 07:07
Show Gist options
  • Save encikpulasan/4f8f01f5b4d9a21b2bbcf2be8895a15c to your computer and use it in GitHub Desktop.
Save encikpulasan/4f8f01f5b4d9a21b2bbcf2be8895a15c to your computer and use it in GitHub Desktop.
Procurement API using Express JS
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