From 0acf95f20af77f17dd3f816d149c6ea7cead2b49 Mon Sep 17 00:00:00 2001 From: Jesus Galaz <jesusgalazr@icloud.com> Date: Sun, 13 Oct 2024 11:04:35 +0200 Subject: [PATCH] User authentication implemented --- public/css/index.css | 117 +++++++++++++++++++++++++++++++++++++++++++ public/css/login.css | 10 ++-- public/css/main.css | 20 +++----- public/js/auth.js | 75 +++++++++++++++++++++++++++ public/login.html | 46 ++++++++++++++++- public/register.html | 20 +++++--- routes/users.js | 72 ++++++++++++++++++++++++++ 7 files changed, 334 insertions(+), 26 deletions(-) create mode 100644 public/css/index.css diff --git a/public/css/index.css b/public/css/index.css new file mode 100644 index 0000000..b0973e6 --- /dev/null +++ b/public/css/index.css @@ -0,0 +1,117 @@ +body { + font-family: "Arial", sans-serif; + background-color: #f5f5f5; + color: #333; + line-height: 1.6; + margin: 0; + padding: 0; + } + .container { + max-width: 600px; + margin: 2rem auto; + padding: 2rem; + background-color: #fff; + border-radius: 8px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + } + header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 2rem; + } + h1 { + font-size: 2rem; + font-weight: 300; + margin: 0; + } + #logout-btn { + background-color: transparent; + border: 1px solid #333; + color: #333; + padding: 0.5rem 1rem; + border-radius: 4px; + cursor: pointer; + transition: all 0.3s ease; + } + #logout-btn:hover { + background-color: #333; + color: #fff; + } + #new-task-form { + display: flex; + margin-bottom: 2rem; + } + input[type="text"] { + flex-grow: 1; + padding: 0.75rem; + border: 1px solid #ddd; + border-radius: 4px 0 0 4px; + font-size: 1rem; + } + button[type="submit"] { + padding: 0.75rem 1.5rem; + background-color: #4caf50; + color: #fff; + border: none; + border-radius: 0 4px 4px 0; + cursor: pointer; + transition: background-color 0.3s ease; + } + button[type="submit"]:hover { + background-color: #45a049; + } + .task-list ul { + list-style-type: none; + padding: 0; + } + .task-list li { + background-color: #f9f9f9; + border-left: 4px solid #4caf50; + margin-bottom: 1rem; + padding: 1rem; + display: flex; + justify-content: space-between; + align-items: center; + transition: all 0.3s ease; + } + .task-list li:hover { + background-color: #f0f0f0; + } + .task-list li.completed { + border-left-color: #999; + opacity: 0.6; + } + .task-list li.completed span { + text-decoration: line-through; + } + .task-actions { + display: flex; + gap: 0.5rem; + } + .task-list li button { + background-color: transparent; + border: none; + cursor: pointer; + font-size: 1.2rem; + transition: color 0.3s ease; + padding: 0; + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; + } + .complete-btn { + color: #4caf50; + } + .complete-btn:hover { + color: #45a049; + } + .delete-btn { + color: #d9534f; + } + .delete-btn:hover { + color: #c9302c; + } + \ No newline at end of file diff --git a/public/css/login.css b/public/css/login.css index aa5f611..04ecf20 100644 --- a/public/css/login.css +++ b/public/css/login.css @@ -85,17 +85,19 @@ button:hover { } .success_message { display: none; + opacity: 0; color: #28a745; margin-top: 1rem; - font-size: 1rem; + font-size: 12px; text-align: center; - opacity: 0; transition: opacity 0.6s ease; } + .success_message.show { - display: block; + display: block; opacity: 1; } + .register-link { text-align: center; margin-top: 1.5rem; @@ -121,4 +123,4 @@ button:hover { } .login-link a:hover { text-decoration: underline; -} \ No newline at end of file +} diff --git a/public/css/main.css b/public/css/main.css index 6b5e56b..8719569 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -1,18 +1,15 @@ -/* Reset default styles */ body { margin: 0; padding: 0; - font-family:Verdana, Geneva, Tahoma, sans-serif; + font-family:Helvetica, Arial, sans-serif; } -/* Container for the entire layout */ .container { display: flex; flex-direction: column; min-height: 100vh; } -/* Header styling */ .header { background-color: #ddf; color: #000; @@ -36,16 +33,14 @@ header button { gap: 10px; } -/* Main content styling */ .main-content { display: flex; - flex-grow: 1; /* Makes the main content stretch to fill the remaining space */ - overflow-y: hidden; /* Hides overflow within the main content */ + flex-grow: 1; + overflow-y: hidden; } -/* Sidebar styling */ .sidebar { - width: 200px; /* Adjust the width as needed */ + width: 200px; padding: 25px; background-color: #ddf; } @@ -55,13 +50,12 @@ header button { padding: 0; } -/* Task list styling */ .task-list { - flex-grow: 1; /* Makes the task list stretch to fill the remaining space */ + flex-grow: 1; padding: 10px; padding-top: 25px; - overflow-y: auto; /* Enables vertical scrolling within the task list */ - max-height: calc(100vh - 100px); /* Adjust the max-height as needed */ + overflow-y: auto; + max-height: calc(100vh - 100px); } .task { diff --git a/public/js/auth.js b/public/js/auth.js index e69de29..0911918 100644 --- a/public/js/auth.js +++ b/public/js/auth.js @@ -0,0 +1,75 @@ +document.addEventListener('DOMContentLoaded', () => { + // Registro + const registerForm = document.getElementById('register-form'); + if (registerForm) { + registerForm.addEventListener('submit', async (event) => { + event.preventDefault(); + + const username = document.getElementById('username').value; + const password = document.getElementById('password').value; + + try { + const response = await fetch('/api/users/register', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ username, password }), + }); + + const result = await response.json(); + + if (response.ok) { + document.querySelector('.success_message').style.display = 'block'; + document.querySelector('.error_text').textContent = ''; + setTimeout(() => { + window.location.href = 'login.html'; + }, 2000); + } else { + document.querySelector('.error_text').textContent = result.error || 'Registration failed'; + document.querySelector('.success_message').style.display = 'none'; + } + } catch (error) { + console.error('Error:', error); + document.querySelector('.error_text').textContent = 'Server error. Please try again later.'; + } + }); + } + + // Inicio de sesión + const loginForm = document.getElementById('login-form'); + if (loginForm) { + loginForm.addEventListener('submit', async (event) => { + event.preventDefault(); + + const username = document.getElementById('username').value; + const password = document.getElementById('password').value; + + try { + const response = await fetch('/api/users/login', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ username, password }), + }); + + const result = await response.json(); + + if (response.ok) { + document.querySelector('.success_message').style.display = 'block'; + document.querySelector('.error_text').textContent = ''; + setTimeout(() => { + window.location.href = 'index.html'; + }, 2000); + } else { + document.querySelector('.error_text').textContent = result.error || 'Login failed'; + document.querySelector('.success_message').style.display = 'none'; + } + } catch (error) { + console.error('Error:', error); + document.querySelector('.error_text').textContent = 'Server error. Please try again later.'; + } + }); + } +}); \ No newline at end of file diff --git a/public/login.html b/public/login.html index 931d251..9d90c07 100644 --- a/public/login.html +++ b/public/login.html @@ -4,7 +4,7 @@ <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Login</title> - <link rel="stylesheet" href="./css/login.css"> + <link rel="stylesheet" href="./css/login.css" /> </head> <body> <div class="login-container"> @@ -32,6 +32,50 @@ </div> <div class="register-link"> + <!DOCTYPE html> + <html lang="es"> + <head> + <meta charset="UTF-8" /> + <meta + name="viewport" + content="width=device-width, initial-scale=1.0" + /> + <title>Login</title> + <link rel="stylesheet" href="./css/login.css" /> + </head> + <body> + <div class="login-container"> + <h2>Login</h2> + <form id="login-form"> + <input + type="text" + class="uname" + id="username" + placeholder="Username" + required + /> + <input + type="password" + class="pass" + id="password" + placeholder="Password" + required + /> + <button type="submit" class="submit-login">Login</button> + </form> + <span class="error_text" style="color: red"></span> + <div class="success_message" style="display: none; color: green"> + Login successful! Redirecting... + </div> + + <div class="register-link"> + Don't have an account? <a href="register.html">Register</a>. + </div> + </div> + + <script src="./js/auth.js"></script> + </body> + </html> Don't have an account? <a href="register.html">Create one</a>. </div> </div> diff --git a/public/register.html b/public/register.html index 053c7f8..aeff643 100644 --- a/public/register.html +++ b/public/register.html @@ -4,35 +4,39 @@ <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Register</title> - <link rel="stylesheet" href="./css/login.css"> - + <link rel="stylesheet" href="./css/login.css" /> </head> <body> <div class="register-container"> <h2>Register</h2> - <form id="register-form" action="register.php" method="POST"> + <form id="register-form"> <input type="text" class="uname" - name="username" + id="username" placeholder="Username" required /> <input type="password" class="pass" - name="password" + id="password" placeholder="Password" required /> <button type="submit" class="submit-register">Register</button> </form> - <span class="error_text"></span> - <div class="success_message">Registration successful! Redirecting...</div> - <div class="login-link"> + <span class="error_text" style="color: red"></span> + <div class="success_message" style="display: none; color: green"> + Registration successful! Redirecting... + </div> + + <div class="login-link" style="margin-top: 20px"> Already have an account? <a href="login.html">Log in</a>. </div> </div> + + <script src="./js/auth.js"></script> </body> </html> diff --git a/routes/users.js b/routes/users.js index e69de29..cf9fc04 100644 --- a/routes/users.js +++ b/routes/users.js @@ -0,0 +1,72 @@ +const express = require('express'); +const bcrypt = require('bcryptjs'); +const User = require('../models/user'); +const router = express.Router(); + +// Register User +router.post('/register', async (req, res) => { + const { username, password } = req.body; + + try { + // Verificar si el usuario ya existe + const existingUser = await User.findOne({ username }); + if (existingUser) { + return res.status(400).json({ error: 'User already exists' }); + } + + // Encriptar la contraseña antes de guardarla + const hashedPassword = await bcrypt.hash(password, 10); + + // Crear un nuevo usuario con la contraseña encriptada + const user = new User({ username, password: hashedPassword }); + await user.save(); + + res.status(201).json({ success: true, message: 'User registered successfully' }); + } catch (error) { + console.error('Error saving user:', error); + res.status(500).json({ error: 'Server error' }); + } +}); + +// LogIn User +router.post('/login', async (req, res) => { + const { username, password } = req.body; + console.log('Attempting to log in:', username); + + try { + const user = await User.findOne({ username }); + console.log('User found:', user); + + if (!user) { + return res.status(400).json({ error: 'Invalid username or password' }); + } + + const isMatch = await bcrypt.compare(password, user.password); + console.log('Password match:', isMatch); + + if (!isMatch) { + return res.status(400).json({ error: 'Invalid username or password' }); + } + + req.session.user = { id: user._id, username: user.username }; + console.log('User logged in:', req.session.user); + + res.json({ success: true, message: 'Login successful' }); + } catch (error) { + console.error('Login error:', error); + res.status(500).json({ error: 'Server error' }); + } +}); + + +// Cerrar sesión del usuario +router.post('/logout', (req, res) => { + req.session.destroy(err => { + if (err) { + return res.status(500).json({ error: 'Logout failed' }); + } + res.json({ success: true, message: 'Logged out successfully' }); + }); +}); + +module.exports = router; \ No newline at end of file -- GitLab