Repository: JohnathanAguilar01/Real-Fake-Car-Rentals
Pull request #10: Added the user model and user controller.
Author: login: JohnathanAguilar01
Labels: name: enhancement
description: New feature or request
Created: 2025-03-15T21:18:17Z | Merged: 2025-03-17T03:24:45Z



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Enhanced session handling to support seamless login management with improved expiration tracking.
  - Updated the vehicle reservation process to deliver clearer confirmation responses and robust error handling.
  - Introduced middleware for session validation to ensure secure user authentication.
  - Added user authentication routes for login and logout functionalities.
  - Implemented a vehicle retrieval feature to fetch all vehicles and available vehicles based on user input.

- **Chores**
  - Upgraded development tooling with refined linting configurations and new support dependencies.
  - Streamlined internal data structures and routing adjustments for improved system reliability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/backend/eslint.config.js b/backend/eslint.config.js
new file mode 100644
index 0000000..e64ccc5
--- /dev/null
+++ b/backend/eslint.config.js
@@ -0,0 +1,12 @@
+import globals from "globals";
+import pluginJs from "@eslint/js";
+import tseslint from "typescript-eslint";
+
+
+/** @type {import('eslint').Linter.Config[]} */
+export default [
+  {files: ["**/*.{js,mjs,cjs,ts}"]},
+  {languageOptions: { globals: globals.browser }},
+  pluginJs.configs.recommended,
+  ...tseslint.configs.recommended,
+];
\ No newline at end of file
diff --git a/backend/package-lock.json b/backend/package-lock.json
index dd8a343..1f2077c 100644
--- a/backend/package-lock.json
+++ b/backend/package-lock.json
@@ -17,6 +17,8 @@
         "mysql2": "^3.11.5"
       },
       "devDependencies": {
+        "@eslint/js": "^9.22.0",
+        "@types/bcrypt": "^5.0.2",
         "@types/cookie-parser": "^1.4.8",
         "@types/cors": "^2.8.17",
         "@types/express": "^5.0.0",
@@ -24,12 +26,14 @@
         "@typescript-eslint/eslint-plugin": "^8.26.1",
         "@typescript-eslint/parser": "^8.26.1",
         "eslint": "^9.22.0",
+        "globals": "^16.0.0",
         "jest": "^29.7.0",
         "nodemon": "^3.1.7",
         "supertest": "^7.0.0",
         "ts-node": "^10.9.2",
         "tsx": "^4.19.3",
-        "typescript": "^5.8.2"
+        "typescript": "^5.8.2",
+        "typescript-eslint": "^8.26.1"
       }
     },
     "node_modules/@ampproject/remapping": {
@@ -1137,6 +1141,19 @@
         "concat-map": "0.0.1"
       }
     },
+    "node_modules/@eslint/eslintrc/node_modules/globals": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+      "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/@eslint/eslintrc/node_modules/minimatch": {
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -1870,6 +1887,16 @@
         "@babel/types": "^7.20.7"
       }
     },
+    "node_modules/@types/bcrypt": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz",
+      "integrity": "sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
     "node_modules/@types/body-parser": {
       "version": "1.19.5",
       "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",
@@ -4280,9 +4307,9 @@
       }
     },
     "node_modules/globals": {
-      "version": "14.0.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
-      "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+      "version": "16.0.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz",
+      "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==",
       "dev": true,
       "license": "MIT",
       "engines": {
@@ -7305,6 +7332,29 @@
         "node": ">=14.17"
       }
     },
