controllers/users-controller.js

/**
*  User
* @typedef {Object} User
* @property {number} [userid] identificador del usuario
* @property {string} nombre nombre del usuario
* @property {string} apellido apellido del usuario
* @property {string} correo correo del usuario
* @property {string} password contrasena del usuario
* @property {string} password_confirmation confirmacion de contrasena
*/

const bcrypt = require('bcryptjs');
const { Database } = require('../database/database');
const CRUD = require('../database/CRUD');
const { Notification } = require('electron');

/** Clase estatica controlador de usuarios */
class UsersController {

	/**
	 * Instancia de Database
	 * @type {?Database}
	 */
	databaseInstance = null;

	/** Propiedad get database retorna una nueva instancia de la clase Database */
	static get database() {
		return this.databaseInstance || ( this.databaseInstance = new Database() );
	}

	/**
	* Crea un registro de usuario en la base de datos
	* @param {User} usuario
	* @example
	* await Database.crearUsuario({
	* 	nombre: 'ryan',
	* 	apellido: 'dohl',
	* 	correo: 'ryandohl@test.com'
	* 	password: '1234678'
	* 	passwordConfirmation: '12345678'
	* });
	*
	*/
	static crearUsuario( usuario ) {

		const saltRounds = 10;
		const salt = bcrypt.genSaltSync( 10 );

		delete usuario['passwordConfirmation'];

		usuario['password'] = bcrypt.hashSync( usuario['password'], salt );

		this.database.insert( CRUD.crearUsuario, usuario, ( error ) => {

			const notificacion = new Notification({
				title: '',
				body: ''
			});

			if ( error ) {

				console.log( error );
				// throw error;  // mostrará el error en pantalla

				notificacion['title'] = 'Error!!';
				notificacion['body'] = 'Error al crear usuario';

				notificacion.show();

				return;
			}

			notificacion['title'] = 'Registro exitoso!!';
			notificacion['body'] = 'Usuario creado con exito';

			notificacion.show();

  		});
	}

	/**
	* Obtiene el total de los usuarios
	* @returns {Promise<{ totalPaginas: number, totalRegistros: number }>}
	*/
	static obtenerTotalUsuarios() {

		return new Promise( ( resolve, reject ) => {

			this.database.getTotalRecords( CRUD.obtenerTotalUsuarios, ( error, resultado ) => {

				const notificacion = new Notification({
					title: 'Error en obtener los registros',
					body: 'No se pudo obtener el total de registros'
				});

				if ( error ) {

					notificacion.show();

					console.log( error );

					return reject( error );
				}

				const totalRegistros = resultado[0]['COUNT(*)'];

				let totalPaginas = ( totalRegistros / 10 );

				resolve({
					totalPaginas: Math.ceil( totalPaginas ),
					totalRegistros: totalRegistros
				});

			});

		});
	}


	/**
	 * Lista los usuarios en forma paginada
	 * @param  {Array<number>} pagination array de numeros de la paginacion
	 * @returns {Promise<Array<User>>} Retorna una promesa con el arreglo de usuarios
	 */
	static listarUsuarios( pagination ) {

		return new Promise(( resolve, reject ) => {

			pagination = { start: pagination[0], limit: pagination[1] };

			this.database.consult( CRUD.listarUsuarios, pagination, ( error, results ) => {

				if ( error ) {

					console.log( error );

					return reject( error );
				}

				resolve( results );
			});

		});
	}

	/**
	 * Cambia el rol del usuario
	 *
	 * @param {Object} usuario  usuario a cambiar
	 * @param {number} usuario.userid identificador del usuario
	 * @param {string} usuario.rol rol del usuario
	 */
	static cambiarRolUsuarios( usuario ) {

		this.database.update( CRUD.editarRolUsuario, usuario, ( error ) => {

			const notificacion = new Notification({
				title: 'Exito',
				body: 'Usuario actualizado'
			});

			if ( error ) {

				// throw error;  // mostrará el error en pantalla

				notificacion['title'] = 'Error!!';
				notificacion['body'] = 'Error al actualizar usuario';

				notificacion.show();

				console.log( error );

				return;
			}

			notificacion.show();
  	});
	}


