feat: inicializacion de Help Desk segun estandar Telcotronics con bitacora de errores e integracion MCP
This commit is contained in:
+157
@@ -0,0 +1,157 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const bcrypt = require('bcryptjs');
|
||||
const User = require('../models/User');
|
||||
const Company = require('../models/Company');
|
||||
const Department = require('../models/Department');
|
||||
|
||||
router.get('/login', (req, res) => {
|
||||
if (req.session.user) return res.redirect('/');
|
||||
res.render('auth/login');
|
||||
});
|
||||
|
||||
router.post('/login', async (req, res) => {
|
||||
const { email, password } = req.body;
|
||||
try {
|
||||
const user = await User.findByEmail(email);
|
||||
if (!user) {
|
||||
req.flash('error_msg', 'Email o contraseña incorrectos');
|
||||
return res.redirect('/login');
|
||||
}
|
||||
if (!user.is_active) {
|
||||
req.flash('error_msg', 'Cuenta desactivada');
|
||||
return res.redirect('/login');
|
||||
}
|
||||
const company = await Company.findById(user.company_id);
|
||||
if (company && !company.is_active) {
|
||||
req.flash('error_msg', 'Tu empresa está desactivada');
|
||||
return res.redirect('/login');
|
||||
}
|
||||
const match = await bcrypt.compare(password, user.password);
|
||||
if (!match) {
|
||||
req.flash('error_msg', 'Email o contraseña incorrectos');
|
||||
return res.redirect('/login');
|
||||
}
|
||||
req.session.user = {
|
||||
id: user.id,
|
||||
company_id: user.company_id,
|
||||
nombre: user.nombre,
|
||||
email: user.email,
|
||||
rol: user.rol
|
||||
};
|
||||
req.flash('success_msg', 'Inicio de sesión exitoso');
|
||||
res.redirect('/');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
req.flash('error_msg', 'Error al iniciar sesión');
|
||||
res.redirect('/login');
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/register', (req, res) => {
|
||||
if (req.session.user) return res.redirect('/');
|
||||
res.render('auth/register');
|
||||
});
|
||||
|
||||
router.post('/register', async (req, res) => {
|
||||
const { nombre, email, password, confirm_password, company_name } = req.body;
|
||||
if (!nombre || !email || !password || !confirm_password) {
|
||||
req.flash('error_msg', 'Todos los campos son obligatorios');
|
||||
return res.redirect('/register');
|
||||
}
|
||||
if (password !== confirm_password) {
|
||||
req.flash('error_msg', 'Las contraseñas no coinciden');
|
||||
return res.redirect('/register');
|
||||
}
|
||||
if (password.length < 6) {
|
||||
req.flash('error_msg', 'La contraseña debe tener al menos 6 caracteres');
|
||||
return res.redirect('/register');
|
||||
}
|
||||
try {
|
||||
const existing = await User.findByEmail(email);
|
||||
if (existing) {
|
||||
req.flash('error_msg', 'El email ya está registrado');
|
||||
return res.redirect('/register');
|
||||
}
|
||||
|
||||
// Create company or use default
|
||||
let companyId = 1;
|
||||
if (company_name) {
|
||||
const slug = company_name.toLowerCase().replace(/[^a-z0-9]/g, '-').replace(/-+/g, '-').slice(0, 100);
|
||||
const slugExists = await Company.findBySlug(slug);
|
||||
if (slugExists) {
|
||||
req.flash('error_msg', 'El nombre de empresa ya está registrado');
|
||||
return res.redirect('/register');
|
||||
}
|
||||
companyId = await Company.create(company_name, slug, 'free');
|
||||
// Seed default departments for new company
|
||||
await Department.create(companyId, 'Soporte Técnico', 'Problemas técnicos y de software');
|
||||
await Department.create(companyId, 'Facturación', 'Problemas de facturación y pagos');
|
||||
await Department.create(companyId, 'General', 'Consultas generales');
|
||||
}
|
||||
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
await User.create(companyId, nombre, email, hashedPassword, company_name ? 'admin' : 'client');
|
||||
req.flash('success_msg', 'Registro exitoso, ahora puedes iniciar sesión');
|
||||
res.redirect('/login');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
req.flash('error_msg', 'Error al registrarse');
|
||||
res.redirect('/register');
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/invite/:token', async (req, res) => {
|
||||
try {
|
||||
const invite = await User.findByInviteToken(req.params.token);
|
||||
if (!invite) {
|
||||
req.flash('error_msg', 'Invitación inválida o expirada');
|
||||
return res.redirect('/login');
|
||||
}
|
||||
res.render('auth/accept-invite', { token: req.params.token, email: invite.email });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
req.flash('error_msg', 'Error al procesar invitación');
|
||||
res.redirect('/login');
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/invite/:token', async (req, res) => {
|
||||
const { nombre, password, confirm_password } = req.body;
|
||||
if (!nombre || !password || !confirm_password) {
|
||||
req.flash('error_msg', 'Todos los campos son obligatorios');
|
||||
return res.redirect(`/invite/${req.params.token}`);
|
||||
}
|
||||
if (password !== confirm_password) {
|
||||
req.flash('error_msg', 'Las contraseñas no coinciden');
|
||||
return res.redirect(`/invite/${req.params.token}`);
|
||||
}
|
||||
try {
|
||||
const invite = await User.findByInviteToken(req.params.token);
|
||||
if (!invite) {
|
||||
req.flash('error_msg', 'Invitación inválida o expirada');
|
||||
return res.redirect('/login');
|
||||
}
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
await User.update(invite.id, {
|
||||
nombre,
|
||||
password: hashedPassword,
|
||||
is_active: 1,
|
||||
invite_token: null,
|
||||
invite_token_expires: null
|
||||
});
|
||||
req.flash('success_msg', 'Cuenta activada, ahora puedes iniciar sesión');
|
||||
res.redirect('/login');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
req.flash('error_msg', 'Error al aceptar invitación');
|
||||
res.redirect(`/invite/${req.params.token}`);
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/logout', (req, res) => {
|
||||
req.session.destroy();
|
||||
res.redirect('/login');
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user