+    "node_modules/typescript-eslint": {
+      "version": "8.26.1",
+      "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.26.1.tgz",
+      "integrity": "sha512-t/oIs9mYyrwZGRpDv3g+3K6nZ5uhKEMt2oNmAPwaY4/ye0+EH4nXIPYNtkYFS6QHm+1DFg34DbglYBz5P9Xysg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/eslint-plugin": "8.26.1",
+        "@typescript-eslint/parser": "8.26.1",
+        "@typescript-eslint/utils": "8.26.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <5.9.0"
+      }
+    },
     "node_modules/undefsafe": {
       "version": "2.0.5",
       "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
diff --git a/backend/package.json b/backend/package.json
index 986d914..645f6e5 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -21,6 +21,8 @@
     "mysql2": "^3.11.5"
   },
   "devDependencies": {
+    "@eslint/js": "^9.22.0",
+    "@types/bcrypt": "^5.0.2",
     "@types/cookie-parser": "^1.4.8",
     "@types/cors": "^2.8.17",
     "@types/express": "^5.0.0",
@@ -28,12 +30,14 @@
     "@typescript-eslint/eslint-plugin": "^8.26.1",
     "@typescript-eslint/parser": "^8.26.1",
     "eslint": "^9.22.0",
+    "globals": "^16.0.0",
     "jest": "^29.7.0",
     "nodemon": "^3.1.7",
     "supertest": "^7.0.0",
     "ts-node": "^10.9.2",
     "tsx": "^4.19.3",
-    "typescript": "^5.8.2"
+    "typescript": "^5.8.2",
+    "typescript-eslint": "^8.26.1"
   },
   "jest": {
     "transform": {}
diff --git a/backend/src/controllers/user-controller.ts b/backend/src/controllers/user-controller.ts
new file mode 100644
index 0000000..55cd057
--- /dev/null
+++ b/backend/src/controllers/user-controller.ts
@@ -0,0 +1,40 @@
+import { Request, Response } from "express";
+import UserService from "../services/user-service.js";
+import { TUser } from "../models/user.js";
+
+// biome-ignore lint/complexity/noStaticOnlyClass: This class follows OOP patterns for learning purposes
+export default class UserController {
+  static async login(req: Request, res: Response) {
+    try {
+      const { id, password }: Pick<TUser, "id" | "password"> = req.body;
+      if (!id || !password) {
+        res.status(400).json({ error: "No user id or password recived" });
+        return;
+      }
+      const sessionid = await UserService.login(id, password);
+      if (!sessionid) {
+        res.status(401).json({ error: "User not found" });
+        return;
+      }
+      res.cookie("sessionid", String(sessionid), {
+        secure: true,
+        httpOnly: true,
+        sameSite: "none",
+      });
+      res.json({ user: { id } });
+      return;
+    } catch (error) {
+      console.error("Login error:", error);
+      res.status(500).send("Internal server error");
+    }
+  }
+
+  static async logout(req: Request, res: Response) {
+    const sessionid = req.cookies.sessionid;
+    if (!sessionid) {
+      res.status(400).json({ error: "No session id recived" });
+    }
+    res.clearCookie("sessionid");
+    res.sendStatus(200);
+  }
+}
diff --git a/backend/src/controllers/vehicle-controller.ts b/backend/src/controllers/vehicle-controller.ts
new file mode 100644
index 0000000..d71228e
--- /dev/null
+++ b/backend/src/controllers/vehicle-controller.ts
@@ -0,0 +1,36 @@
+import { Request, Response } from "express";
+import VehicleService from "../services/vehicle-service.js";
+
+export default class VehicleController {
+  static async getAllVehicles(req: Request, res: Response) {
+    try {
+      const vehicles = await VehicleService.getAllVehicles();
+      res.json(vehicles);
+    } catch (error) {
+      console.error(error);
+      res.status(500).send("Server error:" + error);
+    }
+  }
+
+  static async getAvailableVehicles(req: Request, res: Response) {
+    try {
+      const type: string = (req.query.type as string) ?? "";
+      const startDate: string = (req.query.startDate as string) ?? "";
+      const endDate: string = (req.query.endDate as string) ?? "";
+
+      const vehicles = await VehicleService.getAvailableVehicles(
+        type,
+        startDate,
+        endDate,
+      );
+      if (!vehicles) {
+        res.status(404).json({ error: "No cars found" });
+        return;
+      }
+      res.json(vehicles);
+    } catch (error) {
+      console.error(error);
+      res.status(500).send("Server error:" + error);
+    }
+  }
+}
diff --git a/backend/src/middlewares/auth.ts b/backend/src/middlewares/auth.ts
new file mode 100644
index 0000000..a4b8939
--- /dev/null
+++ b/backend/src/middlewares/auth.ts
@@ -0,0 +1,30 @@
+import { Request, Response, NextFunction } from "express";
+import UserService from "../services/user-service.js";
+
+// middleware to check if user is logged in
+export const authCheck = async (
+  req: Request,
+  res: Response,
+  next: NextFunction,
+): Promise<Response | void> => {
+  try {
+    const sessionid = req.cookies.sessionid;
+    // Ensure sessionid is present and valid
+    if (
+      !sessionid ||
+      typeof sessionid !== "string" ||
+      sessionid.trim() === ""
+    ) {
+      return res.status(401).send("Unauthorized: No session ID provided");
+    }
+
+    const exists: boolean = await UserService.sessionExists(sessionid);
+    if (!exists) {
+      return res.status(401).send("Unauthorized: Invalid session ID");
+    }
+    next();
+  } catch (error) {
+    console.error(error);
+    return res.status(500).json({ error: "Internal Server Error" });
+  }
+};
diff --git a/backend/src/models/user.ts b/backend/src/models/user.ts
new file mode 100644
index 0000000..0d3917b
--- /dev/null
+++ b/backend/src/models/user.ts
@@ -0,0 +1,19 @@
+export type TUser = {
+  id: number;
+  firstName: string;
+  lastName: string;
+  email: string;
+  userName: string;
+  password: string;
+};
+
+export class User {
+  constructor(
+    public userId: number,
+    public firstName: string,
+    public lastName: string,
+    public email: string,
+    public userName: string,
+    public password: string,
+  ) {}
+}
diff --git a/backend/src/models/vehicle.ts b/backend/src/models/vehicle.ts
index c04a6a8..b6cc950 100644
--- a/backend/src/models/vehicle.ts
+++ b/backend/src/models/vehicle.ts
@@ -1,5 +1,5 @@
 type Vehicle = {
-  vin: number;
+  vin: string;
   mileage: number;
   mpg: number;
   price: number;
diff --git a/backend/src/routes/user-routes.js b/backend/src/routes/user-routes.js
deleted file mode 100644
index 8711715..0000000
--- a/backend/src/routes/user-routes.js
+++ /dev/null
@@ -1,191 +0,0 @@
-import express from "express";
-import bodyparser from "body-parser";
-import cookieparser from "cookie-parser";
-import crypto from "crypto";
-import bcrypt from "bcrypt";
-import db from "../db";
-const router = express.Router();
-
-router.use(bodyparser.json());
-router.use(cookieparser());
-
-const sessions = new Map();
-const saltRounds = 5;
-
-// generate a random uid
-function generateSessionId() {
-  return crypto.randomUUID();
-}
-
-// updates the expire time for a session or makes a new one if no session exists
-async function createOrUpdateSession(username, inputSessionsId = null) {
-  // Set expiration time to 2 days from now
-  const expiresAt = Date.now() + 1000 * 60 * 60 * 24 * 2;
-
-  // Use provided session ID or generate a new one
-  let sessionsId = inputSessionsId || generateSessionId();
-
-  // const [result] = await pool.query(query, [sessionsId, username]);Store session in the sessions map
-  // sessions.set(sessionsId, { username, expiresAt });
-
-  try {
-    const query =
-      "INSERT IGNORE INTO Sessions (SessionID, CustomerID) " +
-      "SELECT ?, CustomerID FROM Customers WHERE UserName = ?";
-    const [result] = await db.query(query, [sessionsId, username]);
-  } catch (error) {
-    console.error("Database error: ", error);
-  }
-  console.log(sessionsId);
-  return sessionsId;
-}
-
-// function to remove all expired sessions
-function removeexpiredsessions() {
-  const currentdate = Date.now();
-  for (let [sessionsid, session] of sessions) {
-    if (session.expiresat < currentdate) {
-      sessions.delete(sessionsid);
-    }
-  }
-}
-
-// middleware to refresh a session
-function refreshsession(req, res, next) {
-  removeexpiredsessions();
-
-  const sessionid = req.cookies.sessionid;
-  const session = sessions.get(sessionid);
-
-  if (session) {
-    createOrUpdateSession(session.username, sessionid);
-    req.user = session;
-  }
-
-  next();
-}
-
-// middleware to check if user is logged in
-async function authcheck(req, res, next) {
-  const sessionid = req.cookies.sessionid;
-
-  // Ensure sessionid is present and valid
-  if (!sessionid || typeof sessionid !== "string" || sessionid.trim() === "") {
-    return res.status(401).send("Unauthorized: No session ID provided");
-  }
-
-  const query =
-    "SELECT COUNT(*) AS sessionExists FROM Sessions WHERE SessionID = ?";
-
-  try {
-    const [rows] = await db.query(query, [sessionid]);
-
-    // Check if the session exists
-    if (rows[0] && rows[0].sessionExists > 0) {
-      return next();
-    } else {
-      return res.status(402).send("Unauthorized: Invalid session ID");
-    }
-  } catch (error) {
-    console.error("Database error:", error);
-    return res.status(500).send("Internal Server Error");
-  }
-}
-
-// login end point
-router.post("/login", async (req, res) => {
-  try {
-    const { username, password } = req.body;
-    const query = "SELECT Password FROM Customers WHERE UserName = ?";
-    const [results] = await db.execute(query, [username]);
-
-    if (results.length === 0) {
-      return res.status(404).send("User not found");
-    }
-
-    const storedHash = results[0].Password; // Notice capital P if it's case-sensitive
-
-    const isMatch = await bcrypt.compare(password, storedHash);
-    if (isMatch) {
-      const sessionid = await createOrUpdateSession(username);
-      res.cookie("sessionid", String(sessionid), {
-        secure: true,
-        httponly: true,
-        samesite: "none",
-      });
-      return res.json({ user: { username } });
-    } else {
-      return res.status(401).send("Incorrect User Information");
-    }
-  } catch (err) {
-    console.error("Login error:", err);
-    res.status(500).send("Internal server error");
-  }
-});
-
-router.post("/authCheck", authcheck, (req, res) => {
-  res.sendStatus(200);
-});
-
-// logout end point
-router.post("/logout", (req, res) => {
-  const sessionid = req.cookies.sessionid;
-  if (sessionid) {
-    sessions.delete(sessionid);
-  }
-  res.clearCookie("sessionid");
-  res.sendStatus(200);
-});
-
-// signup end point
-router.post("/signup", (req, res) => {
-  const { firstName, lastName, email, username, password, confirmPassword } =
-    req.body;
-
-  console.log(
-    firstName +
-      " " +
-      lastName +
-      " " +
-      email +
-      " " +
-      username +
-      " " +
-      password +
-      " " +
-      confirmPassword,
-  );
-  if (password != confirmPassword) {
-    return res.status(400).send("Passwords do not match.");
-  }
-
-  if (
-    !firstName ||
-    !lastName ||
-    !email ||
-    !username ||
-    !password ||
-    !confirmPassword
-  ) {
-    return res.status(400).send("Missing information.");
-  }
-
-  bcrypt.hash(password, saltRounds, (err, hash) => {
-    if (err) {
-      console.error("Error hashing password:", err);
-      return res.status(500).send("Internal server error");
-    }
-
-    const query =
-      "INSERT INTO Customers (FirstName, LastName, Email, UserName, Password)" +
-      "VALUES (?, ?, ?, ?, ?)";
-    db.execute(query, [firstName, lastName, email, username, hash], (err) => {
-      if (err) {
-        return res.status(500).send("Database error.");
-      }
-      return res.status(201).send("User registered successfully");
-    });
-  });
-});
-
-export default router;
diff --git a/backend/src/routes/user-routes.ts b/backend/src/routes/user-routes.ts
new file mode 100644
index 0000000..c42a097
--- /dev/null
+++ b/backend/src/routes/user-routes.ts
@@ -0,0 +1,12 @@
+import express from "express";
+import bodyParser from "body-parser";
+import cookieParser from "cookie-parser";
+import UserController from "../controllers/user-controller.js";
+const router = express.Router();
+router.use(bodyParser.json());
+router.use(cookieParser());
+
+router.post("/login", UserController.login);
+router.post("/logout", UserController.logout);
+
+export default router;
diff --git a/backend/src/routes/vehicles-routes.ts b/backend/src/routes/vehicles-routes.ts
index 2fa0c2c..c71699d 100644
--- a/backend/src/routes/vehicles-routes.ts
+++ b/backend/src/routes/vehicles-routes.ts
@@ -1,38 +1,10 @@
 import express from "express";
-import VehicleController from "../controllers/vehicle-controler.js";
+import VehicleController from "../controllers/vehicle-controller.js";
 const router = express.Router();
 
 // Example: Fetch all users
-router.get("/", async (req, res) => {
-  try {
-    const vehicles = await VehicleController.getAllVehicles();
-    res.json(vehicles);
-  } catch (error) {
-    console.error(error);
-    res.status(500).send("Server error:" + error);
-  }
-});
+router.get("/", VehicleController.getAllVehicles);
 
-router.get("/available", async (req, res) => {
-  try {
-    const type: string = (req.query.type as string) ?? "";
-    const startDate: string = (req.query.startDate as string) ?? "";
-    const endDate: string = (req.query.endDate as string) ?? "";
-
-    const vehicles = await VehicleController.getAvailableVehicles(
-      type,
-      startDate,
-      endDate,
-    );
-    if (!vehicles) {
-      res.status(404).json({ error: "No cars found" });
-      return;
-    }
-    res.json(vehicles);
-  } catch (error) {
-    console.error(error);
-    res.status(500).send("Server error:" + error);
-  }
-});
+router.get("/available", VehicleController.getAvailableVehicles);
 
 export default router;
diff --git a/backend/src/services/user-service.ts b/backend/src/services/user-service.ts
new file mode 100644
index 0000000..ca23911
--- /dev/null
+++ b/backend/src/services/user-service.ts
@@ -0,0 +1,79 @@
+import db from "../config/db.js";
+import { RowDataPacket } from "mysql2";
+import crypto from "crypto";
+import bcrypt from "bcrypt";
+
+// biome-ignore lint/complexity/noStaticOnlyClass: This class follows OOP patterns for learning purposes
+export default class UserService {
+  // updates the expire time for a session or makes a new one if no session exists
+  private static async createOrUpdateSession(
+    userId: number,
+    inputSessionId: string | null = null,
+  ) {
+    try {
+      if (!inputSessionId) {
+        const sessionId: string = crypto.randomUUID();
+        const addDaysToDate = (date: Date, days: number): string => {
+          const futureDate = new Date(date);
+          futureDate.setDate(futureDate.getDate() + days);
+
+          // Format to YYYY-MM-DD
+          const year = futureDate.getFullYear();
+          const month = String(futureDate.getMonth() + 1).padStart(2, "0"); // Ensure two digits
+          const day = String(futureDate.getDate()).padStart(2, "0"); // Ensure two digits
+
+          return `${year}-${month}-${day}`;
+        };
+
+        // Example Usage
+        const today: Date = new Date();
+        const expireLogin: string = addDaysToDate(today, 5);
+
+        const query: string =
+          "INSERT INTO Sessions (session_id, user_id, expire_login) " +
+          "VALUE (?,?,?)";
+        const [results] = await db.query(query, [
+          sessionId,
+          userId,
+          expireLogin,
+        ]);
+        console.log(results);
+        return sessionId;
+      }
+      const sessionId: string | null = inputSessionId;
+      const query: string =
+        "UPDATE Sessions SET last_login = ? WHERE session_id = ?";
+      const [results] = await db.query(query, [sessionId]);
+      console.log(results);
+      return sessionId;
+    } catch (error) {
+      console.error("Database error: ", error);
+    }
+  }
+
+  static async sessionExists(sessionId: string) {
+    const query: string =
+      "SELECT COUNT(*) AS count FROM Sessions WHERE session_id = ?";
+    const [results]: [RowDataPacket[], any] = await db.query(query, sessionId);
+    return results[0].count > 0;
+  }
+
+  static async login(userId: number, password: string) {
+    const query = "SELECT Password FROM Customers WHERE user_id = ?";
+    const [results]: [RowDataPacket[], any] = await db.execute(query, userId);
+    const storedHash = results[0].Password; // Notice capital P if it's case-sensitive
+
+    const isMatch = await bcrypt.compare(password, storedHash);
+    if (isMatch) {
+      const sessionid = await this.createOrUpdateSession(userId);
+      return sessionid;
+    }
+    return null;
+  }
+
+  static async logout(sessionId: string) {
+    const query: string = "DELETE FROM Sessions WHERE session_id = ?";
+    const [results]: any = await db.query(query, sessionId);
+    return results.affectedRows;
+  }
+}
diff --git a/backend/src/controllers/vehicle-controler.ts b/backend/src/services/vehicle-service.ts
similarity index 62%
rename from backend/src/controllers/vehicle-controler.ts
rename to backend/src/services/vehicle-service.ts
index b0221eb..e6e692e 100644
--- a/backend/src/controllers/vehicle-controler.ts
+++ b/backend/src/services/vehicle-service.ts
@@ -1,8 +1,9 @@
 import Vehicle from "../models/vehicle.js";
 import db from "../config/db.js";
+import { throws } from "assert";
 
 // biome-ignore lint/complexity/noStaticOnlyClass: This class follows OOP patterns for learning purposes
-class VehicleController {
+export default class VehicleService {
   static async getAllVehicles(): Promise<Vehicle[]> {
     const [result]: any = await db.query("SELECT * FROM Vehicles");
     return result;
@@ -30,14 +31,17 @@ class VehicleController {
     insurance: boolean,
     customerID: number,
     vehicleID: number,
-  ): Promise<{ vehicleId: number } | null> {
-    const query: string =
-      "INSERT INTO Reservations (StartDate, EndDate, Insurance, CustomerID, Vehicle)" +
-      "VALUES (?, ?, ?, ?, ?)";
-    const values = [startDate, endDate, insurance, customerID, vehicleID];
-    const [result]: any = await db.query(query, values);
-    return result.insertId ? { vehicleId: result.insertId } : null;
+  ): Promise<{ reservationsId: number } | null> {
+    try {
+      const query: string =
+        "INSERT INTO Reservations (StartDate, EndDate, Insurance, CustomerID, Vehicle)" +
+        "VALUES (?, ?, ?, ?, ?)";
+      const values = [startDate, endDate, insurance, customerID, vehicleID];
+      const [result]: any = await db.query(query, values);
+      return result.insertId ? { reservationsId: result.insertId } : null;
+    } catch (error) {
+      console.error("Error creating reservation:", error);
+      throw error;
+    }
   }
 }
-
-export default VehicleController;
diff --git a/database/setup.sql b/database/setup.sql
index f6c2564..0a46000 100644
--- a/database/setup.sql
+++ b/database/setup.sql
@@ -61,6 +61,7 @@ CREATE TABLE IF NOT EXISTS Reports(
 CREATE TABLE IF NOT EXISTS Sessions(
     SessionID VARCHAR(255) PRIMARY KEY,
     CustomerID INT,
+    LastLogin DATE,
     CONSTRAINT FK_SessionsCustomerID 
     FOREIGN KEY (CustomerID) 
     REFERENCES Customers(CustomerID)


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 4**

<details>
<summary>🔭 Outside diff range comments (1)</summary><blockquote>

<details>
<summary>backend/src/routes/vehicles-routes.ts (1)</summary><blockquote>

`16-36`: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Consider adding reservation endpoint**

The PR title mentions adding a user controller, but there's no corresponding endpoint for creating reservations despite the VehicleController having a createReservation method according to the AI summary. Consider adding an endpoint for this functionality.

---

🏁 Script executed:

```shell
#!/bin/bash
# Check if there's a reservation creation endpoint in other route files
echo "Searching for reservation creation endpoints..."
rg -l "createReservation" --type ts --glob "backend/src/routes/*.ts"
```

Length of output: 173

---



</details>

**Action Required: Add Missing Reservation Endpoint**

The current routes do not expose the `createReservation` functionality from the VehicleController. Although the PR title hints at additional controller work, no endpoint (e.g., a POST route) exists to handle reservation creation. Please add an endpoint—such as a `router.post("/reservation", …)`—that utilizes the VehicleController’s `createReservation` method, with appropriate error handling and input validation.

- **File Impact:** Likely in a new or existing routes file (e.g., within backend/src/routes/vehicles-routes.ts or a dedicated reservations routing file)
- **Action:** Implement the missing endpoint to ensure reservation functionality is accessible

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (6)</summary><blockquote>

<details>
<summary>database/setup.sql (1)</summary><blockquote>

`64-64`: **Consider using DATETIME or TIMESTAMP instead of DATE for LastLogin**

The DATE type only captures the calendar date without time information. For login tracking, using DATETIME or TIMESTAMP would provide more precise tracking by recording the exact time of login, which is generally more useful for security auditing, session management, and analytics.

```diff
- LastLogin DATE,
+ LastLogin DATETIME,
```

This change would enhance your ability to:
- Detect suspicious login patterns more precisely
- Implement accurate session timeout mechanisms
- Create more detailed user activity reports

</blockquote></details>
<details>
<summary>backend/src/models/user.ts (1)</summary><blockquote>

`1-17`: **Add data validation for user properties**

The user model lacks input validation for important fields like email, which should follow proper email format, or password, which should meet security requirements.

Consider implementing validation logic either:
1. Within the User class
2. Using a validation library like Joi or class-validator
3. Adding validation in the controller layer

This is essential for maintaining data integrity and security.

</blockquote></details>
<details>
<summary>backend/eslint.config.js (1)</summary><blockquote>

`1-12`: **ESLint configuration looks good, with some potential enhancements**

The ESLint configuration follows the modern flat config format and includes essential configurations for both JavaScript and TypeScript. 




Consider enhancing this base configuration with:

```diff
 import globals from "globals";
 import pluginJs from "@eslint/js";
 import tseslint from "typescript-eslint";

-
 /** @type {import('eslint').Linter.Config[]} */
 export default [
   {files: ["**/*.{js,mjs,cjs,ts}"]},
   {languageOptions: { globals: globals.browser }},
   pluginJs.configs.recommended,
   ...tseslint.configs.recommended,
+  // Additional TypeScript-specific parser options
+  {
+    files: ["**/*.ts"],
+    languageOptions: {
+      parser: tseslint.parser,
+      parserOptions: {
+        project: "./tsconfig.json",
+      },
+    },
+  },
+  // Project-specific rules
+  {
+    rules: {
+      // Add custom rules here
+      "no-console": ["warn", { allow: ["warn", "error"] }],
+    },
+  },
 ];
```

</blockquote></details>
<details>
<summary>backend/src/controllers/vehicle-controller.ts (2)</summary><blockquote>

`3-3`: **Unused import should be removed**

The `throws` import from `assert` is not being used in this file.


```diff
 import Vehicle from "../models/vehicle.js";
 import db from "../config/db.js";
-import { throws } from "assert";
```

---

`28-46`: **Return type and error handling improved, but method name inconsistency**

The improved error handling with try/catch is good. However, there's inconsistency between the method name (`rentVehicle`) and what it actually does (creates a reservation).




Consider renaming the method to align with its functionality:

```diff
-  static async rentVehicle(
+  static async createReservation(
     startDate: string,
     endDate: string,
     insurance: boolean,
     customerID: number,
     vehicleID: number,
   ): Promise<{ reservationsId: number } | null> {
     try {
       const query: string =
         "INSERT INTO Reservations (StartDate, EndDate, Insurance, CustomerID, Vehicle)" +
         "VALUES (?, ?, ?, ?, ?)";
       const values = [startDate, endDate, insurance, customerID, vehicleID];
       const [result]: any = await db.query(query, values);
       return result.insertId ? { reservationsId: result.insertId } : null;
     } catch (error) {
       console.error("Error creating reservation:", error);
       throw error;
     }
   }
```

This would make the method name consistent with both its behavior and the return type (`reservationsId`).

</blockquote></details>
<details>
<summary>backend/src/controllers/user-controller.ts (1)</summary><blockquote>

`5-5`: **Class should use `default` export for consistency**

The `UserController` class is using named export while other controllers (like `VehicleController`) use default export. For consistency, consider using default export here as well.



```diff
-export class UserController {
+class UserController {
   // rest of the class...
 }
+
+export default UserController;
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 9a22967623159878b3790ad6cf027cfe9decd666 and 9a7a7bfb67998e16a5af19c1fdf3a8dbbb556314.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `backend/package-lock.json` is excluded by `!**/package-lock.json`

</details>

<details>
<summary>📒 Files selected for processing (9)</summary>

* `backend/eslint.config.js` (1 hunks)
* `backend/package.json` (1 hunks)
* `backend/src/controllers/user-controller.ts` (1 hunks)
* `backend/src/controllers/vehicle-controller.ts` (2 hunks)
* `backend/src/models/user.ts` (1 hunks)
* `backend/src/models/vehicle.ts` (1 hunks)
* `backend/src/routes/user-routes.js` (0 hunks)
* `backend/src/routes/vehicles-routes.ts` (1 hunks)
* `database/setup.sql` (1 hunks)

</details>

<details>
<summary>💤 Files with no reviewable changes (1)</summary>

* backend/src/routes/user-routes.js

</details>

<details>
<summary>🔇 Additional comments (3)</summary><blockquote>

<details>
<summary>backend/src/models/vehicle.ts (1)</summary>

`2-2`: **Appropriate type change for VIN**

Changing the VIN type from number to string is correct, as Vehicle Identification Numbers are alphanumeric strings that include letters and special characters. This change aligns the type with the industry standard format for VINs.

</details>
<details>
<summary>backend/src/routes/vehicles-routes.ts (1)</summary>

`2-2`: **Fixed import path for VehicleController**

The correction of the import path is appropriate. Ensure that the vehicle-controller.js file exists and has the correct exports to avoid runtime errors.

</details>
<details>
<summary>backend/package.json (1)</summary>

`24-39`: <details>
<summary>✅ Verification successful</summary>

**Dev dependencies look appropriate for the ESLint setup**

The added ESLint-related packages match the imports in the eslint.config.js file and reflect current versions.



---

🏁 Script executed:

```shell
#!/bin/bash
# Check if the TypeScript and ESLint versions are compatible with each other
npm info @eslint/js@9.22.0 peerDependencies
npm info typescript-eslint@8.26.1 peerDependencies
```

Length of output: 160

---



</details>

**Approved: ESLint and TypeScript dev dependencies are correctly aligned**

After verifying the peer dependencies, the versions declared in `backend/package.json` for ESLint and TypeScript packages are confirmed to be compatible. Specifically:

- `@eslint/js@9.22.0` requires ESLint `^8.57.0 || ^9.0.0` and our declared `eslint@^9.22.0` fits.
- `@typescript-eslint` packages (version `8.26.1`) require TypeScript `>=4.8.4 <5.9.0` and our `typescript@^5.8.2` meets this condition.

No changes are needed.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-15T21:21:44Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>♻️ Duplicate comments (3)</summary><blockquote>

<details>
<summary>backend/src/controllers/user-controller.ts (3)</summary><blockquote>

`41-44`: _⚠️ Potential issue_

**Fix UPDATE query parameter mismatch**

The UPDATE statement has two placeholders (`?`) but only one parameter is provided in the array. Also, the reassignment of `inputSessionId` to `sessionId` is unnecessary.



```diff
-      const sessionId: string | null = inputSessionId;
       const query: string =
-        "UPDATE Sessions SET last_login = ? WHERE session_id = ?";
-      const [results] = await db.query(query, [sessionId]);
+        "UPDATE Sessions SET last_login = CURRENT_DATE() WHERE session_id = ?";
+      const [results] = await db.query(query, [inputSessionId]);
```

---

`47-49`: _⚠️ Potential issue_

**Add proper return in catch block**

The catch block doesn't return anything, which means the function will return `undefined` when an error occurs. This can lead to unexpected behavior when calling code doesn't handle this case.


```diff
    } catch (error) {
      console.error("Database error: ", error);
+      return null;
    }
```

---

`30-32`: _⚠️ Potential issue_

**Fix SQL syntax and add `last_login` column**

There are two issues with the INSERT statement:
1. It uses "VALUE" instead of "VALUES"
2. It doesn't set the `last_login` column to the current date


```diff
        const query: string =
-          "INSERT INTO Sessions (session_id, user_id, expire_login) " +
-          "VALUE (?,?,?)";
+          "INSERT INTO Sessions (session_id, user_id, expire_login, last_login) " +
+          "VALUES (?,?,?,CURRENT_DATE())";
```

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (3)</summary><blockquote>

<details>
<summary>backend/src/routes/user-routes.ts (2)</summary><blockquote>

`5-9`: **Return type should use `undefined` instead of `void` in union type**

The function's return type `Promise<Response | void>` uses `void` in a union type, which can be confusing since `void` represents the absence of a value.


```diff
 const authCheck = async (
   req: Request,
   res: Response,
   next: NextFunction,
-): Promise<Response | void> => {
+): Promise<Response | undefined> => {
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 9-9: void is confusing inside a union type.

Unsafe fix: Use undefined instead.


(lint/suspicious/noConfusingVoidType)

</details>

</details>

---

`26-29`: **Inconsistent error response formats**

The error responses are inconsistent - some use `send()` with plain text (lines 18 and 23) while others use `json()` (line 28).


```diff
-    return res.status(401).send("Unauthorized: No session ID provided");
+    return res.status(401).json({ error: "Unauthorized: No session ID provided" });

-    return res.status(401).send("Unauthorized: Invalid session ID");
+    return res.status(401).json({ error: "Unauthorized: Invalid session ID" });
```

</blockquote></details>
<details>
<summary>backend/src/controllers/user-controller.ts (1)</summary><blockquote>

`26-27`: **Remove unnecessary "Example Usage" comment**

This comment doesn't provide value and suggests that the code might be copied from elsewhere.


```diff
-        // Example Usage
         const today: Date = new Date();
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 9a7a7bfb67998e16a5af19c1fdf3a8dbbb556314 and 8d14128b56fd2ac33277b7c607ec9f897ed723bb.

</details>

<details>
<summary>📒 Files selected for processing (3)</summary>

* `backend/src/controllers/user-controller.ts` (1 hunks)
* `backend/src/routes/user-routes.js` (0 hunks)
* `backend/src/routes/user-routes.ts` (1 hunks)

</details>

<details>
<summary>💤 Files with no reviewable changes (1)</summary>

* backend/src/routes/user-routes.js

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

<details>
<summary>backend/src/routes/user-routes.ts</summary>

[error] 9-9: void is confusing inside a union type.

Unsafe fix: Use undefined instead.


(lint/suspicious/noConfusingVoidType)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (4)</summary><blockquote>

<details>
<summary>backend/src/routes/user-routes.ts (2)</summary>

`11-19`: **Good session validation implementation**

The validation logic for the session ID is thorough and secure, checking if:
1. The session ID exists
2. It has the correct type
3. It's not an empty string after trimming

This helps prevent security issues like SQL injection in downstream database operations.

---

`21-25`: **Proper session existence check**

The code correctly uses the `UserController.sessionExists` method to validate the session ID against the database before allowing the request to proceed.

</details>
<details>
<summary>backend/src/controllers/user-controller.ts (2)</summary>

`7-10`: **Add return type to `createOrUpdateSession` method**

The method is missing a return type annotation. Based on the implementation, it should return a Promise with either a string (sessionId) or null/undefined (in case of errors).


```diff
 async createOrUpdateSession(
   userId: number,
   inputSessionId: string | null = null,
-) {
+): Promise<string | null | undefined> {
```

---

`14-24`: **Move `addDaysToDate` function outside the method**

Defining this function inside the `createOrUpdateSession` method means it's recreated every time the method is called, which is inefficient.


```diff
+// Helper function to add days to a date and format as YYYY-MM-DD
+const addDaysToDate = (date: Date, days: number): string => {
+  const futureDate = new Date(date);
+  futureDate.setDate(futureDate.getDate() + days);
+
+  // Format to YYYY-MM-DD
+  const year = futureDate.getFullYear();
+  const month = String(futureDate.getMonth() + 1).padStart(2, "0");
+  const day = String(futureDate.getDate()).padStart(2, "0");
+
+  return `${year}-${month}-${day}`;
+};
+
 export class UserController {
   // updates the expire time for a session or makes a new one if no session exists
   async createOrUpdateSession(
     userId: number,
     inputSessionId: string | null = null,
   ) {
     try {
       if (!inputSessionId) {
         const sessionId: string = crypto.randomUUID();
-        const addDaysToDate = (date: Date, days: number): string => {
-          const futureDate = new Date(date);
-          futureDate.setDate(futureDate.getDate() + days);
-
-          // Format to YYYY-MM-DD
-          const year = futureDate.getFullYear();
-          const month = String(futureDate.getMonth() + 1).padStart(2, "0"); // Ensure two digits
-          const day = String(futureDate.getDate()).padStart(2, "0"); // Ensure two digits
-
-          return `${year}-${month}-${day}`;
-        };
```

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-15T22:06:05Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 8**

<details>
<summary>♻️ Duplicate comments (3)</summary><blockquote>

<details>
<summary>backend/src/models/user.ts (1)</summary><blockquote>

`10-19`: _🛠️ Refactor suggestion_

**Add password hashing and validation methods**

The User class currently only stores raw password data. For security best practices, consider enhancing the class with methods for password hashing and validation.

```diff
export class User {
  constructor(
    public userId: number,
    public firstName: string,
    public lastName: string,
    public email: string,
    public userName: string,
    public password: string,
  ) {}
+
+  // Methods to handle password securely
+  static hashPassword(password: string): Promise<string> {
+    // Implement password hashing using bcrypt or similar
+    // Example implementation would be added here
+  }
+
+  validatePassword(password: string): Promise<boolean> {
+    // Implement password validation
+    // Example implementation would be added here
+  }
}
```

</blockquote></details>
<details>
<summary>backend/src/services/user-service.ts (2)</summary><blockquote>

`44-47`: _⚠️ Potential issue_

**Fix UPDATE query parameter issue**

The UPDATE statement has two placeholders but only one parameter is provided. Additionally, the last_login value should be set to the current date.


```diff
  const query: string =
-   "UPDATE Sessions SET last_login = ? WHERE session_id = ?";
-  const [results] = await db.query(query, [sessionId]);
+   "UPDATE Sessions SET last_login = CURRENT_DATE() WHERE session_id = ?";
+  const [results] = await db.query(query, [inputSessionId]);
```

---

`54-59`: _⚠️ Potential issue_

**Improve sessionExists method with return type and error handling**

The `sessionExists` method has no return type annotation, no error handling, and the query parameter is not wrapped in an array.


```diff
-static async sessionExists(sessionId: string) {
+static async sessionExists(sessionId: string): Promise<boolean> {
+  try {
     const query: string =
       "SELECT COUNT(*) AS count FROM Sessions WHERE session_id = ?";
-    const [results]: [RowDataPacket[], any] = await db.query(query, sessionId);
+    const [results]: [RowDataPacket[], any] = await db.query(query, [sessionId]);
     return results[0].count > 0;
+  } catch (error) {
+    console.error("Database error checking session:", error);
+    return false;
+  }
}
```

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (9)</summary><blockquote>

<details>
<summary>backend/src/controllers/user-controller.ts (2)</summary><blockquote>

`11-11`: **Fix typo in error message**

There's a typo in the error message.

```diff
- res.status(400).json({ error: "No user id or password recived" });
+ res.status(400).json({ error: "No user id or password received" });
```

---

`35-35`: **Fix typo in error message**

There's a typo in the error message.

```diff
- res.status(400).json({ error: "No session id recived" });
+ res.status(400).json({ error: "No session id received" });
```

</blockquote></details>
<details>
<summary>backend/src/middlewares/auth.ts (1)</summary><blockquote>

`5-9`: **Use undefined instead of void in union type**

The Promise return type uses void in a union type which can be confusing.

```diff
export const authCheck = async (
  req: Request,
  res: Response,
  next: NextFunction,
- ): Promise<Response | void> => {
+ ): Promise<Response | undefined> => {
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 9-9: void is confusing inside a union type.

Unsafe fix: Use undefined instead.


(lint/suspicious/noConfusingVoidType)

</details>

</details>

</blockquote></details>
<details>
<summary>backend/src/services/vehicle-service.ts (2)</summary><blockquote>

`3-3`: **Remove unused import**

The `throws` import from 'assert' is not used in this file.

```diff
-import { throws } from "assert";
```

---

`28-46`: **Rename method to match its functionality**

The method is named `rentVehicle` but it creates a reservation entry. Consider renaming it to align with the returned object structure (`reservationsId`).

```diff
-  static async rentVehicle(
+  static async createReservation(
     startDate: string,
     endDate: string,
     insurance: boolean,
     customerID: number,
     vehicleID: number,
   ): Promise<{ reservationsId: number } | null> {
```

</blockquote></details>
<details>
<summary>backend/src/services/user-service.ts (4)</summary><blockquote>

`9-12`: **Add return type to createOrUpdateSession method**

The `createOrUpdateSession` method doesn't have a return type specified.

```diff
  private static async createOrUpdateSession(
    userId: number,
    inputSessionId: string | null = null,
-  ) {
+  ): Promise<string | null> {
```

---

`16-26`: **Extract addDaysToDate as a utility function**

The `addDaysToDate` function is defined inside the `createOrUpdateSession` method, making it recreated every time the method is called. It would be better as a private static method or utility function.

```diff
+ // Helper function to add days to a date and format as YYYY-MM-DD
+ private static addDaysToDate(date: Date, days: number): string {
+   const futureDate = new Date(date);
+   futureDate.setDate(futureDate.getDate() + days);
+
+   // Format to YYYY-MM-DD
+   const year = futureDate.getFullYear();
+   const month = String(futureDate.getMonth() + 1).padStart(2, "0");
+   const day = String(futureDate.getDate()).padStart(2, "0");
+
+   return `${year}-${month}-${day}`;
+ }

private static async createOrUpdateSession(
  userId: number,
  inputSessionId: string | null = null,
): Promise<string | null> {
  try {
    if (!inputSessionId) {
      const sessionId: string = crypto.randomUUID();
-     const addDaysToDate = (date: Date, days: number): string => {
-       const futureDate = new Date(date);
-       futureDate.setDate(futureDate.getDate() + days);
-
-       // Format to YYYY-MM-DD
-       const year = futureDate.getFullYear();
-       const month = String(futureDate.getMonth() + 1).padStart(2, "0"); // Ensure two digits
-       const day = String(futureDate.getDate()).padStart(2, "0"); // Ensure two digits
-
-       return `${year}-${month}-${day}`;
-     };

      // Example Usage
      const today: Date = new Date();
-     const expireLogin: string = addDaysToDate(today, 5);
+     const expireLogin: string = this.addDaysToDate(today, 5);
```

---

`43-43`: **Remove unnecessary assignment**

The reassignment of `inputSessionId` to `sessionId` is unnecessary.

```diff
-      const sessionId: string | null = inputSessionId;
       const query: string =
         "UPDATE Sessions SET last_login = ? WHERE session_id = ?";
```

---

`32-34`: **Fix typo in SQL query**

The SQL query uses `VALUE` instead of `VALUES` which may cause syntax errors in some SQL implementations.

```diff
        const query: string =
          "INSERT INTO Sessions (session_id, user_id, expire_login) " +
-         "VALUE (?,?,?)";
+         "VALUES (?,?,?)";
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 8d14128b56fd2ac33277b7c607ec9f897ed723bb and a2b0eac59325a965d5daf4f8d572d4c54a1b3c00.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `backend/package-lock.json` is excluded by `!**/package-lock.json`

</details>

<details>
<summary>📒 Files selected for processing (9)</summary>

* `backend/package.json` (1 hunks)
* `backend/src/controllers/user-controller.ts` (1 hunks)
* `backend/src/controllers/vehicle-controller.ts` (1 hunks)
* `backend/src/middlewares/auth.ts` (1 hunks)
* `backend/src/models/user.ts` (1 hunks)
* `backend/src/routes/user-routes.ts` (1 hunks)
* `backend/src/routes/vehicles-routes.ts` (1 hunks)
* `backend/src/services/user-service.ts` (1 hunks)
* `backend/src/services/vehicle-service.ts` (2 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* backend/package.json

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧠 Learnings (1)</summary>

<details>
<summary>backend/src/controllers/vehicle-controller.ts (1)</summary>

```
Learnt from: JohnathanAguilar01
PR: JohnathanAguilar01/Real-Fake-Car-Rentals#9
File: backend/src/controllers/vehicle-controler.ts:4-40
Timestamp: 2025-03-15T19:24:46.625Z
Learning: This project is meant for improving OOP skills and should follow OOP patterns rather than functional programming approaches. Suggestions should align with object-oriented design principles.
```

</details>

</details><details>
<summary>🪛 Biome (1.9.4)</summary>

<details>
<summary>backend/src/middlewares/auth.ts</summary>

[error] 9-9: void is confusing inside a union type.

Unsafe fix: Use undefined instead.


(lint/suspicious/noConfusingVoidType)

</details>
<details>
<summary>backend/src/controllers/vehicle-controller.ts</summary>

[error] 4-36: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)

</details>
<details>
<summary>backend/src/services/user-service.ts</summary>

[error] 68-68: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.


(lint/complexity/noThisInStatic)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (6)</summary><blockquote>

<details>
<summary>backend/src/models/user.ts (1)</summary>

`1-8`: _🛠️ Refactor suggestion_

**Ensure consistency between type definition properties and class properties**

The `TUser` type has an `id` property, but the `User` class constructor uses `userId`. This inconsistency could lead to type mismatches and confusion when mapping between the two.

```diff
export type TUser = {
-  id: number;
+  userId: number;
  firstName: string;
  lastName: string;
  email: string;
  userName: string;
  password: string;
};
```




> Likely an incorrect or invalid review comment.

</details>
<details>
<summary>backend/src/routes/vehicles-routes.ts (2)</summary>

`2-2`: **Fixed controller import path**

The import statement now correctly references the controller file with the proper spelling.

---

`6-8`: **Improved route handler implementation**

The route handlers have been simplified by directly using the controller methods, which is cleaner and more maintainable. Good job on improving the code organization!

</details>
<details>
<summary>backend/src/routes/user-routes.ts (2)</summary>

`1-8`: **Properly setup router with necessary middleware**

The router is correctly configured with body-parser and cookie-parser middleware for handling JSON requests and cookies, which are essential for authentication functionality.

---

`9-10`: **Authentication routes properly defined**

The login and logout routes are appropriately defined as POST methods and connected to the corresponding controller methods.

</details>
<details>
<summary>backend/src/controllers/vehicle-controller.ts (1)</summary>

`4-36`: **Implementation follows OOP patterns**

The class-based implementation with static methods aligns with the project's goal of improving OOP skills. This is good! 

The controller is properly separated from the service layer, following the separation of concerns principle, which is an important aspect of object-oriented design.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 4-36: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)

</details>

</details>

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-16T09:42:11Z
user: login: JohnathanAguilar01
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-17T00:55:43Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-17T00:56:08Z
user: login: JohnathanAguilar01
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-17T02:04:07Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-17T02:04:35Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-17T02:04:36Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-17T02:04:38Z

Review comments:
diff_hunk: @@ -0,0 +1,17 @@
+export type TUser = {
+  firstName: string;
+  lastName: string;
+  email: string;
+  userName: string;
+  password: string;
+};
path: backend/src/models/user.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add ID field to user type**

The TUser type lacks an ID field, while the database schema shows a CustomerID as the primary key. Consider adding an optional ID field to match the database structure.

```diff
export type TUser = {
+ id?: number;
  firstName: string;
  lastName: string;
  email: string;
  userName: string;
  password: string;
};
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
export type TUser = {
  id?: number;
  firstName: string;
  lastName: string;
  email: string;
  userName: string;
  password: string;
};
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-15T21:21:43Z
author_association: NONE
diff_hunk: @@ -0,0 +1,17 @@
+export type TUser = {
+  firstName: string;
+  lastName: string;
+  email: string;
+  userName: string;
+  password: string;
+};
+
+export class User {
+  constructor(
+    public firstName: string,
+    public lastName: string,
+    public email: string,
+    public userName: string,
+    public password: string,
+  ) {}
+}
path: backend/src/models/user.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

_⚠️ Potential issue_

**Add password hashing and validation methods**

The User class currently only stores raw password data. Consider enhancing the class with methods for password hashing and validation to improve security.

```diff
export class User {
  constructor(
    public firstName: string,
    public lastName: string,
    public email: string,
    public userName: string,
    public password: string,
+   public id?: number
  ) {}
+
+  // Methods to handle password securely
+  static hashPassword(password: string): Promise<string> {
+    // Implement password hashing using bcrypt or similar
+  }
+
+  validatePassword(password: string): Promise<boolean> {
+    // Implement password validation
+  }
}
```




<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
export class User {
  constructor(
    public firstName: string,
    public lastName: string,
    public email: string,
    public userName: string,
    public password: string,
    public id?: number
  ) {}

  // Methods to handle password securely
  static hashPassword(password: string): Promise<string> {
    // Implement password hashing using bcrypt or similar
  }

  validatePassword(password: string): Promise<boolean> {
    // Implement password validation
  }
}
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-03-15T21:21:43Z
author_association: NONE
diff_hunk: @@ -0,0 +1,51 @@
+import db from "../config/db.js";
+import crypto from "crypto";
+
+// biome-ignore lint/complexity/noStaticOnlyClass: This class follows OOP patterns for learning purposes
+export class UserController {
+  // updates the expire time for a session or makes a new one if no session exists
+  async createOrUpdateSession(
+    userId: number,
+    inputSessionId: string | null = null,
+  ) {
+    try {
+      if (!inputSessionId) {
+        const sessionId: string = crypto.randomUUID();
+        const addDaysToDate = (date: Date, days: number): string => {
+          const futureDate = new Date(date);
+          futureDate.setDate(futureDate.getDate() + days);
+
+          // Format to YYYY-MM-DD
+          const year = futureDate.getFullYear();
+          const month = String(futureDate.getMonth() + 1).padStart(2, "0"); // Ensure two digits
+          const day = String(futureDate.getDate()).padStart(2, "0"); // Ensure two digits
+
+          return `${year}-${month}-${day}`;
+        };
+
+        // Example Usage
+        const today: Date = new Date();
+        const expireLogin: string = addDaysToDate(today, 5);
+
+        const query: string =
+          "INSERT INTO Sessions (session_id, user_id, expire_login) " +
+          "VALUE (?,?,?)";
+        const [result]: any = await db.query(query, [
+          sessionId,
+          userId,
+          expireLogin,
+        ]);
+        console.log(result);
+        return sessionId;
+      }
+      const sessionId: string | null = inputSessionId;
+      const query: string =
+        "UPDATE Sessions SET last_login = ? WHERE session_id = ?";
+      const [result] = await db.query(query, [sessionId]);
+      console.log(result);
+      return sessionId;
+    } catch (error) {
+      console.error("Database error: ", error);
+    }
+  }
+}
path: backend/src/controllers/user-controller.ts
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**UserController implementation needs improvements**

The implementation of the `createOrUpdateSession` method has several issues that need to be addressed.



1. Missing return type on the `createOrUpdateSession` method
2. The update query doesn't set the current date for `last_login`
3. No error handling for when queries fail (just returns undefined)
4. Nested function definition is unnecessary and bloats the method

Here's a suggested improvement:

```diff
 import db from "../config/db.js";
 import crypto from "crypto";
 
+// Helper function to add days to a date and format as YYYY-MM-DD
+const addDaysToDate = (date: Date, days: number): string => {
+  const futureDate = new Date(date);
+  futureDate.setDate(futureDate.getDate() + days);
+
+  // Format to YYYY-MM-DD
+  const year = futureDate.getFullYear();
+  const month = String(futureDate.getMonth() + 1).padStart(2, "0"); 
+  const day = String(futureDate.getDate()).padStart(2, "0");
+
+  return `${year}-${month}-${day}`;
+};
+
 // biome-ignore lint/complexity/noStaticOnlyClass: This class follows OOP patterns for learning purposes
 export class UserController {
   // updates the expire time for a session or makes a new one if no session exists
   async createOrUpdateSession(
     userId: number,
     inputSessionId: string | null = null,
-  ) {
+  ): Promise<string | null> {
     try {
       if (!inputSessionId) {
         const sessionId: string = crypto.randomUUID();
-        const addDaysToDate = (date: Date, days: number): string => {
-          const futureDate = new Date(date);
-          futureDate.setDate(futureDate.getDate() + days);
-
-          // Format to YYYY-MM-DD
-          const year = futureDate.getFullYear();
-          const month = String(futureDate.getMonth() + 1).padStart(2, "0"); // Ensure two digits
-          const day = String(futureDate.getDate()).padStart(2, "0"); // Ensure two digits
-
-          return `${year}-${month}-${day}`;
-        };
-
-        // Example Usage
         const today: Date = new Date();
         const expireLogin: string = addDaysToDate(today, 5);
 
         const query: string =
-          "INSERT INTO Sessions (session_id, user_id, expire_login) " +
-          "VALUE (?,?,?)";
+          "INSERT INTO Sessions (session_id, user_id, expire_login, last_login) " +
+          "VALUES (?,?,?,CURRENT_DATE())";
         const [result]: any = await db.query(query, [
           sessionId,
           userId,
           expireLogin,
         ]);
         console.log(result);
         return sessionId;
       }
-      const sessionId: string | null = inputSessionId;
       const query: string =
-        "UPDATE Sessions SET last_login = ? WHERE session_id = ?";
-      const [result] = await db.query(query, [sessionId]);
+        "UPDATE Sessions SET last_login = CURRENT_DATE() WHERE session_id = ?";
+      const [result] = await db.query(query, [inputSessionId]);
       console.log(result);
-      return sessionId;
+      return inputSessionId;
     } catch (error) {
       console.error("Database error: ", error);
+      return null;
     }
   }
 }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
import db from "../config/db.js";
import crypto from "crypto";

// Helper function to add days to a date and format as YYYY-MM-DD
const addDaysToDate = (date: Date, days: number): string => {
  const futureDate = new Date(date);
  futureDate.setDate(futureDate.getDate() + days);

  // Format to YYYY-MM-DD
  const year = futureDate.getFullYear();
  const month = String(futureDate.getMonth() + 1).padStart(2, "0"); 
  const day = String(futureDate.getDate()).padStart(2, "0");

  return `${year}-${month}-${day}`;
};

// biome-ignore lint/complexity/noStaticOnlyClass: This class follows OOP patterns for learning purposes
export class UserController {
  // updates the expire time for a session or makes a new one if no session exists
  async createOrUpdateSession(
    userId: number,
    inputSessionId: string | null = null,
  ): Promise<string | null> {
    try {
      if (!inputSessionId) {
        const sessionId: string = crypto.randomUUID();
        const today: Date = new Date();
        const expireLogin: string = addDaysToDate(today, 5);

        const query: string =
          "INSERT INTO Sessions (session_id, user_id, expire_login, last_login) " +
          "VALUES (?,?,?,CURRENT_DATE())";
        const [result]: any = await db.query(query, [
          sessionId,
          userId,
          expireLogin,
        ]);
        console.log(result);
        return sessionId;
      }
      const query: string =
        "UPDATE Sessions SET last_login = CURRENT_DATE() WHERE session_id = ?";
      const [result] = await db.query(query, [inputSessionId]);
      console.log(result);
      return inputSessionId;
    } catch (error) {
      console.error("Database error: ", error);
      return null;
    }
  }
}
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-15T21:21:44Z
author_association: NONE
diff_hunk: @@ -0,0 +1,51 @@
+import db from "../config/db.js";
+import crypto from "crypto";
+
+// biome-ignore lint/complexity/noStaticOnlyClass: This class follows OOP patterns for learning purposes
+export class UserController {
+  // updates the expire time for a session or makes a new one if no session exists
+  async createOrUpdateSession(
+    userId: number,
+    inputSessionId: string | null = null,
+  ) {
+    try {
+      if (!inputSessionId) {
+        const sessionId: string = crypto.randomUUID();
+        const addDaysToDate = (date: Date, days: number): string => {
+          const futureDate = new Date(date);
+          futureDate.setDate(futureDate.getDate() + days);
+
+          // Format to YYYY-MM-DD
+          const year = futureDate.getFullYear();
+          const month = String(futureDate.getMonth() + 1).padStart(2, "0"); // Ensure two digits
+          const day = String(futureDate.getDate()).padStart(2, "0"); // Ensure two digits
+
+          return `${year}-${month}-${day}`;
+        };
+
+        // Example Usage
+        const today: Date = new Date();
+        const expireLogin: string = addDaysToDate(today, 5);
+
+        const query: string =
+          "INSERT INTO Sessions (session_id, user_id, expire_login) " +
+          "VALUE (?,?,?)";
+        const [result]: any = await db.query(query, [
+          sessionId,
+          userId,
+          expireLogin,
+        ]);
+        console.log(result);
+        return sessionId;
+      }
+      const sessionId: string | null = inputSessionId;
+      const query: string =
+        "UPDATE Sessions SET last_login = ? WHERE session_id = ?";
+      const [result] = await db.query(query, [sessionId]);
+      console.log(result);
+      return sessionId;
path: backend/src/controllers/user-controller.ts
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Missing parameter in UPDATE query execution**

The UPDATE statement defines two placeholders but only one parameter is provided to the query method.



```diff
       const query: string =
-        "UPDATE Sessions SET last_login = ? WHERE session_id = ?";
-      const [result] = await db.query(query, [sessionId]);
+        "UPDATE Sessions SET last_login = CURRENT_DATE() WHERE session_id = ?";
+      const [result] = await db.query(query, [inputSessionId]);
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
      const query: string =
        "UPDATE Sessions SET last_login = CURRENT_DATE() WHERE session_id = ?";
      const [result] = await db.query(query, [inputSessionId]);
      console.log(result);
      return sessionId;
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-15T21:21:44Z
author_association: NONE
diff_hunk: @@ -0,0 +1,58 @@
+import db from "../config/db.js";
+import crypto from "crypto";
+
+// biome-ignore lint/complexity/noStaticOnlyClass: This class follows OOP patterns for learning purposes
+export class UserController {
+  // updates the expire time for a session or makes a new one if no session exists
+  async createOrUpdateSession(
+    userId: number,
+    inputSessionId: string | null = null,
+  ) {
+    try {
+      if (!inputSessionId) {
+        const sessionId: string = crypto.randomUUID();
+        const addDaysToDate = (date: Date, days: number): string => {
+          const futureDate = new Date(date);
+          futureDate.setDate(futureDate.getDate() + days);
+
+          // Format to YYYY-MM-DD
+          const year = futureDate.getFullYear();
+          const month = String(futureDate.getMonth() + 1).padStart(2, "0"); // Ensure two digits
+          const day = String(futureDate.getDate()).padStart(2, "0"); // Ensure two digits
+
+          return `${year}-${month}-${day}`;
+        };
+
+        // Example Usage
+        const today: Date = new Date();
+        const expireLogin: string = addDaysToDate(today, 5);
+
+        const query: string =
+          "INSERT INTO Sessions (session_id, user_id, expire_login) " +
+          "VALUE (?,?,?)";
+        const [results] = await db.query(query, [
+          sessionId,
+          userId,
+          expireLogin,
+        ]);
+        console.log(results);
+        return sessionId;
+      }
+      const sessionId: string | null = inputSessionId;
+      const query: string =
+        "UPDATE Sessions SET last_login = ? WHERE session_id = ?";
+      const [results] = await db.query(query, [sessionId]);
+      console.log(results);
+      return sessionId;
+    } catch (error) {
+      console.error("Database error: ", error);
+    }
+  }
+
+  static async sessionExists(sessionId: string) {
+    const query: string =
+      "SELECT COUNT(*) AS count FROM Sessions WHERE session_id = ?";
+    const [results] = await db.query(query, sessionId);
+    return results[0].count > 0;
+  }
path: backend/src/controllers/user-controller.ts
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Improve `sessionExists` method with return type and error handling**

The `sessionExists` method has several issues:
1. No return type annotation
2. No error handling
3. The query parameter is not wrapped in an array


```diff
-  static async sessionExists(sessionId: string) {
+  static async sessionExists(sessionId: string): Promise<boolean> {
+    try {
       const query: string =
         "SELECT COUNT(*) AS count FROM Sessions WHERE session_id = ?";
-      const [results] = await db.query(query, sessionId);
+      const [results] = await db.query(query, [sessionId]);
       return results[0].count > 0;
+    } catch (error) {
+      console.error("Database error checking session:", error);
+      return false;
+    }
   }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  static async sessionExists(sessionId: string): Promise<boolean> {
    try {
      const query: string =
        "SELECT COUNT(*) AS count FROM Sessions WHERE session_id = ?";
      const [results] = await db.query(query, [sessionId]);
      return results[0].count > 0;
    } catch (error) {
      console.error("Database error checking session:", error);
      return false;
    }
  }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-15T22:06:04Z
author_association: NONE
diff_hunk: @@ -0,0 +1,36 @@
+import { Request, Response } from "express";
+import VehicleService from "../services/vehicle-service.js";
+
+export default class VehicleController {
+  static async getAllVehicles(req: Request, res: Response) {
+    try {
+      const vehicles = await VehicleService.getAllVehicles();
+      res.json(vehicles);
+    } catch (error) {
+      console.error(error);
+      res.status(500).send("Server error:" + error);
+    }
+  }
+
+  static async getAvailableVehicles(req: Request, res: Response) {
+    try {
+      const type: string = (req.query.type as string) ?? "";
+      const startDate: string = (req.query.startDate as string) ?? "";
+      const endDate: string = (req.query.endDate as string) ?? "";
+
+      const vehicles = await VehicleService.getAvailableVehicles(
+        type,
+        startDate,
+        endDate,
+      );
+      if (!vehicles) {
+        res.status(404).json({ error: "No cars found" });
+        return;
+      }
+      res.json(vehicles);
+    } catch (error) {
+      console.error(error);
+      res.status(500).send("Server error:" + error);
+    }
+  }
path: backend/src/controllers/vehicle-controller.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Improve vehicle availability check and error handling**

There are several improvements that can be made to this method:

1. The null check for vehicles might be inaccurate if `vehicles` is an empty array
2. Error handling should be more secure by not exposing raw error details
3. Consider validating date inputs before processing

```diff
  static async getAvailableVehicles(req: Request, res: Response) {
    try {
      const type: string = (req.query.type as string) ?? "";
      const startDate: string = (req.query.startDate as string) ?? "";
      const endDate: string = (req.query.endDate as string) ?? "";

+     // Optional: Validate date format here
+     // if (!isValidDateFormat(startDate) || !isValidDateFormat(endDate)) {
+     //   return res.status(400).json({ error: "Invalid date format" });
+     // }

      const vehicles = await VehicleService.getAvailableVehicles(
        type,
        startDate,
        endDate,
      );
-     if (!vehicles) {
+     if (!vehicles || vehicles.length === 0) {
        res.status(404).json({ error: "No cars found" });
        return;
      }
      res.json(vehicles);
    } catch (error) {
      console.error(error);
-     res.status(500).send("Server error:" + error);
+     res.status(500).json({ error: "An error occurred while searching for available vehicles" });
    }
  }
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  static async getAvailableVehicles(req: Request, res: Response) {
    try {
      const type: string = (req.query.type as string) ?? "";
      const startDate: string = (req.query.startDate as string) ?? "";
      const endDate: string = (req.query.endDate as string) ?? "";

      // Optional: Validate date format here
      // if (!isValidDateFormat(startDate) || !isValidDateFormat(endDate)) {
      //   return res.status(400).json({ error: "Invalid date format" });
      // }

      const vehicles = await VehicleService.getAvailableVehicles(
        type,
        startDate,
        endDate,
      );
      if (!vehicles || vehicles.length === 0) {
        res.status(404).json({ error: "No cars found" });
        return;
      }
      res.json(vehicles);
    } catch (error) {
      console.error(error);
      res.status(500).json({ error: "An error occurred while searching for available vehicles" });
    }
  }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-16T09:42:10Z
author_association: NONE
diff_hunk: @@ -0,0 +1,36 @@
+import { Request, Response } from "express";
+import VehicleService from "../services/vehicle-service.js";
+
+export default class VehicleController {
+  static async getAllVehicles(req: Request, res: Response) {
+    try {
+      const vehicles = await VehicleService.getAllVehicles();
+      res.json(vehicles);
+    } catch (error) {
+      console.error(error);
+      res.status(500).send("Server error:" + error);
+    }
+  }
path: backend/src/controllers/vehicle-controller.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Enhance error handling for better security**

The current error handling exposes raw error details in the response, which could potentially reveal sensitive information about your system.

```diff
  static async getAllVehicles(req: Request, res: Response) {
    try {
      const vehicles = await VehicleService.getAllVehicles();
      res.json(vehicles);
    } catch (error) {
      console.error(error);
-     res.status(500).send("Server error:" + error);
+     res.status(500).json({ error: "An error occurred while fetching vehicles" });
    }
  }
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
export default class VehicleController {
  static async getAllVehicles(req: Request, res: Response) {
    try {
      const vehicles = await VehicleService.getAllVehicles();
      res.json(vehicles);
    } catch (error) {
      console.error(error);
      res.status(500).json({ error: "An error occurred while fetching vehicles" });
    }
  }
}
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 4-36: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-16T09:42:10Z
author_association: NONE
diff_hunk: @@ -0,0 +1,40 @@
+import { Request, Response } from "express";
+import UserService from "../services/user-service.js";
+import { TUser } from "../models/user.js";
+
+// biome-ignore lint/complexity/noStaticOnlyClass: This class follows OOP patterns for learning purposes
+export default class UserController {
+  static async login(req: Request, res: Response) {
+    try {
+      const { id, password }: Pick<TUser, "id" | "password"> = req.body;
+      if (!id || !password) {
+        res.status(400).json({ error: "No user id or password recived" });
+        return;
+      }
+      const sessionid = await UserService.login(id, password);
+      if (!sessionid) {
+        res.status(401).json({ error: "User not found" });
+        return;
+      }
+      res.cookie("sessionid", String(sessionid), {
+        secure: true,
+        httpOnly: true,
+        sameSite: "none",
+      });
+      res.json({ user: { id } });
+      return;
+    } catch (error) {
+      console.error("Login error:", error);
+      res.status(500).send("Internal server error");
+    }
+  }
+
+  static async logout(req: Request, res: Response) {
+    const sessionid = req.cookies.sessionid;
+    if (!sessionid) {
+      res.status(400).json({ error: "No session id recived" });
+    }
+    res.clearCookie("sessionid");
+    res.sendStatus(200);
+  }
path: backend/src/controllers/user-controller.ts
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Missing return statement in logout method**

The logout method doesn't return after setting the 400 status response, which means it will continue execution and clear the cookie even when no session ID exists.

Apply this fix:

```diff
  static async logout(req: Request, res: Response) {
    const sessionid = req.cookies.sessionid;
    if (!sessionid) {
      res.status(400).json({ error: "No session id recived" });
+     return;
    }
    res.clearCookie("sessionid");
    res.sendStatus(200);
  }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  static async logout(req: Request, res: Response) {
    const sessionid = req.cookies.sessionid;
    if (!sessionid) {
      res.status(400).json({ error: "No session id recived" });
      return;
    }
    res.clearCookie("sessionid");
    res.sendStatus(200);
  }
`````

</details>

<!-- suggestion_end -->

---

_⚠️ Potential issue_

**Logout should call UserService.logout**

The logout method clears the cookie but doesn't remove the session from the database by calling UserService.logout.

Apply this fix:

```diff
  static async logout(req: Request, res: Response) {
    const sessionid = req.cookies.sessionid;
    if (!sessionid) {
      res.status(400).json({ error: "No session id recived" });
      return;
    }
+   try {
+     await UserService.logout(sessionid);
      res.clearCookie("sessionid");
      res.sendStatus(200);
+   } catch (error) {
+     console.error("Logout error:", error);
+     res.status(500).send("Internal server error");
+   }
  }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  static async logout(req: Request, res: Response) {
    const sessionid = req.cookies.sessionid;
    if (!sessionid) {
      res.status(400).json({ error: "No session id recived" });
      return;
    }
    try {
      await UserService.logout(sessionid);
      res.clearCookie("sessionid");
      res.sendStatus(200);
    } catch (error) {
      console.error("Logout error:", error);
      res.status(500).send("Internal server error");
    }
  }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-16T09:42:10Z
author_association: NONE
diff_hunk: @@ -0,0 +1,30 @@
+import { Request, Response, NextFunction } from "express";
+import UserService from "../services/user-service.js";
+
+// middleware to check if user is logged in
+export const authCheck = async (
+  req: Request,
+  res: Response,
+  next: NextFunction,
+): Promise<Response | void> => {
+  try {
+    const sessionid = req.cookies.sessionid;
+    // Ensure sessionid is present and valid
+    if (
+      !sessionid ||
+      typeof sessionid !== "string" ||
+      sessionid.trim() === ""
+    ) {
+      return res.status(401).send("Unauthorized: No session ID provided");
+    }
+
+    const exists: boolean = await UserService.sessionExists(sessionid);
+    if (!exists) {
+      return res.status(401).send("Unauthorized: Invalid session ID");
+    }
path: backend/src/middlewares/auth.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add session expiration check**

The current implementation checks if a session exists but doesn't verify if it has expired.

```diff
  const exists: boolean = await UserService.sessionExists(sessionid);
  if (!exists) {
    return res.status(401).send("Unauthorized: Invalid session ID");
  }
+ const isExpired: boolean = await UserService.isSessionExpired(sessionid);
+ if (isExpired) {
+   return res.status(401).send("Unauthorized: Session expired");
+ }
  next();
```

Consider adding an `isSessionExpired` method to the UserService class that checks if the current date is past the expire_login date.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    const exists: boolean = await UserService.sessionExists(sessionid);
    if (!exists) {
      return res.status(401).send("Unauthorized: Invalid session ID");
    }
    const isExpired: boolean = await UserService.isSessionExpired(sessionid);
    if (isExpired) {
      return res.status(401).send("Unauthorized: Session expired");
    }
    next();
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-03-16T09:42:10Z
author_association: NONE
diff_hunk: @@ -0,0 +1,79 @@
+import db from "../config/db.js";
+import { RowDataPacket } from "mysql2";
+import crypto from "crypto";
+import bcrypt from "bcrypt";
+
+// biome-ignore lint/complexity/noStaticOnlyClass: This class follows OOP patterns for learning purposes
+export default class UserService {
+  // updates the expire time for a session or makes a new one if no session exists
+  private static async createOrUpdateSession(
+    userId: number,
+    inputSessionId: string | null = null,
+  ) {
+    try {
+      if (!inputSessionId) {
+        const sessionId: string = crypto.randomUUID();
+        const addDaysToDate = (date: Date, days: number): string => {
+          const futureDate = new Date(date);
+          futureDate.setDate(futureDate.getDate() + days);
+
+          // Format to YYYY-MM-DD
+          const year = futureDate.getFullYear();
+          const month = String(futureDate.getMonth() + 1).padStart(2, "0"); // Ensure two digits
+          const day = String(futureDate.getDate()).padStart(2, "0"); // Ensure two digits
+
+          return `${year}-${month}-${day}`;
+        };
+
+        // Example Usage
+        const today: Date = new Date();
+        const expireLogin: string = addDaysToDate(today, 5);
+
+        const query: string =
+          "INSERT INTO Sessions (session_id, user_id, expire_login) " +
+          "VALUE (?,?,?)";
+        const [results] = await db.query(query, [
+          sessionId,
+          userId,
+          expireLogin,
+        ]);
+        console.log(results);
+        return sessionId;
+      }
+      const sessionId: string | null = inputSessionId;
+      const query: string =
+        "UPDATE Sessions SET last_login = ? WHERE session_id = ?";
+      const [results] = await db.query(query, [sessionId]);
+      console.log(results);
+      return sessionId;
+    } catch (error) {
+      console.error("Database error: ", error);
+    }
path: backend/src/services/user-service.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add return null in catch block**

The catch block in `createOrUpdateSession` doesn't return anything. Add an explicit return null to handle errors properly.

```diff
    } catch (error) {
      console.error("Database error: ", error);
+     return null;
    }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    } catch (error) {
      console.error("Database error: ", error);
      return null;
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-03-16T09:42:10Z
author_association: NONE
diff_hunk: @@ -0,0 +1,79 @@
+import db from "../config/db.js";
+import { RowDataPacket } from "mysql2";
+import crypto from "crypto";
+import bcrypt from "bcrypt";
+
+// biome-ignore lint/complexity/noStaticOnlyClass: This class follows OOP patterns for learning purposes
+export default class UserService {
+  // updates the expire time for a session or makes a new one if no session exists
+  private static async createOrUpdateSession(
+    userId: number,
+    inputSessionId: string | null = null,
+  ) {
+    try {
+      if (!inputSessionId) {
+        const sessionId: string = crypto.randomUUID();
+        const addDaysToDate = (date: Date, days: number): string => {
+          const futureDate = new Date(date);
+          futureDate.setDate(futureDate.getDate() + days);
+
+          // Format to YYYY-MM-DD
+          const year = futureDate.getFullYear();
+          const month = String(futureDate.getMonth() + 1).padStart(2, "0"); // Ensure two digits
+          const day = String(futureDate.getDate()).padStart(2, "0"); // Ensure two digits
+
+          return `${year}-${month}-${day}`;
+        };
+
+        // Example Usage
+        const today: Date = new Date();
+        const expireLogin: string = addDaysToDate(today, 5);
+
+        const query: string =
+          "INSERT INTO Sessions (session_id, user_id, expire_login) " +
+          "VALUE (?,?,?)";
+        const [results] = await db.query(query, [
+          sessionId,
+          userId,
+          expireLogin,
+        ]);
+        console.log(results);
+        return sessionId;
+      }
+      const sessionId: string | null = inputSessionId;
+      const query: string =
+        "UPDATE Sessions SET last_login = ? WHERE session_id = ?";
+      const [results] = await db.query(query, [sessionId]);
+      console.log(results);
+      return sessionId;
+    } catch (error) {
+      console.error("Database error: ", error);
+    }
+  }
+
+  static async sessionExists(sessionId: string) {
+    const query: string =
+      "SELECT COUNT(*) AS count FROM Sessions WHERE session_id = ?";
+    const [results]: [RowDataPacket[], any] = await db.query(query, sessionId);
+    return results[0].count > 0;
+  }
+
+  static async login(userId: number, password: string) {
+    const query = "SELECT Password FROM Customers WHERE user_id = ?";
+    const [results]: [RowDataPacket[], any] = await db.execute(query, userId);
+    const storedHash = results[0].Password; // Notice capital P if it's case-sensitive
+
+    const isMatch = await bcrypt.compare(password, storedHash);
+    if (isMatch) {
+      const sessionid = await this.createOrUpdateSession(userId);
+      return sessionid;
+    }
+    return null;
+  }
path: backend/src/services/user-service.ts
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Fix query parameter issue in login method**

The `userId` parameter in the execute call is not wrapped in an array.

```diff
static async login(userId: number, password: string) {
  const query = "SELECT Password FROM Customers WHERE user_id = ?";
-  const [results]: [RowDataPacket[], any] = await db.execute(query, userId);
+  const [results]: [RowDataPacket[], any] = await db.execute(query, [userId]);
  const storedHash = results[0].Password; // Notice capital P if it's case-sensitive

  const isMatch = await bcrypt.compare(password, storedHash);
  if (isMatch) {
-    const sessionid = await this.createOrUpdateSession(userId);
+    const sessionid = await UserService.createOrUpdateSession(userId);
    return sessionid;
  }
  return null;
}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  static async login(userId: number, password: string) {
    const query = "SELECT Password FROM Customers WHERE user_id = ?";
    const [results]: [RowDataPacket[], any] = await db.execute(query, [userId]);
    const storedHash = results[0].Password; // Notice capital P if it's case-sensitive

    const isMatch = await bcrypt.compare(password, storedHash);
    if (isMatch) {
      const sessionid = await UserService.createOrUpdateSession(userId);
      return sessionid;
    }
    return null;
  }
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 68-68: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.


(lint/complexity/noThisInStatic)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-16T09:42:10Z
author_association: NONE
diff_hunk: @@ -0,0 +1,79 @@
+import db from "../config/db.js";
+import { RowDataPacket } from "mysql2";
+import crypto from "crypto";
+import bcrypt from "bcrypt";
+
+// biome-ignore lint/complexity/noStaticOnlyClass: This class follows OOP patterns for learning purposes
+export default class UserService {
+  // updates the expire time for a session or makes a new one if no session exists
+  private static async createOrUpdateSession(
+    userId: number,
+    inputSessionId: string | null = null,
+  ) {
+    try {
+      if (!inputSessionId) {
+        const sessionId: string = crypto.randomUUID();
+        const addDaysToDate = (date: Date, days: number): string => {
+          const futureDate = new Date(date);
+          futureDate.setDate(futureDate.getDate() + days);
+
+          // Format to YYYY-MM-DD
+          const year = futureDate.getFullYear();
+          const month = String(futureDate.getMonth() + 1).padStart(2, "0"); // Ensure two digits
+          const day = String(futureDate.getDate()).padStart(2, "0"); // Ensure two digits
+
+          return `${year}-${month}-${day}`;
+        };
+
+        // Example Usage
+        const today: Date = new Date();
+        const expireLogin: string = addDaysToDate(today, 5);
+
+        const query: string =
+          "INSERT INTO Sessions (session_id, user_id, expire_login) " +
+          "VALUE (?,?,?)";
+        const [results] = await db.query(query, [
+          sessionId,
+          userId,
+          expireLogin,
+        ]);
+        console.log(results);
+        return sessionId;
+      }
+      const sessionId: string | null = inputSessionId;
+      const query: string =
+        "UPDATE Sessions SET last_login = ? WHERE session_id = ?";
+      const [results] = await db.query(query, [sessionId]);
+      console.log(results);
+      return sessionId;
+    } catch (error) {
+      console.error("Database error: ", error);
+    }
+  }
+
+  static async sessionExists(sessionId: string) {
+    const query: string =
+      "SELECT COUNT(*) AS count FROM Sessions WHERE session_id = ?";
+    const [results]: [RowDataPacket[], any] = await db.query(query, sessionId);
+    return results[0].count > 0;
+  }
+
+  static async login(userId: number, password: string) {
+    const query = "SELECT Password FROM Customers WHERE user_id = ?";
+    const [results]: [RowDataPacket[], any] = await db.execute(query, userId);
+    const storedHash = results[0].Password; // Notice capital P if it's case-sensitive
+
+    const isMatch = await bcrypt.compare(password, storedHash);
+    if (isMatch) {
+      const sessionid = await this.createOrUpdateSession(userId);
+      return sessionid;
+    }
+    return null;
+  }
+
+  static async logout(sessionId: string) {
+    const query: string = "DELETE FROM Sessions WHERE session_id = ?";
+    const [results]: any = await db.query(query, sessionId);
+    return results.affectedRows;
+  }
path: backend/src/services/user-service.ts
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Fix query parameter issue in logout method**

The `sessionId` parameter in the query call is not wrapped in an array.

```diff
static async logout(sessionId: string) {
  const query: string = "DELETE FROM Sessions WHERE session_id = ?";
-  const [results]: any = await db.query(query, sessionId);
+  const [results]: any = await db.query(query, [sessionId]);
  return results.affectedRows;
}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  static async logout(sessionId: string) {
    const query: string = "DELETE FROM Sessions WHERE session_id = ?";
    const [results]: any = await db.query(query, [sessionId]);
    return results.affectedRows;
  }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-16T09:42:10Z
author_association: NONE
diff_hunk: @@ -0,0 +1,17 @@
+export type TUser = {
+  firstName: string;
+  lastName: string;
+  email: string;
+  userName: string;
+  password: string;
+};
+
+export class User {
+  constructor(
+    public firstName: string,
+    public lastName: string,
+    public email: string,
+    public userName: string,
+    public password: string,
+  ) {}
+}
path: backend/src/models/user.ts
user: login: JohnathanAguilar01
body: Should I store both raw and have a function to hash it or should I just hash it then store the hashed password?

created_at: 2025-03-17T00:55:43Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,17 @@
+export type TUser = {
+  firstName: string;
+  lastName: string;
+  email: string;
+  userName: string;
+  password: string;
+};
+
+export class User {
+  constructor(
+    public firstName: string,
+    public lastName: string,
+    public email: string,
+    public userName: string,
+    public password: string,
+  ) {}
+}
path: backend/src/models/user.ts
user: login: coderabbitai[bot]
body: @JohnathanAguilar01 You should **only store the hashed password**. Never store raw passwords in your database. This is a critical security best practice.

Here's how the workflow should go:
1. When a user registers or changes their password, immediately hash it
2. Store only the hashed version in the database
3. For login validation, hash the incoming password and compare it with the stored hash

Let me show you how to implement this with bcrypt:

```typescript
import bcrypt from 'bcrypt';

export class User {
  constructor(
    public firstName: string,
    public lastName: string,
    public email: string,
    public userName: string,
    public password: string, // This should be the hashed password
    public id?: number
  ) {}

  // Static method to hash passwords before creating user
  static async hashPassword(password: string): Promise<string> {
    const saltRounds = 10;
    return bcrypt.hash(password, saltRounds);
  }

  // Method to validate password during login
  async validatePassword(candidatePassword: string): Promise<boolean> {
    return bcrypt.compare(candidatePassword, this.password);
  }
  
  // Static method to create a user with a hashed password
  static async createWithHashedPassword(userData: Omit<TUser, 'password'> & { password: string }): Promise<User> {
    const hashedPassword = await User.hashPassword(userData.password);
    return new User(
      userData.firstName,
      userData.lastName,
      userData.email,
      userData.userName,
      hashedPassword,
      userData.id
    );
  }
}
```

This approach ensures you never store plaintext passwords anywhere in your system.

---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: JohnathanAguilar01
PR: JohnathanAguilar01/Real-Fake-Car-Rentals#10
File: backend/src/models/user.ts:0-0
Timestamp: 2025-03-17T00:56:07.235Z
Learning: Never store raw passwords in the database. Only store password hashes. Use bcrypt for password hashing in the application with a recommended salt rounds value of 10.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-03-17T00:56:08Z
author_association: NONE
diff_hunk: @@ -0,0 +1,30 @@
+import { Request, Response, NextFunction } from "express";
+import UserService from "../services/user-service.js";
+
+// middleware to check if user is logged in
+export const authCheck = async (
+  req: Request,
+  res: Response,
+  next: NextFunction,
+): Promise<Response | void> => {
+  try {
+    const sessionid = req.cookies.sessionid;
+    // Ensure sessionid is present and valid
+    if (
+      !sessionid ||
+      typeof sessionid !== "string" ||
+      sessionid.trim() === ""
+    ) {
+      return res.status(401).send("Unauthorized: No session ID provided");
+    }
+
+    const exists: boolean = await UserService.sessionExists(sessionid);
+    if (!exists) {
+      return res.status(401).send("Unauthorized: Invalid session ID");
+    }
path: backend/src/middlewares/auth.ts
user: login: JohnathanAguilar01
body: I am gonna have the database delete any expired sessions so no need to check if they are expired.
created_at: 2025-03-17T01:19:11Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,79 @@
+import db from "../config/db.js";
+import { RowDataPacket } from "mysql2";
+import crypto from "crypto";
+import bcrypt from "bcrypt";
+
+// biome-ignore lint/complexity/noStaticOnlyClass: This class follows OOP patterns for learning purposes
+export default class UserService {
+  // updates the expire time for a session or makes a new one if no session exists
+  private static async createOrUpdateSession(
+    userId: number,
+    inputSessionId: string | null = null,
+  ) {
+    try {
+      if (!inputSessionId) {
+        const sessionId: string = crypto.randomUUID();
+        const addDaysToDate = (date: Date, days: number): string => {
+          const futureDate = new Date(date);
+          futureDate.setDate(futureDate.getDate() + days);
+
+          // Format to YYYY-MM-DD
+          const year = futureDate.getFullYear();
+          const month = String(futureDate.getMonth() + 1).padStart(2, "0"); // Ensure two digits
+          const day = String(futureDate.getDate()).padStart(2, "0"); // Ensure two digits
+
+          return `${year}-${month}-${day}`;
+        };
+
+        // Example Usage
+        const today: Date = new Date();
+        const expireLogin: string = addDaysToDate(today, 5);
+
+        const query: string =
+          "INSERT INTO Sessions (session_id, user_id, expire_login) " +
+          "VALUE (?,?,?)";
+        const [results] = await db.query(query, [
+          sessionId,
+          userId,
+          expireLogin,
+        ]);
+        console.log(results);
+        return sessionId;
+      }
+      const sessionId: string | null = inputSessionId;
+      const query: string =
+        "UPDATE Sessions SET last_login = ? WHERE session_id = ?";
+      const [results] = await db.query(query, [sessionId]);
+      console.log(results);
+      return sessionId;
+    } catch (error) {
+      console.error("Database error: ", error);
+    }
path: backend/src/services/user-service.ts
user: login: JohnathanAguilar01
body: should I not throw an error instead?
created_at: 2025-03-17T01:20:45Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,17 @@
+export type TUser = {
+  firstName: string;
+  lastName: string;
+  email: string;
+  userName: string;
+  password: string;
+};
+
+export class User {
+  constructor(
+    public firstName: string,
+    public lastName: string,
+    public email: string,
+    public userName: string,
+    public password: string,
+  ) {}
+}
path: backend/src/models/user.ts
user: login: JohnathanAguilar01
body: why are you omitting the password to just put it back with the same data type?
created_at: 2025-03-17T01:53:02Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,17 @@
+export type TUser = {
+  firstName: string;
+  lastName: string;
+  email: string;
+  userName: string;
+  password: string;
+};
+
+export class User {
+  constructor(
+    public firstName: string,
+    public lastName: string,
+    public email: string,
+    public userName: string,
+    public password: string,
+  ) {}
+}
path: backend/src/models/user.ts
user: login: coderabbitai[bot]
body: @JohnathanAguilar01 You're right to question that! The `Omit<TUser, 'password'> & { password: string }` type construct was unnecessarily complex. I was trying to semantically indicate that the password parameter is a raw password (to be hashed) rather than an already-hashed password, but since both are strings, it ends up being redundant and confusing.

A clearer approach would be:

```typescript
// More straightforward typing
static async createWithHashedPassword(userData: TUser): Promise<User> {
  // Hash the raw password that was passed in
  const hashedPassword = await User.hashPassword(userData.password);
  
  return new User(
    userData.firstName,
    userData.lastName,
    userData.email,
    userData.userName,
    hashedPassword,
    userData.id
  );
}
```

Or better yet, make the intention explicit:

```typescript
static async createWithHashedPassword(
  firstName: string,
  lastName: string,
  email: string,
  userName: string,
  rawPassword: string, // Name indicates this is the raw password
  id?: number
): Promise<User> {
  const hashedPassword = await User.hashPassword(rawPassword);
  return new User(firstName, lastName, email, userName, hashedPassword, id);
}
```

Thanks for pointing this out!

---

<details>
<summary>🧠 Learnings used</summary>

```
Learnt from: JohnathanAguilar01
PR: JohnathanAguilar01/Real-Fake-Car-Rentals#10
File: backend/src/models/user.ts:0-0
Timestamp: 2025-03-17T00:56:07.667Z
Learning: Never store raw passwords in the database. Only store password hashes. Use bcrypt for password hashing in the application with a recommended salt rounds value of 10.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-03-17T02:04:35Z
author_association: NONE
diff_hunk: @@ -0,0 +1,79 @@
+import db from "../config/db.js";
+import { RowDataPacket } from "mysql2";
+import crypto from "crypto";
+import bcrypt from "bcrypt";
+
+// biome-ignore lint/complexity/noStaticOnlyClass: This class follows OOP patterns for learning purposes
+export default class UserService {
+  // updates the expire time for a session or makes a new one if no session exists
+  private static async createOrUpdateSession(
+    userId: number,
+    inputSessionId: string | null = null,
+  ) {
+    try {
+      if (!inputSessionId) {
+        const sessionId: string = crypto.randomUUID();
+        const addDaysToDate = (date: Date, days: number): string => {
+          const futureDate = new Date(date);
+          futureDate.setDate(futureDate.getDate() + days);
+
+          // Format to YYYY-MM-DD
+          const year = futureDate.getFullYear();
+          const month = String(futureDate.getMonth() + 1).padStart(2, "0"); // Ensure two digits
+          const day = String(futureDate.getDate()).padStart(2, "0"); // Ensure two digits
+
+          return `${year}-${month}-${day}`;
+        };
+
+        // Example Usage
+        const today: Date = new Date();
+        const expireLogin: string = addDaysToDate(today, 5);
+
+        const query: string =
+          "INSERT INTO Sessions (session_id, user_id, expire_login) " +
+          "VALUE (?,?,?)";
+        const [results] = await db.query(query, [
+          sessionId,
+          userId,
+          expireLogin,
+        ]);
+        console.log(results);
+        return sessionId;
+      }
+      const sessionId: string | null = inputSessionId;
+      const query: string =
+        "UPDATE Sessions SET last_login = ? WHERE session_id = ?";
+      const [results] = await db.query(query, [sessionId]);
+      console.log(results);
+      return sessionId;
+    } catch (error) {
+      console.error("Database error: ", error);
+    }
path: backend/src/services/user-service.ts
user: login: coderabbitai[bot]
body: @JohnathanAguilar01 Yes, throwing an error is a valid approach and might be more appropriate in this case. It depends on your error handling strategy:

```diff
    } catch (error) {
      console.error("Database error: ", error);
      throw error; // Re-throw the error for upstream handling
    }
```

**Throwing an error:**
- Makes the error visible to calling methods, forcing them to handle it
- Provides full error context to upstream handlers
- Follows "fail-fast" principle
- Better when failures are exceptional and should interrupt normal flow

**Returning null (my original suggestion):**
- Allows silent failure with logging
- Calling code must check for null returns
- More contained error handling
- Better when failures are expected and should be handled gracefully

Since this is a critical authentication function, throwing the error is likely better as it ensures authentication failures aren't silently ignored.

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-03-17T02:04:36Z
author_association: NONE
diff_hunk: @@ -0,0 +1,30 @@
+import { Request, Response, NextFunction } from "express";
+import UserService from "../services/user-service.js";
+
+// middleware to check if user is logged in
+export const authCheck = async (
+  req: Request,
+  res: Response,
+  next: NextFunction,
+): Promise<Response | void> => {
+  try {
+    const sessionid = req.cookies.sessionid;
+    // Ensure sessionid is present and valid
+    if (
+      !sessionid ||
+      typeof sessionid !== "string" ||
+      sessionid.trim() === ""
+    ) {
+      return res.status(401).send("Unauthorized: No session ID provided");
+    }
+
+    const exists: boolean = await UserService.sessionExists(sessionid);
+    if (!exists) {
+      return res.status(401).send("Unauthorized: Invalid session ID");
+    }
path: backend/src/middlewares/auth.ts
user: login: coderabbitai[bot]
body: @JohnathanAguilar01 I understand your approach. Having the database automatically delete expired sessions is an efficient strategy that eliminates the need for a separate expiration check in the middleware. The existing `sessionExists` check will be sufficient since expired sessions won't be present in the database at all.

---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: JohnathanAguilar01
PR: JohnathanAguilar01/Real-Fake-Car-Rentals#10
File: backend/src/middlewares/auth.ts:21-24
Timestamp: 2025-03-17T02:04:33.328Z
Learning: In the Real-Fake-Car-Rentals project, expired user sessions are automatically deleted at the database level rather than being checked for expiration in the auth middleware.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-03-17T02:04:38Z
author_association: NONE

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-03-15T21:18:23Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

This pull request introduces several backend improvements. A new ESLint configuration file and updated dependencies are added for linting and type checking in JavaScript/TypeScript projects. The session management functionality is refactored by adding a new `UserController` and removing redundant code from routes. Updates to the vehicle controller adjust the return type and error handling. New user types and classes are established, and the vehicle model is modified to use a string for VIN numbers. Finally, an SQL column for last login is added to the Sessions table.

## Changes

| File(s) | Change Summary |
|---------|----------------|
| `backend/eslint.config.js`<br>`backend/package.json` | Added new ESLint configuration importing `globals`, `@eslint/js`, and `typescript-eslint`; added corresponding dev dependencies in package.json. |
| `backend/src/controllers/user-controller.ts`<br>`backend/src/controllers/vehicle-controller.ts` | Introduced new `UserController` with `login` and `logout` methods; added `VehicleController` with `getAllVehicles` and `getAvailableVehicles` methods. |
| `backend/src/models/user.ts`<br>`backend/src/models/vehicle.ts` | Added new user type (`TUser`) and `User` class; updated the `vin` property in the Vehicle model from a number to a string. |
| `backend/src/routes/user-routes.js`<br>`backend/src/routes/vehicles-routes.ts` | Removed redundant session management function from `user-routes.js`; fixed a typo in the import path for `VehicleController` in `vehicles-routes.ts`. |
| `database/setup.sql` | Modified the `Sessions` table by adding a new `LastLogin DATE` column. |
| `backend/src/routes/user-routes.ts` | Introduced new router for user authentication with routes for `login` and `logout`, including middleware for JSON and cookie parsing. |
| `backend/src/middlewares/auth.ts` | Added new middleware function `authCheck` to verify user session validity. |
| `backend/src/services/user-service.ts`<br>`backend/src/services/vehicle-service.ts` | Introduced `UserService` class with methods for session management; refactored `VehicleController` into `VehicleService` with updated method signatures. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Client
    participant UserController
    participant Database

    Client->>UserController: call login(id, password)
    alt credentials valid
        UserController->>Database: Verify user credentials
        Database-->>UserController: Return user data
        UserController->>UserController: Set session cookie
        UserController-->>Client: Return user ID
    else credentials invalid
        UserController-->>Client: Return 401 Unauthorized
    end
```

## Possibly related PRs

- **JohnathanAguilar01/Real-Fake-Car-Rentals#9:** The changes in the main PR, particularly the introduction of the `UserController` class and its methods, are related to the modifications in the retrieved PR, which also includes a `VehicleController` class with similar method structures for handling vehicle-related requests.

## Poem

> I'm a coding rabbit, hopping through the code,  
> Session changes lead the way on this exciting road.  
> ESLint guides my leaps, and controllers set the pace,  
> VINs now sing in strings, in a well-refactored space.  
> SQL tables get a boost with a new date in sight—  
> Hop on, code friends, let's keep our code light! 🐰✨

<!-- walkthrough_end -->
<!-- This is an auto-generated comment: all tool run failures by coderabbit.ai -->

> [!WARNING]
> There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.
> 
> <details>
> <summary>🔧 ESLint</summary>
> 
> > If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.
> 
> <details>
> <summary>backend/src/controllers/user-controller.ts</summary>
> 
> 
> Oops! Something went wrong! :(
> 
> ESLint: 9.16.0
> 
> ESLint couldn't find an eslint.config.(js|mjs|cjs) file.
> 
> From ESLint v9.0.0, the default configuration file is now eslint.config.js.
> If you are using a .eslintrc.* file, please follow the migration guide
> to update your configuration file to the new format:
> 
> https://eslint.org/docs/latest/use/configure/migration-guide
> 
> If you still have problems after following the migration guide, please stop by
> https://eslint.org/chat/help to chat with the team.
> 
> 
> </details>
> 
> <details>
> <summary>backend/src/routes/user-routes.ts</summary>
> 
> 
> Oops! Something went wrong! :(
> 
> ESLint: 9.16.0
> 
> ESLint couldn't find an eslint.config.(js|mjs|cjs) file.
> 
> From ESLint v9.0.0, the default configuration file is now eslint.config.js.
> If you are using a .eslintrc.* file, please follow the migration guide
> to update your configuration file to the new format:
> 
> https://eslint.org/docs/latest/use/configure/migration-guide
> 
> If you still have problems after following the migration guide, please stop by
> https://eslint.org/chat/help to chat with the team.
> 
> 
> </details>
> 
> <details>
> <summary>backend/src/controllers/vehicle-controller.ts</summary>
> 
> 
> Oops! Something went wrong! :(
> 
> ESLint: 9.16.0
> 
> ESLint couldn't find an eslint.config.(js|mjs|cjs) file.
> 
> From ESLint v9.0.0, the default configuration file is now eslint.config.js.
> If you are using a .eslintrc.* file, please follow the migration guide
> to update your configuration file to the new format:
> 
> https://eslint.org/docs/latest/use/configure/migration-guide
> 
> If you still have problems after following the migration guide, please stop by
> https://eslint.org/chat/help to chat with the team.
> 
> 
> </details>
> 
> + 5 others
> 
> </details>

<!-- end of auto-generated comment: all tool run failures by coderabbit.ai -->

<!-- announcements_start -->

> [!TIP]
> <details>
> <summary>⚡🧪 Multi-step agentic review comment chat (experimental)</summary>
> 
> - We're introducing multi-step agentic chat in review comments. This experimental feature enhances review discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments.
> 						- To enable this feature, set early_access to true under in the settings.
> 
> </details>

<!-- announcements_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=JohnathanAguilar01/Real-Fake-Car-Rentals&utm_content=10):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: JohnathanAguilar01
created_at: 2025-03-17T01:28:04Z
body: @coderabbitai review
author_association: OWNER
user: login: coderabbitai[bot]
created_at: 2025-03-17T01:28:09Z
body: <!-- This is an auto-generated reply by CodeRabbit -->
<details>
<summary>:white_check_mark: Actions performed</summary>

Review triggered.

> Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

</details>
author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-03-17T01:28:25Z
body: <!-- This is an auto-generated reply by CodeRabbit -->
<details>
<summary>🧩 Analysis chain</summary>

🏁 Script executed:
```
#!/bin/bash
# Fetch comments on PR #10
gh pr view 10 --json comments --jq '.comments[]' 2>/dev/null || echo "Failed to fetch comments"
```

Length of output: 22136

---

🏁 Script executed:
```
#!/bin/bash
# Check if the eslint.config.js file exists and view its content
cat backend/eslint.config.js 2>/dev/null || echo "ESLint config file not found"

# Check the structure of the backend directory to see how the files are organized
find backend -type f -name "*.js" -o -name "*.ts" | sort | head -n 20
```

Length of output: 908

---



</details>

@JohnathanAguilar01 I've reviewed the PR and noticed the ESLint configuration issues in the automated code review. The new ESLint config file (`backend/eslint.config.js`) appears to be correctly structured for ESLint v9, but the tool is failing to find it when running.

Looking at the error messages in the automated review:
```
ESLint couldn't find an eslint.config.(js|mjs|cjs) file.
From ESLint v9.0.0, the default configuration file is now eslint.config.js.
```

This is likely happening because:
1. The CodeRabbit ESLint runner might be looking in a different directory than where your config is located
2. There might be a path resolution issue within the CI/CD environment

To fix this issue, you could:
1. Make sure your `package.json` has the correct ESLint script configuration pointing to the right location
2. Consider adding an ESLint configuration file at the repository root level if the tools are being run from there
3. Or disable the ESLint check in CodeRabbit until the configuration is fully working

The actual code changes look good - I particularly like how you've structured the user model and controller!

<details>
<summary>:white_check_mark: Actions performed</summary>

Review triggered.

> Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

</details>
author_association: NONE