From ad313f3b21f83ff9b0fcc121f8fc24ad51745b53 Mon Sep 17 00:00:00 2001 From: Mosiur Rahman Date: Thu, 23 Apr 2026 16:10:00 +0600 Subject: [PATCH] Phase 3 server side configuration done --- server/src/controllers/authController.ts | 18 +++- server/src/controllers/todoController.ts | 111 +++++++++++++++++++++ server/src/controllers/whoamiController.ts | 0 server/src/models/Todo.ts | 48 +++++++++ server/src/routes/authRoutes.ts | 4 +- server/src/routes/todoRoutes.ts | 14 +++ server/src/routes/whoamiRoutes.ts | 0 server/src/server.ts | 5 +- 8 files changed, 197 insertions(+), 3 deletions(-) create mode 100644 server/src/controllers/todoController.ts create mode 100644 server/src/controllers/whoamiController.ts create mode 100644 server/src/models/Todo.ts create mode 100644 server/src/routes/todoRoutes.ts create mode 100644 server/src/routes/whoamiRoutes.ts diff --git a/server/src/controllers/authController.ts b/server/src/controllers/authController.ts index 1c37775..044b801 100644 --- a/server/src/controllers/authController.ts +++ b/server/src/controllers/authController.ts @@ -41,7 +41,8 @@ export const login = async (req: Request, res: Response ): Promise => { } const user = await User.findOne({ email }); - if (!user) { + const isMatch = await user?.comparePassword(password) + if (!user || !isMatch) { res.status(401).json({message:'Invalid Email or password'}) return; } @@ -54,4 +55,19 @@ export const login = async (req: Request, res: Response ): Promise => { res.status(500).json({ message: 'Server error during login' }); } +} + + +export const getMe = async (req: Request, res: Response): Promise => { + try { + const user = req.user; + if (!user) { + res.status(401).json({message:'Undefined User'}) + return; + } + res.json({ user }) + } catch (error) { + console.error(error) + res.status(500).json({ message: 'Server Error'}) + } } \ No newline at end of file diff --git a/server/src/controllers/todoController.ts b/server/src/controllers/todoController.ts new file mode 100644 index 0000000..29945de --- /dev/null +++ b/server/src/controllers/todoController.ts @@ -0,0 +1,111 @@ +import { Request, Response } from "express" +import { Todo } from "../models/Todo" + +export const createTodo = async (req: Request, res: Response): Promise => { + try { + const {title, description, priority, dueDate} = req.body + + if (!title) { + res.status(400).json({message: "Please insert title"}) + return + } + + const todo = await Todo.create({ + title, + description, + priority, + dueDate, + user: req.user._id + }) + + res.status(201).json({todo}) + } catch (error) { + console.error('Create todo error:', error) + res.status(500).json({ message: 'Server error' }) } +} + +export const getTodos = async (req: Request, res: Response): Promise => { + try { + const todos = await Todo.find({ user: req.user?._id }) + res.status(200).json({ todos }) + } catch (error) { + console.error('Get todos error:', error) + res.status(500).json({ message: 'Server error' }) + } +} + +export const updateTodos = async (req: Request, res: Response): Promise => { + try { + const id = req.params.id + const todo = await Todo.findById(id) + if (!todo) { + res.status(404).json({message: "Object Not Found"}) + return; + } + + if (todo.user.toString()!== req.user?._id.toString()){ + res.status(403).json({ message: "Not authorized" }) + return; + } + + const updateTodo = await Todo.findByIdAndUpdate( + id, + req.body, + {new: true} + ) + + res.status(200).json({ todo: updateTodo }) + } catch (error) { + console.error('Update todo error:', error) + res.status(500).json({ message: 'Server error' }) + } +} + +export const deleteTodo = async (req: Request, res: Response): Promise => { + try{ + const id = req.params.id + const deleteTodo = await Todo.findById(id) + if (!deleteTodo) { + res.status(404).json({ message: 'Todo not found' }) + return; + } + if (deleteTodo.user.toString() !== req.user?._id.toString()) { + res.status(403).json({ message: 'Not authorized' }) + return + } + + await Todo.findByIdAndDelete(id) + res.status(200).json({ message: 'Todo deleted successfully' }) + } catch (error) { + console.error(error) + res.status(500).json({message: "Server Error"}) + } + +} + +export const toggleTodo = async (req: Request, res: Response): Promise =>{ + try { + + const todo = await Todo.findById(req.params.id) + if (!todo) { + res.status(404).json({ message: 'Todo not found' }) + return +} + +// ownership check: + if (todo.user.toString() !== req.user?._id.toString()) { + res.status(403).json({ message: 'Not authorized' }) + return + } + + todo.completed = !todo.completed + await todo.save() + res.status(200).json({ todo }) + + + } catch (error) { + console.error(error) + res.status(500).json({message: "Server Error"}) + + } +} \ No newline at end of file diff --git a/server/src/controllers/whoamiController.ts b/server/src/controllers/whoamiController.ts new file mode 100644 index 0000000..e69de29 diff --git a/server/src/models/Todo.ts b/server/src/models/Todo.ts new file mode 100644 index 0000000..10e76a6 --- /dev/null +++ b/server/src/models/Todo.ts @@ -0,0 +1,48 @@ +import { Document, model, Schema, Types } from "mongoose"; + +export interface ITodo { + title: string, + description?: string, + completed: boolean, + priority: 'low' | 'medium' | 'high' + dueDate?: Date, + user: Types.ObjectId +} + +export interface ITodoDocument extends ITodo, Document { + _id: Types.ObjectId +} + +const todoSchema = new Schema ({ + title: { + type: String, + required: [true, 'Title is required'], + trim: true, + }, + description: { + type: String, + required: false + }, + completed: { + type: Boolean, + default: false + }, + priority: { + type: String, + enum: ['low', 'medium', 'high',], + default: 'medium' + }, + dueDate:{ + type: Date, + required: false + }, + user: { + type: Schema.Types.ObjectId, + ref: 'User', + required: true + } + +}, {timestamps: true} +) + +export const Todo = model('Todo', todoSchema) \ No newline at end of file diff --git a/server/src/routes/authRoutes.ts b/server/src/routes/authRoutes.ts index 700c082..3da4d49 100644 --- a/server/src/routes/authRoutes.ts +++ b/server/src/routes/authRoutes.ts @@ -1,10 +1,12 @@ import { Router } from 'express'; -import { register, login } from '../controllers/authController'; +import { register, login, getMe } from '../controllers/authController'; +import { protect } from '../middleware/authMiddleware'; const router = Router(); router.post('/register', register); router.post ('/login', login) +router.get('/me',protect, getMe) export default router; diff --git a/server/src/routes/todoRoutes.ts b/server/src/routes/todoRoutes.ts new file mode 100644 index 0000000..b7ba9a2 --- /dev/null +++ b/server/src/routes/todoRoutes.ts @@ -0,0 +1,14 @@ +import { Router } from "express"; +import { createTodo, deleteTodo, getTodos, toggleTodo, updateTodos } from "../controllers/todoController"; +import { protect } from "../middleware/authMiddleware"; + +const router = Router(); +router.use(protect) + +router.get("/", getTodos) +router.post("/", createTodo) +router.put("/:id", updateTodos) +router.delete("/:id", deleteTodo) +router.patch("/:id/toggle", toggleTodo) + +export default router; \ No newline at end of file diff --git a/server/src/routes/whoamiRoutes.ts b/server/src/routes/whoamiRoutes.ts new file mode 100644 index 0000000..e69de29 diff --git a/server/src/server.ts b/server/src/server.ts index 69fdc73..7ebf254 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -3,6 +3,7 @@ import cors from 'cors'; import {ENV} from './config/env'; import {connectDB, readyState} from './config/db'; import authRoutes from './routes/authRoutes'; +import todoRoutes from './routes/todoRoutes'; const app: Application = express() @@ -19,7 +20,7 @@ app.get('/health', (_req: Request, res: Response)=> { //for checking database connection -app.get('/health/db', (req: Request, res: Response)=> { +app.get('/health/db', (_req: Request, res: Response)=> { res.json({ db_status: readyState(), environment: ENV.NODE_ENV, @@ -30,6 +31,8 @@ app.get('/health/db', (req: Request, res: Response)=> { //api routes app.use('/api/auth', authRoutes); +app.use('/api/todos', todoRoutes); + //start Server