diff --git a/controllers/usuario.controller.js b/controllers/usuario.controller.js index a923013..f02a977 100644 --- a/controllers/usuario.controller.js +++ b/controllers/usuario.controller.js @@ -1,4 +1,8 @@ const Usuario = require('../models/usuario.model.js'); +const nodemailer = require('nodemailer'); +const path = require('path'); +const dotenv = require('dotenv'); +dotenv.config(); /** * @description Registra un nuevo usuario en la base de datos. @@ -16,6 +20,91 @@ exports.registrarUsuario = async (req, res) => { } } +/** + * @description Genera una contraseña aleatoria. + * @param {int} longitud - Longitud de la contraseña. + * @returns {String} Contraseña nueva. + */ +function generarContrasena(longitud = 6) { + const caracteres = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + let contrasena = ''; + for (let it = 0; it < longitud; it++) { + const indice = Math.floor(Math.random() * caracteres.length); + contrasena += caracteres[indice]; + } + return contrasena; +} + +/** + * @description Manda un correo de recuperación para recuperar la contraseña + * @param {*} req - Solicitud HTTP que contiene información del usuario. + * @param {*} res - Respuesta HTTP que se usa para enviar el resultado. + * @returns {JSON} Código de respuesta + */ +exports.mandarCorreo = async (req, res) => { + try{ + const usuario = req.query.usuario; + const usuarioId = await Usuario.obtenerId(usuario); + if (usuarioId == null){ + res.status(201).json({code: 201}); + return; + } + + const nuevaContrasena = generarContrasena(); + + const transporter = nodemailer.createTransport({ + service: 'gmail', + auth: { + user: process.env.MAIL_USER, + pass: process.env.MAIL_PASSWORD, + }, + }); + + const mailOptions = { + from: process.env.MAIL_USER, + to: process.env.MAIL_RECEIVER, + subject: 'Recuperar contraseña ZuustentoTracker', + html: `
+ Logo de ZuustentoTracker +

¿Olvidaste tu contraseña?

+

Este correo es automatizado, se solicitó el cambio de contraseña para:

+

${usuario}

+

Nueva Contraseña:

+

${nuevaContrasena}

+

Si no solicitaste este cambio, puedes ignorar este correo.

+
`, + attachments: [ + { + filename: 'logo.png', + path: path.join(__dirname, '..', 'public', 'ZuustentoTracker_AppIcon.png'), + cid: 'logo' + } + ] + }; + + transporter.sendMail(mailOptions, (error, info) => { + if (error) { + console.log(error) + res.status(500).json({code: 500}); + return; + } + }); + + await Usuario.cambiarContrasena(usuarioId.usuarioId, nuevaContrasena); + + res.status(200).json({code: 200}); + } catch (error){ + console.log(error) + res.status(500).json({code: 500}) + } +}; + +/** + * @description Obtiene todos los usuarios de la base de datos + * @param {*} req - Solicitud HTTP que contiene información del usuario. + * @param {*} res - Respuesta HTTP que se usa para enviar el resultado. + * @returns {JSON} Código de respuesta + */ exports.obtenerUsuarios = async (req, res) => { try{ const resultado = await Usuario.obtenerUsuarios(); @@ -25,6 +114,12 @@ exports.obtenerUsuarios = async (req, res) => { } } +/** + * @description Edita la informacion de un usuario + * @param {*} req - Solicitud HTTP que contiene información del usuario. + * @param {*} res - Respuesta HTTP que se usa para enviar el resultado. + * @returns {JSON} Código de respuesta + */ exports.editarUsuario = async (req, res) => { try{ const resultado = await Usuario.editarUsuario(parseInt(req.query.usuarioId), req.body); @@ -36,6 +131,12 @@ exports.editarUsuario = async (req, res) => { } } +/** + * @description Elimina un usuario de la plataforma + * @param {*} req - Solicitud HTTP que contiene información del usuario. + * @param {*} res - Respuesta HTTP que se usa para enviar el resultado. + * @returns {JSON} Código de respuesta + */ exports.eliminarUsuario = async (req, res) => { try{ const resultado = await Usuario.eliminarUsuario(parseInt(req.query.usuarioId)); @@ -44,4 +145,4 @@ exports.eliminarUsuario = async (req, res) => { } catch (error){ return res.status(500).json({ code: 500 }); } -} \ No newline at end of file +} diff --git a/models/usuario.model.js b/models/usuario.model.js index f9cc149..9226e45 100644 --- a/models/usuario.model.js +++ b/models/usuario.model.js @@ -84,7 +84,10 @@ module.exports = class Usuario { return nuevo; } - + /** + * @description Extrae todos los usuarios de la base de datos y especifica sus roles + * @returns {Array} Resultado de la consulta. + */ static async obtenerUsuarios(){ const usuarios = await prisma.USUARIO.findMany({ include: { @@ -104,6 +107,12 @@ module.exports = class Usuario { return resultado; } + /** + * @description Edita la informacion de un usuario + * @param {Object} infoUsuario - Objeto con información del usuario. + * @param {int} usuarioId - Id del usuario a editar. + * @returns {Array} Resultado de la consulta + */ static async editarUsuario(usuarioId, infoUsuario){ const contrasenaHash = await bcrypt.hash(infoUsuario.contrasena, 12); @@ -121,6 +130,10 @@ module.exports = class Usuario { }) } + /** + * @description Elimina la informacion de un usuario + * @param {int} usuarioId - Id del usuario a editar. + */ static async eliminarUsuario(usuarioId){ await prisma.USUARIO.delete({ where: { @@ -128,4 +141,39 @@ module.exports = class Usuario { } }) } + + /** + * @description Obtiene el id de un usuario apartir de su nombre + * @param {String} nombreUsuario Nombre del usuario + * @returns {int} Resultado de la consulta + */ + static async obtenerId(nombreUsuario) { + return await prisma.USUARIO.findFirst({ + where: { + user: nombreUsuario + }, + select: { + usuarioId: true + } + }) + } + + /** + * @description Cambia la contraseña de un usuario + * @param {int} usuarioId Id del usuario + * @param {String} contrasena Contraseña nueva + * @returns {int} Resultado de la consulta + */ + static async cambiarContrasena(usuarioId, contrasena) { + const contrasenaHash = await bcrypt.hash(contrasena, 12); + + await prisma.USUARIO.update({ + where: { + usuarioId: usuarioId + }, + data: { + contrasena: contrasenaHash + } + }); + } }; diff --git a/package-lock.json b/package-lock.json index d6d9ddd..f522b32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "mariadb": "^3.4.0", "mysql2": "^3.14.0", "nodejs": "^0.0.0", + "nodemailer": "^7.0.3", "winston": "^3.17.0" }, "devDependencies": { @@ -6379,6 +6380,14 @@ "integrity": "sha512-1V+0HwaB/dhxzidEFc4uJ3k52gLI4B6YBZgJIofjwYCSAkD6CI0me6TDBT2QM2nbGWNxCHcq9/wVynzQYZOhUg==", "license": "ISC" }, + "node_modules/nodemailer": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.3.tgz", + "integrity": "sha512-Ajq6Sz1x7cIK3pN6KesGTah+1gnwMnx5gKl3piQlQQE/PwyJ4Mbc8is2psWYxK3RJTVeqsDaCv8ZzXLCDHMTZw==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", diff --git a/package.json b/package.json index b30f619..fa3794b 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "mariadb": "^3.4.0", "mysql2": "^3.14.0", "nodejs": "^0.0.0", + "nodemailer": "^7.0.3", "winston": "^3.17.0" }, "devDependencies": { diff --git a/public/ZuustentoTracker_AppIcon.PNG b/public/ZuustentoTracker_AppIcon.PNG new file mode 100644 index 0000000..1495dc2 Binary files /dev/null and b/public/ZuustentoTracker_AppIcon.PNG differ diff --git a/routes/usuario.routes.js b/routes/usuario.routes.js index 2e332cf..0bfeaee 100644 --- a/routes/usuario.routes.js +++ b/routes/usuario.routes.js @@ -18,6 +18,7 @@ router.get("/obtenerUsuarios", usuarioController.obtenerUsuarios); /* POST METHODS */ router.post("/iniciarSesion", autenticacionController.iniciarSesion); router.post("/registrarUsuario", usuarioController.registrarUsuario); +router.post("/recuperarContrasena", usuarioController.mandarCorreo); /* ----------- */ /* PUT METHODS */