diff --git a/middleware/auth.js b/middleware/auth.js index 7deb650..36ad902 100644 --- a/middleware/auth.js +++ b/middleware/auth.js @@ -1,3 +1,45 @@ +// import jwt from "jsonwebtoken"; +// import prisma from "../lib/prisma.js"; + +// const JWT_SECRET = process.env.JWT_SECRET || "your-secret-key"; + +// export const authenticateToken = async (req, res, next) => { +// try { +// // TODO: Implement the authentication middleware +// // 1. Get the token from the request header +// // 2. Verify the token +// // 3. Get the user from the database +// // 4. If the user doesn't exist, throw an error +// // 5. Attach the user to the request object +// // 6. Call the next middleware + + + +// } catch (error) { +// if (error.name === "JsonWebTokenError") { +// return res.status(401).json({ +// success: false, +// message: "Invalid token", +// }); +// } + +// if (error.name === "TokenExpiredError") { +// return res.status(401).json({ +// success: false, +// message: "Token expired", +// }); +// } + +// return res.status(500).json({ +// success: false, +// message: "Authentication error", +// }); +// } +// }; + + + + import jwt from "jsonwebtoken"; import prisma from "../lib/prisma.js"; @@ -5,16 +47,39 @@ const JWT_SECRET = process.env.JWT_SECRET || "your-secret-key"; export const authenticateToken = async (req, res, next) => { try { - // TODO: Implement the authentication middleware // 1. Get the token from the request header + const authHeader = req.headers.authorization; + + if (!authHeader || !authHeader.startsWith("Bearer ")) { + return res.status(401).json({ + success: false, + message: "Access token missing or invalid", + }); + } + + const token = authHeader.split(" ")[1]; + // 2. Verify the token + const decoded = jwt.verify(token, JWT_SECRET); + // 3. Get the user from the database + const user = await prisma.user.findUnique({ + where: { id: decoded.id }, + }); + // 4. If the user doesn't exist, throw an error + if (!user) { + return res.status(401).json({ + success: false, + message: "User not found", + }); + } + // 5. Attach the user to the request object - // 6. Call the next middleware + req.user = user; - - + // 6. Call the next middleware + next(); } catch (error) { if (error.name === "JsonWebTokenError") { return res.status(401).json({ diff --git a/prisma/migrations/20251219135401_/migration.sql b/prisma/migrations/20251219135401_/migration.sql new file mode 100644 index 0000000..f942249 --- /dev/null +++ b/prisma/migrations/20251219135401_/migration.sql @@ -0,0 +1,55 @@ +-- CreateEnum +CREATE TYPE "TaskStatus" AS ENUM ('pending', 'in_progress', 'completed', 'cancelled'); + +-- CreateEnum +CREATE TYPE "Priority" AS ENUM ('low', 'medium', 'high', 'urgent'); + +-- CreateTable +CREATE TABLE "users" ( + "id" TEXT NOT NULL, + "email" TEXT NOT NULL, + "password" TEXT NOT NULL, + "name" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "users_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "tasks" ( + "id" TEXT NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT NOT NULL, + "status" "TaskStatus" NOT NULL, + "priority" "Priority" NOT NULL, + "dueDate" TIMESTAMP(3), + "assignedTo" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "userId" TEXT NOT NULL, + + CONSTRAINT "tasks_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "subtasks" ( + "id" TEXT NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT NOT NULL, + "completed" BOOLEAN NOT NULL DEFAULT false, + "taskId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "subtasks_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "users_email_key" ON "users"("email"); + +-- AddForeignKey +ALTER TABLE "tasks" ADD CONSTRAINT "tasks_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "subtasks" ADD CONSTRAINT "subtasks_taskId_fkey" FOREIGN KEY ("taskId") REFERENCES "tasks"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..fbffa92 --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "postgresql" \ No newline at end of file diff --git a/routes/auth.js b/routes/auth.js index 7a78cfc..b13049f 100644 --- a/routes/auth.js +++ b/routes/auth.js @@ -1,3 +1,5 @@ + + import express from "express"; import bcrypt from "bcryptjs"; import jwt from "jsonwebtoken"; @@ -5,21 +7,67 @@ import prisma from "../lib/prisma.js"; import { authenticateToken } from "../middleware/auth.js"; const router = express.Router(); -const JWT_SECRET = process.env.JWT_SECRET || "your-secret-key"; +const JWT_SECRET = process.env.JWT_SECRET || "okokokokkokok"; -// POST /api/auth/register - Register a new user +/** + * POST /api/auth/register + * Register a new user + */ router.post("/register", async (req, res) => { try { - // TODO: Implement the registration logic - // 1. Validate the input - // 2. Check if the user already exists + const { name, email, password } = req.body; + + // 1. Validate input + if (!name || !email || !password) { + return res.status(400).json({ + success: false, + message: "Name, email, and password are required", + }); + } + + // 2. Check if user already exists + const existingUser = await prisma.user.findUnique({ + where: { email }, + }); + + if (existingUser) { + return res.status(409).json({ + success: false, + message: "User already exists", + }); + } + // 3. Hash the password + const hashedPassword = await bcrypt.hash(password, 10); + // 4. Create the user - // 5. Generate a JWT token - // 6. Return the user data and token + const user = await prisma.user.create({ + data: { + name, + email, + password: hashedPassword, + }, + }); + // 5. Generate JWT token + const token = jwt.sign( + { id: user.id, email: user.email }, + JWT_SECRET, + { expiresIn: "7d" } + ); + // Remove password from response + const { password: _, ...userWithoutPassword } = user; + // 6. Return user data and token + res.status(201).json({ + success: true, + message: "User registered successfully", + data: { + user: userWithoutPassword, + token, + }, + }); } catch (error) { console.error("Registration error:", error); res.status(500).json({ @@ -30,17 +78,63 @@ router.post("/register", async (req, res) => { } }); -// POST /api/auth/login - Login user +/** + * POST /api/auth/login + * Login user + */ router.post("/login", async (req, res) => { try { - // TODO: Implement the login logic - // 1. Validate the input - // 2. Check if the user exists - // 3. Compare the password - // 4. Generate a JWT token - // 5. Return the user data and token - - + const { email, password } = req.body; + + // 1. Validate input + if (!email || !password) { + return res.status(400).json({ + success: false, + message: "Email and password are required", + }); + } + + // 2. Check if user exists + const user = await prisma.user.findUnique({ + where: { email }, + }); + + if (!user) { + return res.status(401).json({ + success: false, + message: "Invalid email or password", + }); + } + + // 3. Compare password + const isPasswordValid = await bcrypt.compare(password, user.password); + + if (!isPasswordValid) { + return res.status(401).json({ + success: false, + message: "Invalid email or password", + }); + } + + // 4. Generate JWT token + const token = jwt.sign( + { id: user.id, email: user.email }, + JWT_SECRET, + { expiresIn: "7d" } + ); + + // Remove password from response + const { password: _, ...userWithoutPassword } = user; + + // 5. Return user data and token + res.json({ + success: true, + message: "Login successful", + data: { + user: userWithoutPassword, + token, + }, + }); } catch (error) { console.error("Login error:", error); res.status(500).json({ @@ -51,10 +145,13 @@ router.post("/login", async (req, res) => { } }); -// GET /api/auth/me - Get current user profile (protected route) +/** + * GET /api/auth/me + * Get current user profile (protected) + */ router.get("/me", authenticateToken, async (req, res) => { try { - // req.user will be set by the authenticateToken middleware + // req.user is set by authenticateToken middleware const { password, ...userWithoutPassword } = req.user; res.json({ diff --git a/services/taskServices.js b/services/taskServices.js index 1f55241..fdd89b1 100644 --- a/services/taskServices.js +++ b/services/taskServices.js @@ -61,6 +61,10 @@ export async function createTask(taskData, userId) { } } + + + + // Update task export async function updateTask(id, updateData, userId) { try {