import express, { json } from "express"; import cors from "cors"; import mysql from "mysql2"; import nodemailer from "nodemailer"; import crypto from "crypto"; import jwt from "jsonwebtoken"; 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 }, }); // Test the email connection transporter .verify() .then(() => { console.log("Email connection successful!"); }) .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: "Your 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, phone: data.phone, }); }, ); }, ); }, ); }, ); }); // 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 ${results} expired verification codes`); } }, ); } // 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: app.post("/find_user", (req, res) => { const { email, password } = req.body; // Input validation if (!email || !password) { return res.status(400).json({ found: false, error: "Email and password are required", }); } // Query to find user with matching email and password const query = "SELECT * FROM User WHERE email = ? AND password = ?"; db_con.query(query, [email, password], (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 user data without sensitive information return res.json({ found: true, name: user.Name, email: user.Email, }); } else { // User not found or invalid credentials return res.json({ found: false, error: "Invalid email or password", }); } }); }); //TODO: 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" }); } // Create 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.listen(3030, () => { console.log(`Running Backend on http://localhost:3030/`); console.log(`Send verification code: POST /send-verification`); console.log(`Verify code: POST /verify-code`); });