Skip to content

Commit 40f3bfa

Browse files
authored
Merge pull request #15 from L1ghtRay/MC
Sree <- MC
2 parents cea8bfa + a126a7f commit 40f3bfa

12 files changed

Lines changed: 685 additions & 611 deletions

File tree

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import User from "../models/users.js";
2+
import {
3+
generateAccessToken,
4+
generateRefreshToken,
5+
} from "../middleware/verify.js";
6+
7+
export const refreshToken = async (req, res) => {
8+
try {
9+
const refreshToken = req.cookies.refreshToken;
10+
11+
if (!refreshToken) {
12+
return res.status(401).json({ message: "No refresh token" });
13+
}
14+
15+
const decoded = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET);
16+
const user = await User.findById(decoded.id);
17+
18+
if (!user) {
19+
return res.status(401).json({ message: "User not found" });
20+
}
21+
22+
const newAccessToken = generateAccessToken(user);
23+
const newrefreshToken = generateRefreshToken(user);
24+
25+
res.cookie("refreshToken", newrefreshToken, {
26+
httpOnly: true,
27+
secure: process.env.NODE_ENV === "production",
28+
sameSite: process.env.NODE_ENV === "production" ? "none" : "lax",
29+
maxAge: 7 * 24 * 60 * 60 * 1000,
30+
});
31+
32+
res.json({ accessToken: newAccessToken });
33+
} catch (error) {
34+
console.error("Refresh token error:", error);
35+
res.status(401).json({ message: "Invalid refresh token" });
36+
}
37+
};
38+
39+
export const getRole = async (req, res) => {
40+
try {
41+
const user = await User.findById(req.user.id);
42+
43+
if (!user) {
44+
return res.status(404).json({ message: "User not found" });
45+
}
46+
47+
res.json({
48+
user: {
49+
id: user._id,
50+
name: user.name,
51+
displayName: user.displayName,
52+
email: user.email,
53+
profile: user.profile,
54+
role: user.role,
55+
setupComplete: user.setupComplete,
56+
phone: user.phone,
57+
address: user.address,
58+
},
59+
});
60+
} catch (error) {
61+
console.error("Get role error:", error);
62+
res.status(401).json({ message: "Invalid token" });
63+
}
64+
};

backend/controllers/donationcontroller.js

Lines changed: 35 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,18 @@
1-
/*
2-
1. Since no categories are assigned in the db yet the category search cannot be performed
3-
2. Also commented the the res.user since validation is not yet started we cannot use that
4-
3. Since no category id is present i added random category id
5-
*/
61
import Category from "../models/categories.js";
72
import Item from "../models/items.js";
8-
import User from "../models/users.js"
3+
import User from "../models/users.js";
94

105
export const donateItem = async (req, res) => {
116
try {
127
console.log("req.body:", req.body);
138
console.log("req.files:", req.files);
149

15-
if (!req.user) {
16-
return res.status(401).json({
17-
error: "Unauthorized",
18-
message: "User not authenticated",
19-
});
20-
}
21-
10+
if (!req.user) {
11+
return res.status(401).json({
12+
error: "Unauthorized",
13+
message: "User not authenticated",
14+
});
15+
}
2216

2317
const {
2418
itemTitle,
@@ -34,15 +28,10 @@ export const donateItem = async (req, res) => {
3428
contactMethods,
3529
} = req.body;
3630

37-
38-
39-
//increment points after a donation
4031
await User.findByIdAndUpdate(req.user._id, {
41-
$inc: { points: 10 }
42-
});
43-
32+
$inc: { points: 10 },
33+
});
4434

45-
// Validate required fields
4635
if (!itemTitle || !itemTitle.trim()) {
4736
return res.status(400).json({
4837
error: "Validation Error",
@@ -64,41 +53,17 @@ export const donateItem = async (req, res) => {
6453
});
6554
}
6655

67-
68-
// Find category document
6956
const categoryDoc = await Category.findOne({
70-
name: category.trim().replace(/\r?\n/g, " "),
71-
});
57+
name: category.trim().replace(/\r?\n/g, " "),
58+
});
7259

