codenautas/backend-plus

View on GitHub
ejemplos/encuesta.js

Summary

Maintainability
D
2 days
Test Coverage
"use strict";

const _ = require('lodash');
const util = require('util');
var readYaml = require('read-yaml-promise');
var MiniTools = require('mini-tools');
var fs = require('fs-promise');
var Promises = require('best-promise');

// var idEncuesta = Math.random();
var idEncuesta = 1001;

var backendPlus = require("..");

var backendEncuesta={};

require('best-globals').setGlobals(global);


class AppEncuesta extends backendPlus.AppBackend{
    constructor(){
        super();
    }
    configList(){
        return super.configList().concat([
            'ejemplos/def-config.yaml',
            'ejemplos/local-config.yaml'
        ]);
    }
    tipoCeldas(){
        //var tiposCeldas = {
        return {
            titulo:{
                completar: function completar(){
                    
                }
            },
            pregunta:{
                completar: function completar(celda, be, idFormulario, celdasAgregadas){
                    if(!celda.variable){
                        celda.variable = celda.pregunta.toLowerCase();
                    }
                    if(!celda.typeInfo && !celda.typeName && !celda["tipo-dato"] && !celda.opciones){
                        throw new Error("falta indicar typeInfo en celda");
                    }
                    if(!celda.typeInfo || typeof celda.typeInfo === 'string'){
                        celda.typeInfo={typeName:celda.typeInfo};
                        if(!celda.typeInfo.typeName){
                            celda.typeInfo.typeName=celda["tipo-dato"]||celda.typeName;
                            if(!celda.typeInfo.typeName){
                                if(celda.opciones){
                                    celda.typeInfo.typeName="enum";
                                    celda.typeInfo.options=celda.opciones;
                                }else{
                                    throw new Error("falta indicar typeInfo en celda, no se pudo calcular");
                                }
                            }
                        }
                        (celda.typeInfo.options||[]).forEach(function(opcion){
                            opcion.option = coalesce(opcion.option,opcion.opcion,coalesce.throwError);
                            opcion.label  = coalesce(opcion.label ,opcion.texto ,coalesce.throwError);
                            opcion.more = !!(opcion.salto || opcion.especifique);
                        });
                    }
                    if(celda.typeInfo.typeName=='multiple'){
                        celda.tipo='texto';
                        celda.subtipo='multiple';
                        celda.opciones.forEach(function(opcion){
                            var variable=(celda.pregunta+'_'+opcion.opcion).toLowerCase();
                            var celdaNueva={
                                tipo: 'pregunta',
                                subtipo: 'multiple',
                                pregunta: celda.pregunta,
                                variable: variable,
                                texto: opcion.texto,
                                typeInfo: {
                                    typeName: 'boolean'
                                },
                            };
                            if(celda['expresion-habilitar']){
                                celdaNueva['expresion-habilitar']=celda['expresion-habilitar'];
                            }
                            celdasAgregadas.push(celdaNueva);
                            be.registrosVacios[idFormulario][variable]=null;
                        });
                    }else{
                        be.registrosVacios[idFormulario][celda.variable]=null;
                    }
                }
            },
            texto: {
                completar: function completar(){
                },
                explicitar:true,
            },
            matriz:{
                completar: function completar(){
                    
                }
            },
            especial:{
                completar: function completar(){}
            }
        }; 
    }
    readStructure(fileName){
        var be = this;
        be.almacenVacio={
            formularios:{}
        };
        be.registrosVacios={};
        return readYaml(fileName).then(function(estructura){
            _.forEach(estructura.formularios, function(formulario, idFormulario){
                // var nuevoArregloCeldas=[]; // comentada por no usada
                be.registrosVacios[idFormulario]={};
                if(formulario.multiple){
                    be.almacenVacio.formularios[idFormulario]=[{registro: be.registrosVacios[idFormulario]}]; // OJO generalizar, el problema es el boton continuar
                }else{
                    be.almacenVacio.formularios[idFormulario]={registro: be.registrosVacios[idFormulario]};
                }
                
                formulario.celdas = formulario.celdas.reduce(function(nuevoArreglo ,celda){
                    if(!celda.tipo){
                        for(var tipoCelda in be.tipoCeldas()){
                    //    for(var tipoCelda in be.tiposCeldas){
//                            if(tipoCelda in celda && !(be.tiposCeldas[tipoCelda].explicitar)){
                            if(tipoCelda in celda && !(be.tipoCeldas()[tipoCelda].explicitar)){
                                celda.tipo = tipoCelda;
                            }
                        }
                    }
                    var defTipoCelda = be.tipoCeldas()[celda.tipo];
                    
                    if(!defTipoCelda){
                        if(!celda.tipo){
                            /*jshint forin: false */
                            for(var tipoCelda2 in celda){
                                throw new Error("falta el tipo de celda, se desconoce: "+tipoCelda2);
                            }
                            /*jshint forin: true */
                        }
                        throw new Error("tipo de celda desconocido: "+celda.tipo);
                    }
                    var celdasAgregadas=[];
                    defTipoCelda.completar(celda, be, idFormulario, celdasAgregadas);
                    celda.tipo=celda.tipo||'';
                    celda.subtipo=celda.subtipo||'';
                    nuevoArreglo.push(celda);
                    while(celdasAgregadas.length){
                        nuevoArreglo.push(celdasAgregadas.shift());
                    }
                    return nuevoArreglo;
                }, []);
            });
            estructura.registrosVacios=be.registrosVacios;
            return estructura;
            
        });
    };
    postConfig(){
        this.releerMetadatos();
    }
    updateDatabase(updateSql, parametros) {
        var id=parametros[0];
        var be=this;
        var client;
        return this.getDbClient().then(function(cli) {
            client=cli;
            return client.query("BEGIN TRANSACTION").execute();
        }).then(function() {
            return client.query("LOCK TABLE bep.datos").execute();
        }).then(function() {            
            return client.query("SELECT id, contenido, estado FROM bep.datos WHERE id = $1",[id]).fetchOneRowIfExists();
        }).then(function(data) {
            if(data.rowCount == 0) {
                var sql = "INSERT INTO bep.datos (id, contenido, cambios) SELECT $1, $2, $3 WHERE NOT EXISTS (SELECT 1 FROM bep.datos WHERE id=$4)";
                return client.query(sql,[id, be.almacenVacio, be.almacenVacio, id]).execute();
            }
        }).then(function() {
            return client.query(updateSql, parametros).execute();
        }).then(function(datos) {
            return client.query("COMMIT").execute().then(function(){ return datos; });
        }).then(function(datos) {
        }).catch(function(err) {
            console.log("error: "+err);
            console.log(err.stack);
            console.log('-----------------------------');
            console.log();
        }).then(function(){
            return parametros;
        }).catch(function(err) {
            console.log("error al cerrar: "+err);
        }).then(function(){
            client.done();
        });
    }
    obtenerParametros(req){
        var parametros=JSON.parse(req.body.info);
        if(req.user.iddato && req.query.id && req.user.iddato != req.query.id){
            throw new Error("No coinciden los ID");
        }
        /////////// OJO, FALTA VER SI TIENE PERMISO EN CASO DE QUE NO SEA UNA ORGANIZACIÓN SIMPLE
        return parametros;
    }
    releerMetadatos(){
        var be=this;
        return Promises.start(function(){
            return be.readStructure(be.config.estructura.origen);
        }).then(function(estructura){
            be.estructura = estructura;
            return "metadatos ok";
        }).catch(function(err){
            console.log('ERROR AL LEER LA ESTRUCTURA');
            console.log(err);
            console.log(err.stack);
        });
    }
    guardarContenido(res, id, contenido, estado, actualizarCambiosTambien){
        var be=this;
        var parametros=[id, contenido, estado];
        var formularioPrincipal=be.estructura["con-for"][id["tipo-abonado"]]["formulario-principal"];
        var cantidadFormulariosAbono = contenido.formularios[formularioPrincipal].registro.t13; // OJO GENERALIZAR
        var formularioMultiple = be.estructura["con-for"][id["tipo-abonado"]].formularios[1]; // OJO GENERALIZAR
        while(contenido.formularios[formularioMultiple].length<cantidadFormulariosAbono){
            actualizarCambiosTambien=true;
            contenido.formularios[formularioMultiple].push({registro: be.registrosVacios[formularioMultiple]});
        }
        var sqlUpdate="UPDATE bep.datos SET contenido = $2, estado = $3 /*, cambios = #4*/ WHERE id = $1 RETURNING contenido";
        if(actualizarCambiosTambien){
            parametros.push(contenido);
            sqlUpdate=sqlUpdate.replace('/*, cambios = #4*/',', cambios = $4');
        }
        return Promises.start(function(){
            return be.updateDatabase(sqlUpdate,parametros);
        }).then(function(result){
            res.end("recibi: "+JSON.stringify(parametros));
        },function(err){
            res.end("error: "+err.message);
        });
    }
    addLoggedServices(){
        super.addLoggedServices();
        var be = this;
        this.app.post('/info', function(req, res){
            res.end('ok!');
        });
        this.app.post('/info-enc-act', function(req, res){
            var rta=be.config["modo-devel"]?{"modo-devel": new Date(be.config["modo-devel"].hasta)>new Date()}:{};
        //    var rta={"modo-devel": new Date(be.config["modo-devel"].hasta)>new Date()  };
            var parametros=be.obtenerParametros(req);
            rta.id = req.user.iddato || parametros.id;
            rta.estructura = be.estructura;
            var client;
            be.getDbClient().then(function(cli){
                client=cli;
                return client.query("SELECT contenido, estado FROM bep.datos WHERE id = $1", [rta.id]).fetchOneRowIfExists();
            }).then(function(result){
                if(result.rowCount>0){
                    rta.almacen=result.row.contenido;
                    rta.estado=result.row.estado;
                }else{
                    rta.almacen=be.almacenVacio;
                    rta.estado='vacio';
                }
                res.end(JSON.stringify(rta));
            }).catch(MiniTools.serveErr(req,res)).then(function(){
                client.done();
            });
        });
        this.app.post('/set-status', function(req, res){
            var parametros=be.obtenerParametros(req);
            be.updateDatabase(
                "UPDATE bep.datos SET estado=$2 WHERE id = $1 RETURNING contenido",
                [parametros.id, parametros.estado]
            ).then(function(result){
                res.end("recibi: "+JSON.stringify(parametros));
            },function(err){
                res.end("error: "+err.message);
            });
        });
        this.app.post('/guardar', function(req, res){
            var parametros=be.obtenerParametros(req);
            be.guardarContenido(res, parametros.id, parametros.almacen, 'pendiente')
        });
        this.app.post('/guardar-cambios', function(req, res){
            var parametros=be.obtenerParametros(req);
            // basado en:
            // select jsonb_set('{"formularios": {"TCNAI" : {"variables": {}}, "TCNAA" : [{"variables": {"v1":"a"}}, {"variables": {"v2":"b"}} ] }}', '{formularios,TCNAA,1,variables,t3}', '3')
            var ruta=['formularios', parametros.ruta.formulario];
            if(parametros.ruta.orden){
                ruta.push((parametros.ruta.orden-1).toString());
            }
            ruta.push('registro');
            ruta.push(parametros.ruta.variable);
            console.log('por hacer un /guardar-cambios');
            console.log(parametros,ruta);
            be.updateDatabase(
                "UPDATE bep.datos SET cambios = jsonb_set(cambios, $2, $3::jsonb), estado='pendiente' WHERE id = $1 RETURNING contenido",
                [parametros.id, ruta, JSON.stringify(parametros.valor)]
            );
            res.end("recibi: "+JSON.stringify(parametros));
        });
        this.app.post('/finalizar', function(req, res){
            var parametros=be.obtenerParametros(req);
            be.guardarContenido(res, parametros.id, parametros.almacen, 'ingresado').then(function(){
            // be.guardarContenido(res, parametros.id, parametros.almacen, 'pendiente').then(function(){
                res.end("Encuesta finalizada");
            });
        });
        this.app.post('/blanquear', function(req, res){
            var parametros=be.obtenerParametros(req);
            be.guardarContenido(res, parametros.id, be.almacenVacio, 'vacio', true).then(function(){
                res.end("Encuesta blanqueada");
            });
        });
        this.app.get('/metadatos/obtener', function(req, res){
            fs.readFile(be.config.estructura.origen,'utf8').then(function(data){
                res.end(data);
            }).catch(function(err){
                console.log(err.message);
            });
            
        });
        this.app.post('/metadatos/reescribir',function(req,res){
            var contenido=req.body.contenido;
            var file=be.config.estructura.origen;
            Promise.all([
                be.config.estructura.origen,
                be.config.estructura.origen.replace(/^(.*[\/\\])([^\/\\]+).yaml$/,function(matchCompleto,path,fileName){
                    return path+'copias/'+fileName;
                })+(new Date()).toISOString().replace(/[:.]/g,'-')+'.yaml'
            ].map(function(fileName){
                return fs.writeFile(fileName,contenido,'utf8').then(function(){
                    console.log('grabado ok', fileName);
                    return 'ok';
                }, function(err){
                    console.log('grabado con error',fileName, err);
                    return 'error al grabar '+fileName+': '+err.message;
                })
            })).then(function(resultados){
                return Promises.start(function(){
                    return be.releerMetadatos();
                }).then(function(result){
                    resultados.push(result);
                    console.log("resultados",resultados)
                    return resultados;
                });
            }).then(function(resultados){
                console.log("resultados",resultados)
                res.end('grabado '+JSON.stringify(resultados));
            })
        });
        this.app.get('/about-info', function(req, res){
            if(req.user.rol=='admin'){
                var client;
                be.getDbClient().then(function(cli){
                    client=cli;
                    return client.query("select * from bep.parametros").fetchUniqueRow();
                }).then(function(sysParams){
                    if(sysParams.row.full_log){
                        res.header('Content-Type','text/plain');
                        res.end(JSON.stringify(be.config,null,'    ').replace(/\n(.*".*pass.*":\s*").*(",?)\n/g,'\n$1********$2\n'));
                    }else{
                        res.status(401);
                        res.end("Not full log");
                    }
                }).catch(MiniTools.serveErr(req,res)).then(function(){
                    client.done();
                });
            }else{
                res.status(401);
                res.end("No autorizado");
            }
        });
    }
    get rootPath(){ return __dirname +'/'; }
}

backendEncuesta.AppEncuesta = AppEncuesta;

module.exports=backendEncuesta;