	/**
	 * Permite cambiar el estado del usuario en la aplicación
	 *
	 * @param  {Object} usuario objeto de consulta
	 * @param {number} usuario.userid identificador del usuario
	 * @param {boolean} usuario.estado nuevo estado del usuario para acceder a la aplicación
	 */
	static cambiarEstadoUsuarios( usuario ) {

		this.database.update( CRUD.editarEstadoUsuario, usuario, ( error ) => {

			const notificacion = new Notification({
				title: '',
				body: ''
			});

			if ( error ) {

				//throw error;  // mostrará el error en pantalla

				notificacion['title'] = 'Error!!';
				notificacion['body'] = 'Error al actualizar usuario';

				notificacion.show();

				console.log( error );

				return;
			}

  	});
	}

	/**
	 * Permite buscar usuarios en la BD
	 * @param  {Object} usuario Usuario a buscar
	 * @param {string} usuario.search cadena de busqueda del usuario
	 * @return {Promise<Array<User>>}  devuelve una promesa con los resultados encontrados
	 * @example
	 * let users = await UsersController.buscarUsuarios({ search: '%' + search + '%' });
	 */
	static buscarUsuarios( usuario ) {

		return new Promise(( resolve, reject ) => {

			this.database.find( CRUD.buscarUsuario, usuario, ( error, results ) => {

				const notificacion = new Notification({
					title: '',
					body: ''
				});

				if ( error ) {

					notificacion['title'] = 'Error!!';
					notificacion['body'] = 'No se encontro el usuario';

					notificacion.show();

					console.log( error );

					return reject( error );
				}

				resolve( results );
			});

		});
	}

	/**
	 * Login de la aplicación
	 *
	 * @promise login
	 * @reject {Error|string}
	 * @fulfill {User}
	 *
	 * @param  {Object} usuario Objeto de inicio de sesion
	 * @param {string} usuario.correo correo del usuario
	 * @param {string} usuario.password contraseña del usuario
	 *
	 * @returns {Promise<User>}  retorna una promesa con el usuario logeado
	 */
	static login( usuario ) {

		// 1.- si el usuario existe dentro de la bd
		// 2.- si existe el usuario pero que este activo
		// 3.- verificar las contraseñas

		return new Promise (( resolve, reject ) => {

			this.database.find( CRUD.validarUsuario, usuario, ( error, results ) => {

				const notificacion = new Notification({
					title: '',
					body: ''
				});

				if ( error ) {

					notificacion['title'] = 'Error!!';
					notificacion['body'] = 'Error en buscar usuario';

					notificacion.show();

					// console.log( error );

					return reject( error );
				}

				if ( results.length === 0 ) {

					// length devuelve la cantidad de elementos en una matriz
					// sino lo encuentra muestra la notificacion

					notificacion['title'] = 'Atención!!';
					notificacion['body'] = 'Credenciales inválidas';

					// console.log("usuario no encontrado");

					notificacion.show();

					reject('credenciales inválidas');

				} else {

					const [ user ] = results;

					const passwordDB = user['password'];

					// compareSync devuelve un boleano el resultado de la comparación
					const match = bcrypt.compareSync( usuario['password'], passwordDB );

					if ( !match ) {

						notificacion['title'] = 'Atención!!';
						notificacion['body'] = 'Credenciales inválidas';

						notificacion.show();

						// console.log("clave invalida");

						reject('credenciales invalidas');

					} else {

						// console.log("usuario valido");

						// Se elimina la propiedad password del objeto results para la vista

						delete user['password'];
						delete user['estado'];

						resolve( user );
					}
				};

			});

		});

	}

	/**
	 * Actualiza el perfil del usuario logeado
	 *
	 * @param  {User} perfil perfil del usuario logeado
	 * @return {Promise<User>}        Una promesa con los datos del perfil actualizados
	 */
	static actualizarPerfil( perfil ) {

		return new Promise(( resolve, reject ) => {

			const saltRounds = 10;
			const salt = bcrypt.genSaltSync( 10 );

			delete perfil['passwordConfirmation'];

			perfil['password'] = bcrypt.hashSync( perfil['password'], salt );

			this.database.update( CRUD.actualizarPerfil, perfil, ( error ) => {

				let notificacion = new Notification({
					title: '',
					body: ''
				});

				if ( error ) {

					notificacion['title'] = 'Error!!';
					notificacion['body'] = 'Error al actualizar perfil';

					console.log( error );

					notificacion.show();

					return reject( error );
				}

				notificacion['title'] = 'Exito';
				notificacion['body'] = 'Perfil del usuario actualizado';

				notificacion.show();

				delete perfil['password'];

				resolve( perfil );
			});
		});
	}
}

module.exports = {
	UsersController
};