7360
if (!categoryDoc) {
74-
return res.status(400).json({
75-
error: "Invalid Category",
76-
message: "The selected category does not exist",
77-
});
78-
}
79-
80-
//Find Donor
81-
82-
83-
84-
// // Validate subcategory if provided
85-
// if (
86-
// subcategory &&
87-
// categoryDoc.subcategories &&
88-
// categoryDoc.subcategories.length > 0
89-
// ) {
90-
// const validSubcategory = categoryDoc.subcategories.includes(
91-
// subcategory.trim()
92-
// );
93-
// if (!validSubcategory) {
94-
// return res.status(400).json({
95-
// error: "Invalid Subcategory",
96-
// message: "The selected subcategory is not valid for this category",
97-
// });
98-
// }
99-
// }
100-
101-
// Parse and validate price if it's a paid donation
61+
return res.status(400).json({
62+
error: "Invalid Category",
63+
message: "The selected category does not exist",
64+
});
65+
}
66+
10267
let finalPrice = 0;
10368
if (isPaid === "yes" || isPaid === true) {
10469
finalPrice = parseFloat(price);
@@ -110,7 +75,6 @@ export const donateItem = async (req, res) => {
11075
}
11176
}
11277

113-
// Handle contact methods - ensure it's always an array
11478
let contactMethodsArray = [];
11579
if (contactMethods) {
11680
if (Array.isArray(contactMethods)) {
@@ -120,38 +84,32 @@ export const donateItem = async (req, res) => {
12084
}
12185
}
12286

87+
let finalDate = null;
88+
if (availableUntil) {
89+
finalDate = new Date(availableUntil);
90+
const today = new Date();
91+
today.setHours(0, 0, 0, 0);
12392

124-
//validating date
125-
// Validate availableUntil
126-
let finalDate = null;
127-
if (availableUntil) {
128-
finalDate = new Date(availableUntil);
129-
const today = new Date();
130-
today.setHours(0,0,0,0); // normalize to midnight
131-
132-
if (isNaN(finalDate.getTime())) {
133-
return res.status(400).json({
134-
error: "Validation Error",
135-
message: "Invalid date format for availableUntil"
136-
});
137-
}
138-
139-
if (finalDate < today) {
140-
return res.status(400).json({
141-
error: "Validation Error",
142-
message: "Available until date cannot be in the past"
143-
});
144-
}
145-
}
93+
if (isNaN(finalDate.getTime())) {
94+
return res.status(400).json({
95+
error: "Validation Error",
96+
message: "Invalid date format for availableUntil",
97+
});
98+
}
14699

100+
if (finalDate < today) {
101+
return res.status(400).json({
102+
error: "Validation Error",
103+
message: "Available until date cannot be in the past",
104+
});
105+
}
106+
}
147107

148-
// Handle image URLs // currently storing file paths, need to be changes to Urls when w store it in cloud
149108
const imageURLs =
150109
req.files && req.files.length > 0
151110
? req.files.map((f) => `/uploads/${f.filename}`)
152111
: [];
153112

154-
// Create the item
155113
const newItem = await Item.create({
156114
name: itemTitle.trim(),
157115
description: description ? description.trim() : "",
@@ -181,7 +139,6 @@ if (availableUntil) {
181139
} catch (err) {
182140
console.error("Donation error:", err);
183141

184-
// Handle mongoose validation errors
185142
if (err.name === "ValidationError") {
186143
const messages = Object.values(err.errors).map((e) => e.message);
187144
return res.status(400).json({
@@ -190,7 +147,6 @@ if (availableUntil) {
190147
});
191148
}
192149

193-
// Handle duplicate key errors
194150
if (err.code === 11000) {
195151
return res.status(400).json({
196152
error: "Duplicate Error",

backend/controllers/itemController.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import Item from "../models/items.js";
55
import Category from "../models/categories.js";
66

77
export const getSearchResults = async (req, res) => {
8-
const query = req.query.q; // e.g., "Stationery" or "baby doll"
8+
const query = req.query.q;
99

1010
if (!query) {
1111
return res.render("../frontend/views/listing.ejs", { items: [] });

backend/middleware/verify.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,36 @@ import jwt from "jsonwebtoken";
22
import dotenv from "dotenv";
33
dotenv.config();
44

5+
const generateAccessToken = (user) => {
6+
return jwt.sign(
7+
{
8+
id: user._id,
9+
email: user.email,
10+
role: user.role,
11+
},
12+
process.env.JWT_ACCESS_SECRET,
13+
{ expiresIn: "3h" }
14+
);
15+
};
16+
17+
const generateRefreshToken = (user) => {
18+
return jwt.sign({ id: user._id }, process.env.JWT_REFRESH_SECRET, {
19+
expiresIn: "7d",
20+
});
21+
};
22+
523
export function verifyToken(req, res, next) {
624
const authHeader = req.headers["authorization"];
725
const token = authHeader?.split(" ")[1];
826
if (!token) {
927
return res.status(401).json({ message: "Access token missing!" });
1028
}
11-
jwt.verify(token, process.env.JWT_SECRET, (err, payload) => {
29+
jwt.verify(token, process.env.JWT_ACCESS_SECRET, (err, payload) => {
1230
if (err) {
1331
return res.status(403).json({ message: "Invalid or expired token!" });
1432
}
1533
req.user = payload;
1634
next();
1735
});
1836
}
37+
export { generateAccessToken, generateRefreshToken };

backend/routes/authroutes.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import express from "express";
2+
import { verifyToken } from "../middleware/verify.js";
3+
import { refreshToken, getRole } from "../controllers/authController.js";
4+
const router = express.Router();
5+
6+
router.post("/refresh-token", refreshToken);
7+
8+
router.get("/get-role", verifyToken, getRole);
9+
10+
router.post("/logout", (req, res) => {
11+
res.clearCookie("refreshToken");
12+
req.logout((err) => {
13+
if (err) {
14+
console.error("Logout error:", err);
15+
}
16+
});
17+
res.json({ message: "Logged out successfully" });
18+
});
19+
20+
export default router;

backend/routes/donationroutes.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,11 @@ import { verifyToken } from "../middleware/verify.js";
1010
import { donateItem } from "../controllers/donationcontroller.js";
1111
const router = express.Router();
1212

13-
// Ensure uploads folder exists
1413
const uploadDir = path.join(process.cwd(), "uploads");
1514
if (!fs.existsSync(uploadDir)) {
1615
fs.mkdirSync(uploadDir, { recursive: true });
1716
}
1817

19-
// Multer storage config
2018
const storage = multer.diskStorage({
2119
destination: (req, file, cb) => {
2220
cb(null, uploadDir);
@@ -27,7 +25,6 @@ const storage = multer.diskStorage({
2725
},
2826
});
2927

30-
// File filter for images
3128
const fileFilter = (req, file, cb) => {
3229
if (file.mimetype.startsWith("image/")) {
3330
cb(null, true);
@@ -36,8 +33,10 @@ const fileFilter = (req, file, cb) => {
3633
}
3734
};
3835

39-
const upload = multer({ storage, fileFilter ,
40-
limits: { fileSize: 5 * 1024 * 1024 }
36+
const upload = multer({
37+
storage,
38+
fileFilter,
39+
limits: { fileSize: 5 * 1024 * 1024 },
4140
});
4241

4342
router.post("/donate", upload.array("images", 5), donateItem);

backend/routes/homeRoutes.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
2-
import express from 'express';
3-
import { getHomePage } from '../controllers/homeController.js';
1+
import express from "express";
2+
import { getHomePage } from "../controllers/homeController.js";
43

54
const router = express.Router();
65

7-
// Maps the root URL (/) to the getHomePage controller
8-
router.get('/', getHomePage);
6+
router.get("/", getHomePage);
97

10-
export default router;
8+
export default router;

0 commit comments

Comments
 (0)