import moment from "moment"; import { Connection } from "typeorm"; import {Email, BaseRepository, Encryptor } from "@leal.api/api_utils"; import { Usuario, ResponseModel, UsuarioSetupSMS, UsuarioRestablecerContrasena } from "@leal.api/api_models"; import { IUsuarioRepository } from "../interfaces"; import { LoginViewModel, PerfilViewModel, RecordarUsuarioViewModel, RegistroViewModel, RestablecerContrasenaViewModel, CambiarContrasenaViewModel, FavoritoViewModel } from "../models"; import { RefreshTokenRepository, RedSocialRepository, UsuarioRedSocialRepository, UsuarioTarjetaRepository, PaisRepository, CiudadRepository } from "."; export class UsuarioRepository extends BaseRepository implements IUsuarioRepository { public encryptor: Encryptor; private mailerEmail: Email; private paisRepo: PaisRepository; private ciudadRepo: CiudadRepository; private refreshTokenRepo: RefreshTokenRepository; private redSocialRepository: RedSocialRepository; private usuarioTarjetaRepository: UsuarioTarjetaRepository; private usuarioRedSocialRepository: UsuarioRedSocialRepository; constructor(connection: Connection) { super(connection, Usuario); this.encryptor = new Encryptor(); this.mailerEmail = new Email(); this.paisRepo = new PaisRepository(connection); this.ciudadRepo = new CiudadRepository(connection); this.refreshTokenRepo = new RefreshTokenRepository(connection); this.redSocialRepository = new RedSocialRepository(connection); this.usuarioTarjetaRepository = new UsuarioTarjetaRepository(connection); this.usuarioRedSocialRepository = new UsuarioRedSocialRepository( connection ); } //Realiza la validacion de acceso a la plataforma movil async inicioSesion( email: string, contrasenia: string, push_token: any ): Promise> { //TODO: check against database and validate email and criterio and pueh_token match try { let Q = `SELECT t1.uid, t1.token FROM usu_usuarios AS t1 LEFT JOIN usu_usuarios_red_social AS t2 ON t1.uid = t2.uid WHERE t1.email = ? AND t1.estado = 'activo' AND ( t1.contrasena = ? OR t1.contrasena = ? OR t2.token = ? )`; const result = (await this.repo.query(Q, [ email, this.encryptor.md5(contrasenia), this.encryptor.encrypt(contrasenia), contrasenia ])) as [{ uid: string; token: string }]; if (result.length > 0) { let resultado = result[0]; //Validacion del push_token if (typeof push_token !== undefined || push_token !== "") { try { await this.update(resultado.uid, { token: push_token }); } catch (error) { console.log("usu_usuarios.token.update:error:", error); } } let refreshToken = ( moment().unix() + this.encryptor.md5(resultado.uid + "-" + moment().unix()) ).toString(); //TODO: insert or update refresh token in DB let loginViewModel = await this.refreshTokenRepo.update_or_insert_refresh_token( resultado.uid, refreshToken ); return loginViewModel; } else { return new ResponseModel( 104, undefined, "No se encontraron resultados" ); } } catch (error) { return new ResponseModel(105, undefined, error); } } async inicioSesion2( email: string, contrasenia: string, push_token: string ): Promise> { //TODO: check against database and validate email and password match try { let result = await this.repo .createQueryBuilder("user") .where( "user.estado NOT LIKE 'inac%' AND user.email = :email AND (user.contrasena = :md5 OR user.contrasena = :encrypt)", { email: email, md5: this.encryptor.md5(contrasenia), encrypt: this.encryptor.encrypt(contrasenia) } ) .select(["user.id", "user.fullname", "user.estado"]) .getOne(); if (result) { if (typeof push_token !== undefined || push_token !== "") { try { await this.update(result.id, { token: push_token }); } catch (error) { console.log("usu_usuarios.token.update:error:", error); } } let refreshToken = ( moment().unix() + this.encryptor.md5(result.id + "-" + moment().unix()) ).toString(); //TODO: insert or update refresh token in DB let loginViewModel = await this.refreshTokenRepo.update_or_insert_refresh_token( result.id, refreshToken ); return loginViewModel; } else { return new ResponseModel( 104, undefined, "No se encontraron resultados" ); } } catch (error) { return new ResponseModel(105, undefined, error); } } /** * Get number of commerces with at least one award * * @param {string} uid * @returns {Promise>} * @memberof UsuarioRepository */ async numCommercesWithAward(uid: string): Promise> { try { const res = (await this.repo .createQueryBuilder("t1") .innerJoin("usu_usuarios_comercios", "t2", "t1.uid = t2.uid") .innerJoin("com_premios", "t3", "t2.id_comercio=t3.id_comercio") .innerJoin("com_comercios", "t4", "t2.id_comercio=t4.id_comercio") .where("t1.uid = :uid", { uid: uid }) .andWhere("t2.puntos_activos>=t3.puntos") .select("COUNT(DISTINCT(t4.id_comercio)) as count") .execute()) as [{ count: number }]; if (res) { const number = res.length > 0 ? res[0].count : 0; return new ResponseModel(100, number); } else { return new ResponseModel(104, 0, "No se encontraron resultados"); } } catch (error) { console.log(error); return new ResponseModel(105, 0, error); } } /** * Get the favorites commerces by user * * @param {string} uid * @param {string} urlLogo * @returns {(Promise< * ResponseModel< * | [ * { * id_comercio: string; * nombre: string; * logo: string; * } * ] * | undefined * > * >)} * @memberof UsuarioRepository */ async favoriteCommerces( uid: string, urlLogo: string ): Promise> { try { let res = (await this.repo .createQueryBuilder("t1") .innerJoin("usu_usuarios_comercios", "t2", "t1.uid = t2.uid") .innerJoin("com_comercios", "t3", "t2.id_comercio = t3.id_comercio") .where("t1.uid = :uid", { uid: uid }) .andWhere("t2.estado = 'activa'") .orderBy("t2.puntos_totales") .select("t3.id_comercio as idComercio, t3.nombre, t3.logo") .execute()) as FavoritoViewModel[]; if (res) { res.forEach(com => { com.logo = urlLogo + com.logo; }); return new ResponseModel(100, res); } else { return new ResponseModel( 104, res, "No se encontraron resultados" ); } } catch (error) { return new ResponseModel(105, undefined, error); } } /** * Get the percentaje of profile data * * @param {string} uid * @memberof UsuarioRepository */ async profilePercentaje(uid: string): Promise> { try { let users = (await this.repo .createQueryBuilder("user") .select( "user.cedula, user.nombre, user.apellido, user.email, user.celular, user.genero, user.cumpleanos, user.cod_ciudad codCiudad" ) .where("user.uid = :uid", { uid: uid }) .execute()) as [Usuario]; let dataNumber = 0; const user = users[0]; if (user) { if (user.cedula && user.cedula.trim() !== "") dataNumber++; if (user.nombre && user.nombre.trim() !== "") dataNumber++; if (user.apellido && user.apellido.trim() !== "") dataNumber++; if (user.email && user.email.trim() !== "") dataNumber++; if (user.celular && user.celular.trim() !== "") dataNumber++; if (user.genero && user.genero.trim() !== "") dataNumber++; if (user.cumpleanos != null) dataNumber++; if (user.codCiudad != null) dataNumber++; let percentaje = Math.round((dataNumber * 100) / 8); return new ResponseModel(100, percentaje); } else return new ResponseModel( 104, dataNumber, "No se encontraron resultados" ); } catch (error) { return new ResponseModel(105, 0, error); } } //Consulta la informacion de usuario con su uid async perfil(uid: string): Promise> { try { let user = await this.repo .createQueryBuilder("user") .where("user.uid = :uid", { uid: uid }) .getOne(); if (user) { let paisInfo = await this.paisRepo.findOne(user.codPais); let ciudadInfo = await this.ciudadRepo.findOne(user.codCiudad); let perfilViewModel = new PerfilViewModel( uid, user.nombre, user.apellido, user.email, user.cedula, user.celular, user.genero, user.foto, user.estado, paisInfo.id, paisInfo.nombre, ciudadInfo.id, ciudadInfo.nombre, user.cumpleanos ); return new ResponseModel(100, perfilViewModel); } else { return new ResponseModel( 104, undefined, "No se encontraron resultados" ); } } catch (error) { return new ResponseModel(105, undefined, error); } } //Validacion de cedula del usuario async validacionCedula(cedula: string): Promise> { try { let result = { code: 100, message: "La cedula no existe" }; //Validacion de la cedula let resultConsulta = await this.repo .createQueryBuilder("user") .where("user.cedula = :cedula", { cedula: cedula }) .select(["user.id"]) .getOne(); if (resultConsulta) { result = { code: 108, message: "La cedula ingresada ya existe" }; } return new ResponseModel(result.code, undefined, result.message); } catch (error) { return new ResponseModel(105, undefined, error); } } //Validacion de email del usuario async validacionMail(email: string): Promise> { try { //Validacion de la cedula let result = await this.repo .createQueryBuilder("user") .where("user.email = :email", { email: email }) .select(["user.id"]) .getOne(); if (result) { return new ResponseModel(108, false); } else { return new ResponseModel(100, true); } } catch (error) { return new ResponseModel(105, undefined, error); } } //Retorna el email enmascarado async recordarUsuario( documento: string ): Promise> { try { let result = await this.repo .createQueryBuilder("user") .where("user.cedula = :cedula", { cedula: documento }) .select(["user.email"]) .getOne(); if (result) { //Extraemos la parte final del email var parteMostrarFinal = result.email.substring( result.email.length - 0, result.email.indexOf("@") ); var parteMostrarInicio = result.email.substring(0, 3); //Extraemos la parte a enmascarar var marks = result.email .substring( result.email.length - (result.email.length - result.email.indexOf("@")), 3 ) .replace(/[a-z]/g, "*") .replace(/[0-9]/g, "*"); //Concatenamos las partes del email let marksText = parteMostrarInicio + marks + parteMostrarFinal; let recordarUsuarioViewModel = new RecordarUsuarioViewModel(marksText); return new ResponseModel( 100, recordarUsuarioViewModel ); } else { return new ResponseModel( 104, undefined, "No se encontraron resultados" ); } } catch (error) { return new ResponseModel(105, undefined, error); } } //Registrar usuarios async registro( email: string, cedula: string, nombre: string, apellido: string, celular: string, contrasena: any, cumpleanos: Date, codCiudad: number, genero: string, siglas: any, token: any ): Promise> { try { //Asignacion de variables let uid: string = this.encryptor.md5(email); let fullname: string = nombre + " " + apellido; let fechaRegistro: Date = new Date(); let estado: string = "activo"; let contrasenaEncript: any = contrasena !== undefined ? this.encryptor.encrypt(contrasena) : undefined; //Validamos que no exista ya en base de datos let buscarUsuario = await this.find({ email: email }, ["email"]); if (buscarUsuario.length <= 0) { //registro de token if (token !== undefined) { //valida el registro de token si existe let resultRedSocial: any = await this.redSocialRepository.consultar_RedSocial( siglas ); if (resultRedSocial.data) { await this.usuarioRedSocialRepository.insertar_UsuarioRedSocial( uid, token, resultRedSocial.data.id, fechaRegistro ); } else { throw resultRedSocial; } } //Creacion de arreglo insercion usu_usuario let registrar: any = { id: uid, email: email, cedula: cedula, nombre: nombre, apellido: apellido, celular: celular, contrasena: contrasenaEncript, cumpleanos: cumpleanos, codCiudad: codCiudad, genero: genero, fullname: fullname, fechaRegistro: fechaRegistro, estado: estado }; //incorporacion de usuario en usu_usuarios await this.repo .createQueryBuilder() .insert() .into(Usuario) .values([registrar]) .execute(); //Ingresar usuario a usu_usuarios_setupsms await this.repo .createQueryBuilder() .insert() .into(UsuarioSetupSMS) .values([ { id: uid, estado: "si" } ]) .execute(); //Envio de mensaje await this.mailerEmail.sendEmail( JSON.stringify({ from: "info@puntosleal.com", fromName: "Leal", to: email, subject: "Ya eres un miembro leal", body: await this.crearCorreoBienvenida(registrar), //Incorporamos la plantilla uid: uid }) ); //Porceso incorporacion de la tarjeta al usuario let idTarjeta: any = await this.usuarioTarjetaRepository.insertar_usuario_tarjeta( uid ); registrar.tarjeta = idTarjeta.message; //Extraccion de token y refresh token para accesar a partes privadas en el momento del registro let login: any = await this.inicioSesion(email, contrasena, undefined); registrar.login = JSON.parse(JSON.stringify(login.data)); return new ResponseModel(100, registrar); } else { return new ResponseModel( 108, undefined, "Usuario ya existe en la base de datos" ); } } catch (error) { return new ResponseModel(105, undefined, error); } } //Restablecer contraseña async restablecerContrasena( email: string ): Promise> { try { //Extraemos la parte final del email var parteMostrarFinal = email.substring( email.length - 0, email.indexOf("@") ); var parteMostrarInicio = email.substring(0, 3); //Extraemos la parte a enmascarar var marks = email .substring(email.length - (email.length - email.indexOf("@")), 3) .replace(/[a-z]/g, "*") .replace(/[0-9]/g, "*"); //Concatenamos las partes del email let marksText = parteMostrarInicio + marks + parteMostrarFinal; let uid: string = this.encryptor.md5(email); //Creamos el uid del usuario para la busqueda //incorporacion de usuario en usu_usuarios let idTableInsert: any = await this.repo .createQueryBuilder() .insert() .into(UsuarioRestablecerContrasena) .values([ { uid: uid, fechaRegistro: new Date(), fechaVencimiento: new Date( moment() .add(24, "hours") .format("YYYY-MM-DD HH:mm:ss") ), cambioContrasena: "no" } ]) .execute(); let mensaje: string = `Ingrese su nueva contraseña: cambiar_contraseña este enlace estara habilitado solo 24 horas por favor cambiela.`; //Envio de mensaje await this.mailerEmail.sendEmail( JSON.stringify({ from: "info@puntosleal.com", fromName: "Leal", to: email, subject: "Cambio contraseña", body: mensaje }) ); return new ResponseModel(100, { transactionId: idTableInsert, email: marksText }); } catch (error) { return new ResponseModel( 105, undefined, error ); } } //Restablecer contraseña async cambiarContrasena( password: string, email: string, idTransaccion: number ): Promise> { try { //Consulta que el usuario aya cambiado su contraseña en antes del vencimiento let result: any = await this.connection .getRepository(UsuarioRestablecerContrasena) .createQueryBuilder("t1") .where("t1.id = :id AND t1.cambioContrasena = :cambioContrasena", { id: idTransaccion, cambioContrasena: "no" }) .select(["t1.uid", "t1.fechaVencimiento"]) .getOne(); if (result !== undefined) { //Confirmamos que el usuario aya cambiado su contraseña en antes del vencimiento if ( moment(result.fechaVencimiento).format("YYYY-MM-DD HH:mm:ss") < moment().format("YYYY-MM-DD HH:mm:ss") ) { return new ResponseModel( 108, undefined, "No es posible cambiar la contraseña." ); } // Actualizacion de contraseña let q = await this.update(result.uid, { contrasena: this.encryptor.encrypt(password) }); //Actualiza el cambio de estado por restabecer la contrasena await this.connection .createQueryBuilder() .update(UsuarioRestablecerContrasena) .set({ cambioContrasena: "si" }) .where("id = :id", { id: idTransaccion }) .execute(); return new ResponseModel(100, { transactionId: idTransaccion, email: email }); } else { return new ResponseModel( 104, undefined, "No se encontraron resultados" ); } } catch (error) { return new ResponseModel( 105, undefined, error ); } } //funcion de crear correo de bienvenida segun tipo de usuario async crearCorreoBienvenida(obj: any) { try { var emailEncoded = obj.email.replace("@", "%40"); var fechaRegistroEn = obj.fechaRegristro; var data = obj.estado === "activo" ? "plantilla uno" : "plantilla dos"; //fs.readFileSync('utils/templates/correo_bienvenida_usuario_completo.html').toString() : fs.readFileSync('utils/templates/correo_bienvenida_usuario_incompleto.html').toString(); var template1 = data.replace("{{nombre}}", obj.fullname); var template2 = template1.replace("{{cedula}}", obj.cedula); var template3 = template2.replace("{{pass}}", "#######"); var template4 = template3.replace("{{emailEncoded}}", emailEncoded); var template = template4.replace("{{fechaRegistro}}", fechaRegistroEn); return template; } catch (e) { console.log("error de salida de plantilla", e); } } async premios(uid: string): Promise> { try { const data = await this.repo .createQueryBuilder("t1") .innerJoin("usu_usuarios_comercios", "t2", "t1.uid=t2.uid") .innerJoin("com_premios", "t3", "t2.id_comercio=t3.id_comercio") .innerJoin("com_comercios", "t4", "t2.id_comercio=t4.id_comercio") .where("t1.uid = :uid", { uid: uid }) .andWhere("t2.estado = 'activa'") .andWhere("t3.estado='activo'") .andWhere("t2.puntos_activos>=t3.puntos") .select( "t4.id_comercio, t4.nombre, t2.puntos_activos, t3.premio, t3.descripcion_premio, t3.puntos" ) .execute(); if (data) return new ResponseModel(100, data); else { return new ResponseModel(104, data, "No se encontraron resultados"); } } catch (error) { console.log(error); return new ResponseModel(105, null, "error retrying premios"); } } async regalos(uid: string): Promise> { try { const data = await this.repo .createQueryBuilder("t1") .innerJoin("com_regalos_usuarios", "t2", "t1.uid=t2.uid") .innerJoin("com_regalos", "t3", "t2.id_regalo=t3.id_regalo") .innerJoin("com_comercios", "t4", "t2.id_comercio=t4.id_comercio") .where("t1.uid = :uid", { uid: uid }) .andWhere("t3.estado ='Activo'") .andWhere("t2.canjeado = 'no'") .andWhere("t3.tipo_regalo <> 'Puntos'") .andWhere("t2.fecha_vencimiento >= now()") .select( "t4.id_comercio, t4.nombre, t3.nombre_regalo, t3.descripcion_regalo, t2.fecha_vencimiento" ) .execute(); if (data) return new ResponseModel(100, data); else { return new ResponseModel(104, data, "No se encontraron resultados"); } } catch (error) { console.log(error); return new ResponseModel(105, null, "error retrying regalos"); } } async campanas(uid: string): Promise> { try { const data = await this.repo .createQueryBuilder("t1") .innerJoin("com_campanas_usuarios", "t2", "t1.uid=t2.uid") .innerJoin("com_campanas", "t3", "t2.id_campana = t3.id") .innerJoin( "com_campanas_contenido", "t4", "t2.id_campana = t4.id_campana" ) .innerJoin("com_comercios", "t5", "t3.id_comercio=t5.id_comercio") .where("t1.uid = :uid", { uid: uid }) .andWhere("t2.reclamado='n'") .andWhere("t3.estado ='activa'") .andWhere("t4.cod_promocional <> '-'") .andWhere("t3.estado_envio = 'enviada'") .andWhere("t3.fecha_fin >= now() and t3.fecha_inicio <= now()") .select( "t5.id_comercio, t5.nombre, t4.promocion, t4.cod_promocional, t3.fecha_fin as fecha_vencimiento" ) .execute(); if (data) return new ResponseModel(100, data); else { return new ResponseModel(104, data, "No se encontraron resultados"); } } catch (error) { console.log(error); return new ResponseModel(105, null, "error retrying campanas"); } } async campanasAuto(uid: string): Promise> { try { const data = await this.repo .createQueryBuilder("t1") .innerJoin("com_campanas_usuarios", "t2", "t1.uid=t2.uid") .innerJoin("com_campana_auto", "t3", "t2.id_campana = t3.id_campana") .innerJoin("com_campanas", "t4", "t2.id_campana = t4.id") .where("t1.uid = :uid", { uid: uid }) .andWhere("t2.reclamado='n'") .andWhere("t3.id_campana IS NOT NULL") .andWhere("t4.fecha_fin >= now()") .andWhere("t4.estado_envio = 'enviada'") .groupBy("t2.id_campana") .select( "t4.id_comercio, max(t2.fecha) as fecha_vencimiento, t3.asunto, t3.cod_promocional" ) .execute(); if (data) return new ResponseModel(100, data); else { return new ResponseModel(104, data, "No se encontraron resultados"); } } catch (error) { console.log(error); return new ResponseModel(105, null, "error retrying campanas auto"); } } }