diff --git a/controllers/AuthController.js b/controllers/AuthController.js new file mode 100644 index 0000000000000000000000000000000000000000..6b003afbeb8918dfc46b9fae706e84d5fe8dc46b --- /dev/null +++ b/controllers/AuthController.js @@ -0,0 +1,197 @@ +const User = require('../Models/User'); +const jwt = require('jsonwebtoken'); +const path = require('path'); + +class AuthController { + // Show the login page + static showLoginPage(req, res) { + res.render('login', { error: null }); + } + + // Show the registration page + static showRegisterPage(req, res) { + res.render('register', { error: null }); + } + + // Register a new user + static signup(req, res) { + const { name, email, password, confirm_password } = req.body; + + // Validate input + if (!name || !email || !password || !confirm_password) { + return res.render('register', { error: 'All fields are required' }); + } + + if (password !== confirm_password) { + return res.render('register', { error: 'Passwords do not match' }); + } + + // Check if email already exists + User.getByEmail(email, (err, user) => { + if (err) { + console.log(err); + return res.render('register', { error: 'Database error' }); + } + + if (user) { + return res.render('register', { error: 'Email already in use' }); + } + + // Create new user + User.create({ name, email, password }, (err, result) => { + if (err) { + console.log(err); + return res.render('register', { error: 'Failed to create user' }); + } + + // Redirect to login page + return res.render('login', { error: null, success: 'Registration successful. Please login.' }); + }); + }); + } + + // API signup + static apiSignup(req, res) { + const { name, email, password } = req.body; + + // Validate input + if (!name || !email || !password) { + return res.status(400).json({ error: 'All fields are required' }); + } + + // Check if email already exists + User.getByEmail(email, (err, user) => { + if (err) { + console.log(err); + return res.status(500).json({ error: 'Database error' }); + } + + if (user) { + return res.status(400).json({ error: 'Email already in use' }); + } + + // Create new user + User.create({ name, email, password }, (err, result) => { + if (err) { + console.log(err); + return res.status(500).json({ error: 'Failed to create user' }); + } + + res.status(201).json({ + message: 'User created successfully', + userId: result.insertId + }); + }); + }); + } + + // Login a user + static login(req, res) { + const { email, password } = req.body; + + // Validate input + if (!email || !password) { + return res.render('login', { error: 'Email and password are required' }); + } + + // Find user by email + User.getByEmail(email, (err, user) => { + if (err) { + console.log(err); + return res.render('login', { error: 'Database error' }); + } + + if (!user) { + return res.render('login', { error: 'Invalid email or password' }); + } + + // Verify password + User.verifyPassword(password, user.password, (err, isMatch) => { + if (err) { + console.log(err); + return res.render('login', { error: 'Authentication error' }); + } + + if (!isMatch) { + return res.render('login', { error: 'Invalid email or password' }); + } + + // Create token + const token = jwt.sign( + { id: user.id, name: user.name, email: user.email }, + process.env.TOKEN_SECRET, + { expiresIn: '24h' } + ); + + // Set token in cookie + res.cookie('auth-token', token, { + httpOnly: true, + maxAge: 24 * 60 * 60 * 1000 // 24 hours + }); + + // Redirect to dashboard + res.redirect('/dashboard'); + }); + }); + } + + // API login + static apiLogin(req, res) { + const { email, password } = req.body; + + // Validate input + if (!email || !password) { + return res.status(400).json({ error: 'Email and password are required' }); + } + + // Find user by email + User.getByEmail(email, (err, user) => { + if (err) { + console.log(err); + return res.status(500).json({ error: 'Database error' }); + } + + if (!user) { + return res.status(400).json({ error: 'Invalid email or password' }); + } + + // Verify password + User.verifyPassword(password, user.password, (err, isMatch) => { + if (err) { + console.log(err); + return res.status(500).json({ error: 'Authentication error' }); + } + + if (!isMatch) { + return res.status(400).json({ error: 'Invalid email or password' }); + } + + // Create token + const token = jwt.sign( + { id: user.id, name: user.name, email: user.email }, + process.env.TOKEN_SECRET, + { expiresIn: '24h' } + ); + + // Send response with token + res.status(200).json({ + message: 'Login successful', + token: token, + user: { + id: user.id, + name: user.name, + email: user.email + } + }); + }); + }); + } + + // Logout a user + static logout(req, res) { + res.clearCookie('auth-token'); + res.redirect('/'); + } +} + +module.exports = AuthController; \ No newline at end of file diff --git a/controllers/CategoryController.js b/controllers/CategoryController.js new file mode 100644 index 0000000000000000000000000000000000000000..0e7202eaea56290a080f3494694d54e1f8ad0413 --- /dev/null +++ b/controllers/CategoryController.js @@ -0,0 +1,129 @@ +const Category = require('../Models/Category'); + +class CategoryController { + // Display all categories (web) + static index(req, res) { + Category.getByUserId(req.user.id, (err, categories) => { + if (err) { + console.log(err); + return res.status(500).send('Error loading categories'); + } + res.render('categories', { + categories: categories, + user: req.user + }); + }); + } + + // Get all categories (API) + static apiIndex(req, res) { + Category.getByUserId(req.user.id, (err, categories) => { + if (err) { + console.log(err); + return res.status(500).json({ error: 'Database error' }); + } + res.json(categories); + }); + } + + // Create a new category (web) + static create(req, res) { + const categoryData = { + name: req.body.name, + description: req.body.description, + userId: req.user.id + }; + + Category.create(categoryData, (err, result) => { + if (err) { + console.log(err); + return res.status(500).send('Error creating category'); + } + res.redirect('/categories'); + }); + } + + // Create a new category (API) + static apiCreate(req, res) { + const categoryData = { + name: req.body.name, + description: req.body.description, + userId: req.user.id + }; + + Category.create(categoryData, (err, result) => { + if (err) { + console.log(err); + return res.status(500).json({ error: 'Error creating category' }); + } + res.status(201).json({ + message: 'Category created successfully', + categoryId: result.insertId + }); + }); + } + + // Update a category (web) + static update(req, res) { + const categoryId = req.body.category_id; + const categoryData = { + name: req.body.name, + description: req.body.description, + userId: req.user.id + }; + + Category.update(categoryId, categoryData, (err, result) => { + if (err) { + console.log(err); + return res.status(500).send('Error updating category'); + } + res.redirect('/categories'); + }); + } + + // Update a category (API) + static apiUpdate(req, res) { + const categoryId = req.params.id; + const categoryData = { + name: req.body.name, + description: req.body.description, + userId: req.user.id + }; + + Category.update(categoryId, categoryData, (err, result) => { + if (err) { + console.log(err); + return res.status(500).json({ error: 'Error updating category' }); + } + res.json({ message: 'Category updated successfully' }); + }); + } + + // Delete a category (web) + static delete(req, res) { + const categoryId = req.params.id; + + Category.delete(categoryId, req.user.id, (err, result) => { + if (err) { + console.log(err); + return res.status(500).send('Error deleting category'); + } + res.redirect('/categories'); + }); + } + + // Delete a category (API) + static apiDelete(req, res) { + const categoryId = req.params.id; + + Category.delete(categoryId, req.user.id, (err, result) => { + if (err) { + console.log(err); + return res.status(500).json({ error: 'Error deleting category' }); + } + res.json({ message: 'Category deleted successfully' }); + }); + } +} + +module.exports = CategoryController; \ No newline at end of file diff --git a/controllers/NoteController.js b/controllers/NoteController.js new file mode 100644 index 0000000000000000000000000000000000000000..acd4f0e752d7e6dd8fa4d4927d5336704a1ac3a6 --- /dev/null +++ b/controllers/NoteController.js @@ -0,0 +1,206 @@ +const Note = require('../Models/Note'); +const Category = require('../Models/Category'); +const jwt = require('jsonwebtoken'); + +// NoteController - จัดการ Logic การทำงานของโน้ต +class NoteController { + // แสดงหน้าแรกที่มีโน้ตทั้งหมด + static async index(req, res) { + // ดึงข้อมูลโน้ตทั้งหมด + Note.getAll(req.user.id, (err, notes) => { + if (err) { + console.log(err); + return res.status(500).send('Error loading notes'); + } + + // ดึงข้อมูล categories สำหรับ dropdown (เฉพาะของ user นี้) + Category.getByUserId(req.user.id, (err, categories) => { + if (err) { + console.log(err); + return res.status(500).send('Error loading categories'); + } + + // ส่งข้อมูลไปแสดงที่หน้า dashboard + res.render('dashboard', { + data: notes, + categories: categories, + user: req.user + }); + }); + }); + } + + // Get all notes (API) + static apiIndex(req, res) { + Note.getAll(req.user.id, (err, notes) => { + if (err) { + console.log(err); + return res.status(500).json({ error: 'Database error' }); + } + res.json(notes); + }); + } + + // สร้างโน้ตใหม่ + static create(req, res) { + const noteData = { + title: req.body.title, + content: req.body.content, + userId: req.user.id, + categoryId: req.body.category_id || null + }; + + Note.create(noteData, (err, result) => { + if (err) { + console.log(err); + return res.status(500).send('Error creating note'); + } + res.redirect('/dashboard'); + }); + } + + // Create a new note (API) + static apiCreate(req, res) { + const noteData = { + title: req.body.title, + content: req.body.content, + userId: req.user.id, + categoryId: req.body.category_id || null + }; + + Note.create(noteData, (err, result) => { + if (err) { + console.log(err); + return res.status(500).json({ error: 'Error creating note' }); + } + res.status(201).json({ + message: 'Note created successfully', + noteId: result.insertId + }); + }); + } + + // อัพเดทโน้ต + static update(req, res) { + const noteId = req.body.note_id; + const noteData = { + title: req.body.title, + content: req.body.content, + categoryId: req.body.category_id || null, + userId: req.user.id + }; + + Note.update(noteId, noteData, (err, result) => { + if (err) { + console.log(err); + return res.status(500).send('Error updating note'); + } + res.redirect('/dashboard'); + }); + } + + // Update a note (API) + static apiUpdate(req, res) { + const noteId = req.params.id; + const noteData = { + title: req.body.title, + content: req.body.content, + categoryId: req.body.category_id || null, + userId: req.user.id + }; + + Note.update(noteId, noteData, (err, result) => { + if (err) { + console.log(err); + return res.status(500).json({ error: 'Error updating note' }); + } + res.json({ message: 'Note updated successfully' }); + }); + } + + // ลบโน้ต + static delete(req, res) { + const noteId = req.params.id; + + Note.delete(noteId, req.user.id, (err, result) => { + if (err) { + console.log(err); + return res.status(500).send('Error deleting note'); + } + res.redirect('/dashboard'); + }); + } + + // Delete a note (API) + static apiDelete(req, res) { + const noteId = req.params.id; + + Note.delete(noteId, req.user.id, (err, result) => { + if (err) { + console.log(err); + return res.status(500).json({ error: 'Error deleting note' }); + } + res.json({ message: 'Note deleted successfully' }); + }); + } + + // Search notes by title or content (web) + static search(req, res) { + const searchTerm = req.query.searchTerm; + + if (!searchTerm) { + return res.redirect('/dashboard'); + } + + Note.search(searchTerm, req.user.id, (err, notes) => { + if (err) { + console.log(err); + return res.status(500).send('Database error'); + } + + Category.getByUserId(req.user.id, (err, categories) => { + if (err) { + console.log(err); + return res.status(500).send('Database error'); + } + + res.render('dashboard', { + data: notes, + categories: categories, + searchTerm: searchTerm, + user: req.user + }); + }); + }); + } + + // แสดงโน้ตของผู้ใช้ที่ล็อกอินอยู่ + static myNotes(req, res) { + const userId = req.user.id; + + // ดึงโน้ตของผู้ใช้ + Note.getByUserId(userId, (err, notes) => { + if (err) { + console.log(err); + return res.status(500).send('Error loading notes'); + } + + // ดึง categories สำหรับ dropdown (เฉพาะของ user นี้) + Category.getByUserId(userId, (err, categories) => { + if (err) { + console.log(err); + return res.status(500).send('Error loading categories'); + } + + res.render('dashboard', { + data: notes, + categories: categories, + myNotes: true, + user: req.user + }); + }); + }); + } +} + +module.exports = NoteController; \ No newline at end of file diff --git a/Models/Category.js b/models/Category.js similarity index 100% rename from Models/Category.js rename to models/Category.js diff --git a/Models/Note.js b/models/Note.js similarity index 100% rename from Models/Note.js rename to models/Note.js diff --git a/Models/User.js b/models/User.js similarity index 100% rename from Models/User.js rename to models/User.js diff --git a/Routes/apiRoute.js b/routes/apiRoute.js similarity index 100% rename from Routes/apiRoute.js rename to routes/apiRoute.js diff --git a/Routes/web.js b/routes/web.js similarity index 100% rename from Routes/web.js rename to routes/web.js diff --git a/Views/categories.ejs b/views/categories.ejs similarity index 100% rename from Views/categories.ejs rename to views/categories.ejs diff --git a/Views/dashboard.ejs b/views/dashboard.ejs similarity index 100% rename from Views/dashboard.ejs rename to views/dashboard.ejs diff --git a/Views/login.ejs b/views/login.ejs similarity index 100% rename from Views/login.ejs rename to views/login.ejs diff --git a/Views/partials/footer.ejs b/views/partials/footer.ejs similarity index 100% rename from Views/partials/footer.ejs rename to views/partials/footer.ejs diff --git a/Views/partials/header.ejs b/views/partials/header.ejs similarity index 100% rename from Views/partials/header.ejs rename to views/partials/header.ejs diff --git a/Views/register.ejs b/views/register.ejs similarity index 100% rename from Views/register.ejs rename to views/register.ejs