diff --git a/SQL_code/Schema.sql b/SQL_code/Schema.sql index ed116e0..97b93c4 100644 --- a/SQL_code/Schema.sql +++ b/SQL_code/Schema.sql @@ -17,6 +17,12 @@ CREATE TABLE UserRole ( FOREIGN KEY (UserID) REFERENCES User (UserID) ON DELETE CASCADE ); +-- Category Entity (must be created before Product or else error) +CREATE TABLE Category ( + CategoryID INT PRIMARY KEY, + Name VARCHAR(255) NOT NULL +); + -- Product Entity CREATE TABLE Product ( ProductID INT PRIMARY KEY, @@ -35,11 +41,6 @@ CREATE TABLE Image_URL ( FOREIGN KEY (ProductID) REFERENCES Product (ProductID) ) --- Category Entity -CREATE TABLE Category ( - CategoryID INT PRIMARY KEY, - Name VARCHAR(255) NOT NULL -); -- Review Entity (Many-to-One with User, Many-to-One with Product) CREATE TABLE Review ( diff --git a/backend/controllers/product.js b/backend/controllers/product.js new file mode 100644 index 0000000..10cd82d --- /dev/null +++ b/backend/controllers/product.js @@ -0,0 +1,70 @@ +const db = require("../utils/database"); + +exports.addToFavorite = (req, res) => { + const { userID, productsID } = req.body; + + // Use parameterized query to prevent SQL injection + db.execute( + "INSERT INTO Favorites (UserID, ProductID) VALUES (?, ?)", + [userID, productsID], + (err, result) => { + if (err) { + console.error("Error adding favorite product:", err); + return res.json({ error: "Could not add favorite product" }); + } + res.json({ + success: true, + message: "Product added to favorites successfully", + }); + } + ); +}; + +//Get all products +exports.getAllProducts = (req, res) => { + const query = "SELECT * FROM Product"; + db.execute(query, (err, data) => { + if (err) { + console.error("Error finding user:", err); + return res.status(500).json({ + found: false, + error: "Database error occurred", + }); + } + res.json({ + success: true, + message: "Product added to favorites successfully", + data, + }); + }); +}; + +// db_con.query( +// "SELECT ProductID FROM product WHERE ProductID = ?", +// [productID], +// (err, results) => { +// if (err) { +// console.error("Error checking product:", err); +// return res.json({ error: "Database error" }); +// } + +// if (results.length === 0) { +// return res.json({ error: "Product does not exist" }); +// } +// }, +// ); + +// db_con.query( +// "INSERT INTO Favorites (UserID, ProductID) VALUES (?, ?)", +// [userID, productID], +// (err, result) => { +// if (err) { +// console.error("Error adding favorite product:", err); +// return res.json({ error: "Could not add favorite product" }); +// } +// res.json({ +// success: true, +// message: "Product added to favorites successfully", +// }); +// }, +// ); diff --git a/backend/controllers/user.js b/backend/controllers/user.js new file mode 100644 index 0000000..ddb06a0 --- /dev/null +++ b/backend/controllers/user.js @@ -0,0 +1,311 @@ +const crypto = require("crypto"); +const db = require("../utils/database"); +const { sendVerificationEmail } = require("../utils/helper"); + +exports.sendVerificationCode = async (req, res) => { + const { email } = req.body; + + if (!email) { + return res.status(400).json({ error: "Email is required" }); + } + + try { + // Generate a random 6-digit code + const verificationCode = crypto.randomInt(100000, 999999).toString(); + console.log( + `Generated verification code for ${email}: ${verificationCode}` + ); + + // Check if email already exists in verification table + db.execute( + "SELECT * FROM AuthVerification WHERE Email = ?", + [email], + async (err, results) => { + if (err) { + console.error("Database error:", err); + return res.status(500).json({ error: "Database error" }); + } + + if (results.length > 0) { + // Update existing record + db.execute( + `UPDATE AuthVerification SET VerificationCode = ?, Authenticated = FALSE, Date = CURRENT_TIMESTAMP + WHERE Email = ?`, + [verificationCode, email], + async (err) => { + if (err) { + console.error("Database error:", err); + return res.status(500).json({ error: "Database error" }); + } + + // Send email and respond + await sendVerificationEmail(email, verificationCode); + res.json({ success: true, message: "Verification code sent" }); + } + ); + } else { + // Insert new record + db.execute( + "INSERT INTO AuthVerification (Email, VerificationCode, Authenticated) VALUES (?, ?, FALSE)", + [email, verificationCode], + async (err) => { + if (err) { + console.error("Database error:", err); + return res.status(500).json({ error: "Database error" }); + } + + // Send email and respond + await sendVerificationEmail(email, verificationCode); + res.json({ success: true, message: "Verification code sent" }); + } + ); + } + } + ); + } catch (error) { + console.error("Error:", error); + res.status(500).json({ error: "Server error" }); + } +}; + +exports.verifyCode = (req, res) => { + const { email, code } = req.body; + + if (!email || !code) { + return res.status(400).json({ error: "Email and code are required" }); + } + + console.log(`Attempting to verify code for ${email}: ${code}`); + + // Check verification code + db.execute( + "SELECT * FROM AuthVerification WHERE Email = ? AND VerificationCode = ? AND Authenticated = 0 AND Date > DATE_SUB(NOW(), INTERVAL 15 MINUTE)", + [email, code], + (err, results) => { + if (err) { + console.error("Database error:", err); + return res.status(500).json({ error: "Database error" }); + } + + if (results.length === 0) { + console.log(`Invalid or expired verification code for email ${email}`); + return res + .status(400) + .json({ error: "Invalid or expired verification code" }); + } + + const userId = results[0].UserID; + + // Mark as authenticated + db.execute( + "UPDATE AuthVerification SET Authenticated = TRUE WHERE Email = ?", + [email], + (err) => { + if (err) { + console.error("Database error:", err); + return res.status(500).json({ error: "Database error" }); + } + + console.log(`Email ${email} successfully verified`); + + res.json({ + success: true, + message: "Verification successful", + userId, + }); + } + ); + } + ); +}; + +exports.completeSignUp = (req, res) => { + const data = req.body; + + db.execute( + `SELECT * FROM AuthVerification WHERE Email = '${data.email}' AND Authenticated = 1;`, + (err, results) => { + if (err) { + console.error("Database error:", err); + return res.status(500).json({ error: "Database error" }); + } + if (results.length === 0) { + return res.status(400).json({ error: "Email not verified" }); + } + + // Create the user + db.execute( + `INSERT INTO User (Name, Email, UCID, Password, Phone, Address) + VALUES ('${data.name}', '${data.email}', '${data.UCID}', '${data.password}', '${data.phone}', '${data.address}')`, + (err, result) => { + if (err) { + console.error("Error creating user:", err); + return res.status(500).json({ error: "Could not create user" }); + } + + // Insert role using the user's ID + db.execute( + `INSERT INTO UserRole (UserID, Client, Admin) + VALUES (LAST_INSERT_ID(), ${data.client || true}, ${ + data.admin || false + })`, + (roleErr) => { + if (roleErr) { + console.error("Error creating role:", roleErr); + return res.status(500).json({ error: "Could not create role" }); + } + + // Delete verification record + db.execute( + `DELETE FROM AuthVerification WHERE Email = '${data.email}'`, + (deleteErr) => { + if (deleteErr) { + console.error("Error deleting verification:", deleteErr); + } + res.json({ + success: true, + message: "User registration completed successfully", + name: data.name, + email: data.email, + UCID: data.UCID, + }); + } + ); + } + ); + } + ); + } + ); +}; + +exports.getAllUser = (req, res) => { + db.execute("SELECT * FROM User;", (err, data) => { + if (err) { + console.error("Errors: ", err); + return res.status(500).json({ error: "\nCould not fetch users!" }); + } + res.json({ Users: data }); + }); +}; + +exports.findUserByEmail = (req, res) => { + const { email } = req.body; + + // Input validation + if (!email) { + return res.status(400).json({ + found: false, + error: "Email is required", + }); + } + + // Query to find user with matching email and password + const query = "SELECT * FROM User WHERE email = ?"; + db.execute(query, [email], (err, data) => { + if (err) { + console.error("Error finding user:", err); + return res.status(500).json({ + found: false, + error: "Database error occurred", + }); + } + + // Check if user was found + if (data && data.length > 0) { + console.log(data); + const user = data[0]; + + // Return all user data except password + return res.json({ + found: true, + userID: user.UserID, + name: user.Name, + email: user.Email, + UCID: user.UCID, + phone: user.Phone, + address: user.Address, + // Include any other fields your user might have + // Make sure the field names match exactly with your database column names + }); + } else { + // User not found or invalid credentials + return res.json({ + found: false, + error: "Invalid email or password", + }); + } + }); +}; + +exports.updateUser = (req, res) => { + const { userId, ...updateData } = req.body; + + if (!userId) { + return res.status(400).json({ error: "User ID is required" }); + } + + //query dynamically based on provided fields + const updateFields = []; + const values = []; + + Object.entries(updateData).forEach(([key, value]) => { + // Only include fields that are actually in the User table + if (["Name", "Email", "Password", "Phone", "UCID"].includes(key)) { + updateFields.push(`${key} = ?`); + values.push(value); + } + }); + + if (updateFields.length === 0) { + return res.status(400).json({ error: "No valid fields to update" }); + } + + // Add userId to values array + values.push(userId); + + const query = `UPDATE User SET ${updateFields.join(", ")} WHERE UserID = ?`; + + db.execute(query, values, (err, result) => { + if (err) { + console.error("Error updating user:", err); + return res.status(500).json({ error: "Could not update user" }); + } + + if (result.affectedRows === 0) { + return res.status(404).json({ error: "User not found" }); + } + + res.json({ success: true, message: "User updated successfully" }); + }); +}; + +exports.deleteUser = (req, res) => { + const { userId } = req.body; + + if (!userId) { + return res.status(400).json({ error: "User ID is required" }); + } + + // Delete from UserRole first (assuming foreign key constraint) + db.execute("DELETE FROM UserRole WHERE UserID = ?", [userId], (err) => { + if (err) { + console.error("Error deleting user role:", err); + return res.status(500).json({ error: "Could not delete user role" }); + } + + // Then delete from User table + db.execute("DELETE FROM User WHERE UserID = ?", [userId], (err, result) => { + if (err) { + console.error("Error deleting user:", err); + return res.status(500).json({ error: "Could not delete user" }); + } + + if (result.affectedRows === 0) { + return res.status(404).json({ error: "User not found" }); + } + + res.json({ success: true, message: "User deleted successfully" }); + }); + }); +}; diff --git a/backend/index.js b/backend/index.js index ecf858a..5421a77 100644 --- a/backend/index.js +++ b/backend/index.js @@ -1,41 +1,20 @@ -import express, { json } from "express"; -import cors from "cors"; -import mysql from "mysql2"; -import nodemailer from "nodemailer"; -import crypto from "crypto"; +const express = require("express"); +const cors = require("cors"); +//Get the db connection +const db = require("./utils/database"); + +const userRouter = require("./routes/user"); +const productRouter = require("./routes/product"); +const { generateEmailTransporter } = require("./utils/mail"); +const { cleanupExpiredCodes } = require("./utils/helper"); const app = express(); + app.use(cors()); app.use(express.json()); -//TODO: Connect with the database: -const db_con = mysql.createConnection({ - host: "localhost", - user: "root", - password: "12345678", - database: "marketplace", - enableKeepAlive: true, // false by default. -}); - -db_con.connect((err) => { - if (err) { - console.error("Database connection failed: " + err.stack); - return; - } - console.log("Connected to MySQL database."); -}); - // Configure email transporter for Zoho -const transporter = nodemailer.createTransport({ - host: "smtp.zohocloud.ca", - secure: true, - port: 465, - auth: { - user: "campusplug@zohomailcloud.ca", //Zoho email - pass: "e0YRrNSeJZQd", //Zoho password - }, -}); - +const transporter = generateEmailTransporter(); // Test the email connection transporter .verify() @@ -45,420 +24,13 @@ transporter .catch((error) => { console.error("Email connection failed:", error); }); -// Generate and send verification code for signup -app.post("/send-verification", async (req, res) => { - const { email } = req.body; - if (!email) { - return res.status(400).json({ error: "Email is required" }); - } - - try { - // Generate a random 6-digit code - const verificationCode = crypto.randomInt(100000, 999999).toString(); - console.log( - `Generated verification code for ${email}: ${verificationCode}`, - ); - - // Check if email already exists in verification table - db_con.query( - "SELECT * FROM AuthVerification WHERE Email = ?", - [email], - async (err, results) => { - if (err) { - console.error("Database error:", err); - return res.status(500).json({ error: "Database error" }); - } - - if (results.length > 0) { - // Update existing record - db_con.query( - `UPDATE AuthVerification SET VerificationCode = ?, Authenticated = FALSE, Date = CURRENT_TIMESTAMP - WHERE Email = ?`, - [verificationCode, email], - async (err) => { - if (err) { - console.error("Database error:", err); - return res.status(500).json({ error: "Database error" }); - } - - // Send email and respond - await sendVerificationEmail(email, verificationCode); - res.json({ success: true, message: "Verification code sent" }); - }, - ); - } else { - // Insert new record - db_con.query( - "INSERT INTO AuthVerification (Email, VerificationCode, Authenticated) VALUES (?, ?, FALSE)", - [email, verificationCode], - async (err) => { - if (err) { - console.error("Database error:", err); - return res.status(500).json({ error: "Database error" }); - } - - // Send email and respond - await sendVerificationEmail(email, verificationCode); - res.json({ success: true, message: "Verification code sent" }); - }, - ); - } - }, - ); - } catch (error) { - console.error("Error:", error); - res.status(500).json({ error: "Server error" }); - } -}); - -// Helper function to send email -async function sendVerificationEmail(email, verificationCode) { - // Send the email with Zoho - await transporter.sendMail({ - from: "campusplug@zohomailcloud.ca", - to: email, - subject: "Campus Plug: Signup Verification Code", - text: `Your verification code is: ${verificationCode}. This code will expire in 15 minutes.`, - html: `
Your verification code is: ${verificationCode}
This code will expire in 15 minutes.
`, - }); - - console.log(`Verification code sent to ${email}`); -} - -// Verify the code -app.post("/verify-code", (req, res) => { - const { email, code } = req.body; - - if (!email || !code) { - return res.status(400).json({ error: "Email and code are required" }); - } - - console.log(`Attempting to verify code for ${email}: ${code}`); - - // Check verification code - db_con.query( - "SELECT * FROM AuthVerification WHERE Email = ? AND VerificationCode = ? AND Authenticated = 0 AND Date > DATE_SUB(NOW(), INTERVAL 15 MINUTE)", - [email, code], - (err, results) => { - if (err) { - console.error("Database error:", err); - return res.status(500).json({ error: "Database error" }); - } - - if (results.length === 0) { - console.log(`Invalid or expired verification code for email ${email}`); - return res - .status(400) - .json({ error: "Invalid or expired verification code" }); - } - - const userId = results[0].UserID; - - // Mark as authenticated - db_con.query( - "UPDATE AuthVerification SET Authenticated = TRUE WHERE Email = ?", - [email], - (err) => { - if (err) { - console.error("Database error:", err); - return res.status(500).json({ error: "Database error" }); - } - - console.log(`Email ${email} successfully verified`); - - res.json({ - success: true, - message: "Verification successful", - userId, - }); - }, - ); - }, - ); -}); - -// Create a users and Complete user registration after verification -app.post("/complete-signup", (req, res) => { - const data = req.body; - - db_con.query( - `SELECT * FROM AuthVerification WHERE Email = '${data.email}' AND Authenticated = 1;`, - (err, results) => { - if (err) { - console.error("Database error:", err); - return res.status(500).json({ error: "Database error" }); - } - if (results.length === 0) { - return res.status(400).json({ error: "Email not verified" }); - } - - // Create the user - db_con.query( - `INSERT INTO User (Name, Email, UCID, Password, Phone, Address) - VALUES ('${data.name}', '${data.email}', '${data.UCID}', '${data.password}', '${data.phone}', '${data.address}')`, - (err, result) => { - if (err) { - console.error("Error creating user:", err); - return res.status(500).json({ error: "Could not create user" }); - } - - // Insert role using the user's ID - db_con.query( - `INSERT INTO UserRole (UserID, Client, Admin) - VALUES (LAST_INSERT_ID(), ${data.client || true}, ${data.admin || false})`, - (roleErr) => { - if (roleErr) { - console.error("Error creating role:", roleErr); - return res.status(500).json({ error: "Could not create role" }); - } - - // Delete verification record - db_con.query( - `DELETE FROM AuthVerification WHERE Email = '${data.email}'`, - (deleteErr) => { - if (deleteErr) { - console.error("Error deleting verification:", deleteErr); - } - res.json({ - success: true, - message: "User registration completed successfully", - name: data.name, - email: data.email, - UCID: data.UCID, - }); - }, - ); - }, - ); - }, - ); - }, - ); -}); - -// Clean up expired verification codes (run this periodically) -function cleanupExpiredCodes() { - db_con.query( - "DELETE FROM AuthVerification WHERE Date < DATE_SUB(NOW(), INTERVAL 15 MINUTE) AND Authenticated = 0", - (err, result) => { - if (err) { - console.error("Error cleaning up expired codes:", err); - } else { - console.log(`Cleaned up ${result} expired verification codes`); - } - }, - ); -} +//Routes +app.use("/api/user", userRouter); //prefix with /api/user +app.use("/api/product", productRouter); //prefix with /api/product // Set up a scheduler to run cleanup every hour setInterval(cleanupExpiredCodes, 60 * 60 * 1000); -//Fetch all users data: -app.get("/fetch_all_users", (req, res) => { - db_con.query("SELECT * FROM User;", (err, data) => { - if (err) { - console.error("Errors: ", err); - return res.status(500).json({ error: "\nCould not fetch users!" }); - } - res.json({ Users: data }); - }); -}); - -//Fetch One user Data with all fields: -app.post("/find_user", (req, res) => { - const { email } = req.body; - - // Input validation - if (!email) { - return res.status(400).json({ - found: false, - error: "Email is required", - }); - } - - // Query to find user with matching email and password - const query = "SELECT * FROM User WHERE email = ?"; - db_con.query(query, [email], (err, data) => { - if (err) { - console.error("Error finding user:", err); - return res.status(500).json({ - found: false, - error: "Database error occurred", - }); - } - - // Check if user was found - if (data && data.length > 0) { - console.log(data); - const user = data[0]; - - // Return all user data except password - return res.json({ - found: true, - userID: user.UserID, - name: user.Name, - email: user.Email, - UCID: user.UCID, - phone: user.Phone, - address: user.Address, - // Include any other fields your user might have - // Make sure the field names match exactly with your database column names - }); - } else { - // User not found or invalid credentials - return res.json({ - found: false, - error: "Invalid email or password", - }); - } - }); -}); - -//Update A uses Data: -app.post("/update", (req, res) => { - const { userId, ...updateData } = req.body; - - if (!userId) { - return res.status(400).json({ error: "User ID is required" }); - } - - //query dynamically based on provided fields - const updateFields = []; - const values = []; - - Object.entries(updateData).forEach(([key, value]) => { - // Only include fields that are actually in the User table - if (["Name", "Email", "Password", "Phone", "UCID"].includes(key)) { - updateFields.push(`${key} = ?`); - values.push(value); - } - }); - - if (updateFields.length === 0) { - return res.status(400).json({ error: "No valid fields to update" }); - } - - // Add userId to values array - values.push(userId); - - const query = `UPDATE User SET ${updateFields.join(", ")} WHERE UserID = ?`; - - db_con.query(query, values, (err, result) => { - if (err) { - console.error("Error updating user:", err); - return res.status(500).json({ error: "Could not update user" }); - } - - if (result.affectedRows === 0) { - return res.status(404).json({ error: "User not found" }); - } - - res.json({ success: true, message: "User updated successfully" }); - }); -}); - -//Delete A uses Data: -app.post("/delete", (req, res) => { - const { userId } = req.body; - - if (!userId) { - return res.status(400).json({ error: "User ID is required" }); - } - - // Delete from UserRole first (assuming foreign key constraint) - db_con.query("DELETE FROM UserRole WHERE UserID = ?", [userId], (err) => { - if (err) { - console.error("Error deleting user role:", err); - return res.status(500).json({ error: "Could not delete user role" }); - } - - // Then delete from User table - db_con.query( - "DELETE FROM User WHERE UserID = ?", - [userId], - (err, result) => { - if (err) { - console.error("Error deleting user:", err); - return res.status(500).json({ error: "Could not delete user" }); - } - - if (result.affectedRows === 0) { - return res.status(404).json({ error: "User not found" }); - } - - res.json({ success: true, message: "User deleted successfully" }); - }, - ); - }); -}); - -app.post("/add_fav_product", (req, res) => { - const { userID, productsID } = req.body; - - // Use parameterized query to prevent SQL injection - db_con.query( - "INSERT INTO Favorites (UserID, ProductID) VALUES (?, ?)", - [userID, productsID], - (err, result) => { - if (err) { - console.error("Error adding favorite product:", err); - return res.json({ error: "Could not add favorite product" }); - } - res.json({ - success: true, - message: "Product added to favorites successfully", - }); - }, - ); -}); - -app.get("/get_product", (req, res) => { - const query = "SELECT * FROM Product"; - db_con.query(query, (err, data) => { - if (err) { - console.error("Error finding user:", err); - return res.status(500).json({ - found: false, - error: "Database error occurred", - }); - } - res.json({ - success: true, - message: "Product added to favorites successfully", - data, - }); - }); -}); - -// db_con.query( -// "SELECT ProductID FROM product WHERE ProductID = ?", -// [productID], -// (err, results) => { -// if (err) { -// console.error("Error checking product:", err); -// return res.json({ error: "Database error" }); -// } - -// if (results.length === 0) { -// return res.json({ error: "Product does not exist" }); -// } -// }, -// ); - -// db_con.query( -// "INSERT INTO Favorites (UserID, ProductID) VALUES (?, ?)", -// [userID, productID], -// (err, result) => { -// if (err) { -// console.error("Error adding favorite product:", err); -// return res.json({ error: "Could not add favorite product" }); -// } -// res.json({ -// success: true, -// message: "Product added to favorites successfully", -// }); -// }, -// ); app.listen(3030, () => { console.log(`Running Backend on http://localhost:3030/`); diff --git a/backend/package.json b/backend/package.json index 3e2f635..612c3f1 100644 --- a/backend/package.json +++ b/backend/package.json @@ -2,7 +2,7 @@ "name": "server", "version": "1.0.0", "main": "index.js", - "type": "module", + "type": "commonjs", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "node index.js" diff --git a/backend/routes/product.js b/backend/routes/product.js new file mode 100644 index 0000000..55d3761 --- /dev/null +++ b/backend/routes/product.js @@ -0,0 +1,10 @@ +const express = require("express"); +const { addToFavorite, getAllProducts } = require("../controllers/product"); + +const router = express.Router(); + +router.post("/add_fav_product", addToFavorite); + +router.get("/get_product", getAllProducts); + +module.exports = router; diff --git a/backend/routes/user.js b/backend/routes/user.js new file mode 100644 index 0000000..3d11102 --- /dev/null +++ b/backend/routes/user.js @@ -0,0 +1,35 @@ +const express = require("express"); +const { + sendVerificationCode, + verifyCode, + completeSignUp, + getAllUser, + findUserByEmail, + updateUser, + deleteUser, +} = require("../controllers/user"); + +const router = express.Router(); + +// Generate and send verification code for signup +router.post("/send-verification", sendVerificationCode); + +// Verify the code +router.post("/verify-code", verifyCode); + +// Create a users and Complete user registration after verification +router.post("/complete-signup", completeSignUp); + +//Fetch all users data: +router.get("/fetch_all_users", getAllUser); + +//Fetch One user Data with all fields: +router.post("/find_user", findUserByEmail); + +//Update A uses Data: +router.post("/update", updateUser); + +//Delete A uses Data: +router.post("/delete", deleteUser); + +module.exports = router; diff --git a/backend/utils/database.js b/backend/utils/database.js new file mode 100644 index 0000000..1016143 --- /dev/null +++ b/backend/utils/database.js @@ -0,0 +1,11 @@ +const mysql = require("mysql2"); + +//Create a pool of connection to allow multiple query happen at the same time +const pool = mysql.createPool({ + host: "localhost", + user: "root", + database: "marketplace", + password: "12345678", +}); + +module.exports = pool.promise(); diff --git a/backend/utils/helper.js b/backend/utils/helper.js new file mode 100644 index 0000000..1e8b6f5 --- /dev/null +++ b/backend/utils/helper.js @@ -0,0 +1,33 @@ +const { generateEmailTransporter } = require("./mail"); + +// Helper function to send email +async function sendVerificationEmail(email, verificationCode) { + const transporter = generateEmailTransporter(); + + // Send the email with Zoho + await transporter.sendMail({ + from: "campusplug@zohomailcloud.ca", + to: email, + subject: "Campus Plug: Signup Verification Code", + text: `Your verification code is: ${verificationCode}. This code will expire in 15 minutes.`, + html: `Your verification code is: ${verificationCode}
This code will expire in 15 minutes.
`, + }); + + console.log(`Verification code sent to ${email}`); +} + +// Clean up expired verification codes (run this periodically) +function cleanupExpiredCodes() { + db_con.query( + "DELETE FROM AuthVerification WHERE Date < DATE_SUB(NOW(), INTERVAL 15 MINUTE) AND Authenticated = 0", + (err, result) => { + if (err) { + console.error("Error cleaning up expired codes:", err); + } else { + console.log(`Cleaned up ${result} expired verification codes`); + } + } + ); +} + +module.exports = { sendVerificationEmail, cleanupExpiredCodes }; diff --git a/backend/utils/mail.js b/backend/utils/mail.js new file mode 100644 index 0000000..6810672 --- /dev/null +++ b/backend/utils/mail.js @@ -0,0 +1,12 @@ +const nodemailer = require("nodemailer"); + +exports.generateEmailTransporter = () => + nodemailer.createTransport({ + host: "smtp.zohocloud.ca", + secure: true, + port: 465, + auth: { + user: "campusplug@zohomailcloud.ca", //Zoho email + pass: "e0YRrNSeJZQd", //Zoho password + }, + }); diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index a194491..5a65c60 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -59,16 +59,19 @@ function App() { console.log("Sending verification code to:", userData.email); // Make API call to send verification code - const response = await fetch("http://localhost:3030/send-verification", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - email: userData.email, - // Add any other required fields - }), - }); + const response = await fetch( + "http://localhost:3030/api/user/send-verification", + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + email: userData.email, + // Add any other required fields + }), + } + ); if (!response.ok) { throw new Error("Failed to send verification code"); @@ -105,16 +108,19 @@ function App() { console.log("Verifying code:", code); // Make API call to verify code - const response = await fetch("http://localhost:3030/verify-code", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - email: tempUserData.email, - code: code, - }), - }); + const response = await fetch( + "http://localhost:3030/api/user/verify-code", + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + email: tempUserData.email, + code: code, + }), + } + ); if (!response.ok) { throw new Error("Failed to verify code"); @@ -149,13 +155,16 @@ function App() { console.log(userData); // Make API call to complete signup - const response = await fetch("http://localhost:3030/complete-signup", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(userData), - }); + const response = await fetch( + "http://localhost:3030/api/user/complete-signup", + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(userData), + } + ); if (!response.ok) { throw new Error("Failed to complete signup"); @@ -245,16 +254,19 @@ function App() { }); // Make API call to localhost:3030/find_user - const response = await fetch("http://localhost:3030/find_user", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - email: formValues.email, - password: formValues.password, - }), - }); + const response = await fetch( + "http://localhost:3030/api/user/find_user", + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + email: formValues.email, + password: formValues.password, + }), + } + ); if (!response.ok) { throw new Error("Network response was not ok"); @@ -497,8 +509,8 @@ function App() { {isLoading ? "Please wait..." : isSignUp - ? "Create Account" - : "Sign In"} + ? "Create Account" + : "Sign In"} diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx index b9a1a6d..73fc17b 100644 --- a/frontend/src/main.jsx +++ b/frontend/src/main.jsx @@ -1,10 +1,10 @@ -import { StrictMode } from 'react' -import { createRoot } from 'react-dom/client' -import './index.css' -import App from './App.jsx' +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import "./index.css"; +import App from "./App.jsx"; -createRoot(document.getElementById('root')).render( +createRoot(document.getElementById("root")).render(