diff --git a/config.json.example b/config.json.example deleted file mode 100644 index 1fa157c1e562f3843ef2f44bf60e1793fbf9c1e7..0000000000000000000000000000000000000000 --- a/config.json.example +++ /dev/null @@ -1,157 +0,0 @@ -{ - "development": - { - "port": 3000, - "ip": "127.0.0.1", - "debug" : true, - "monetdb": { - "host": "simcaqdb3.c3sl.ufpr.br", - "port": 50000, - "dbname": "simcaq", - "user": "monetdb", - "password":"monetdb", - "nrConnections": "4" - }, - "cdn" : { - "url": "http://simcaqdb3.c3sl.ufpr.br:3000", - "download": "https://simcaqdev.c3sl.ufpr.br/download/" - }, - "mongodb" : { - "uri": "mongodb://localhost/dev_users" - }, - "monq": { - "uri": "mongodb://localhost/dev_monq" - }, - "default": { - "api": { - "version" : "v1" - }, - "lde": { - "url": "http://ldedev.c3sl.ufpr.br/#" - }, - "simcaq": { - "url": "http://simcaqdev.c3sl.ufpr.br/#" - } - }, - "email": { - "host": "SMTP.office365.com", - "port": 587, - "secureConnection": false, - "auth": { - "user": "dadoseducacionais@ufpr.br", - "pass": "COLOCAR_A_SENHA_AQUI" - }, - "tls": { - "ciphers": "SSLv3" - }, - "from": "\"Laboratório de Dados Educacionais\" <dadoseducacionais@ufpr.br>" - }, - "security": { - "tokenLife": 3600 - } - }, - "test": - { - "port": 3000, - "ip": "127.0.0.1", - "debug" : true, - "monetdb": { - "host": "simcaqdb3.c3sl.ufpr.br", - "port": 50000, - "dbname": "simcaq", - "user": "monetdb", - "password":"monetdb", - "nrConnections": "4" - }, - "cdn" : { - "url": "http://simcaqdb3.c3sl.ufpr.br:3000", - "download": "https://simcaqdev.c3sl.ufpr.br/download/" - }, - "mongodb" : { - "uri": "mongodb://localhost/test_users", - "secret": "SimCAQC3SL" - }, - "monq": { - "uri": "mongodb://localhost/test_monq" - }, - "default": { - "api": { - "version" : "v1" - }, - "lde": { - "url": "http://ldedev.c3sl.ufpr.br/#" - }, - "simcaq": { - "url": "http://simcaqdev.c3sl.ufpr.br/#" - } - }, - "email": { - "host": "SMTP.office365.com", - "port": 587, - "secureConnection": false, - "auth": { - "user": "dadoseducacionais@ufpr.br", - "pass": "COLOCAR_A_SENHA_AQUI" - }, - "tls": { - "ciphers": "SSLv3" - }, - "from": "\"Laboratório de Dados Educacionais\" <dadoseducacionais@ufpr.br>" - }, - "security": { - "tokenLife": 3600 - } - }, - "production": - { - "port": 3000, - "ip": "127.0.0.1", - "debug" : false, - "monetdb": { - "host": "simcaqdb3.c3sl.ufpr.br", - "port": 50000, - "dbname": "simcaq", - "user": "monetdb", - "password":"monetdb", - "nrConnections": "4" - }, - "cdn" : { - "url": "http://simcaqdb3.c3sl.ufpr.br:7000", - "download": "https://simcaq.c3sl.ufpr.br/download/" - }, - "mongodb" : { - "uri": "mongodb://localhost/users", - "secret": "SimCAQC3SL" - }, - "monq": { - "uri": "mongodb://localhost/monq" - }, - "default": { - "api": { - "version" : "v1" - }, - "lde": { - "url": "http://lde.c3sl.ufpr.br/#" - }, - "simcaq": { - "url": "http://simcaq.c3sl.ufpr.br/#" - } - }, - "email": { - "host": "SMTP.office365.com", - "port": 587, - "secureConnection": false, - "auth": { - "user": "dadoseducacionais@ufpr.br", - "pass": "COLOCAR_A_SENHA_AQUI" - }, - "tls": { - "ciphers": "SSLv3" - }, - "from": "\"Laboratório de Dados Educacionais\" <dadoseducacionais@ufpr.br>" - }, - "security": { - "tokenLife": 3600 - } - } -} diff --git a/gulpfile.babel.js b/gulpfile.babel.js index 32500420095cccb6a792b14ebe739bbfa16d4abc..c661d5af261b6a5a8baf5232592d01ef7cb48b28 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -1,7 +1,5 @@ require('babel-core/register'); -const fs = require('fs'); - const gulp = require('gulp'); const babel = require('gulp-babel'); diff --git a/package.json b/package.json index 7dfdb851bb284b14fde47cfb150526dd37da0626..ee49663181dfbe88f1567fc0f31877f519e1b57e 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "babel-core": "^6.26.3", "babel-preset-es2015": "^6.24.1", "babel-register": "^6.26.0", + "bcrypt": "^5.1.0", "bcrypt-nodejs": "0.0.3", "body-parser": "^1.18.3", "chai": "^3.5.0", @@ -51,6 +52,7 @@ "mocha": "^3.5.3", "monetdb-pool": "0.0.8", "mongoose": "^4.13.17", + "multer": "^1.4.5-lts.1", "natives": "^1.1.6", "nconf": "^0.8.5", "node-uuid": "^1.4.8", @@ -60,7 +62,10 @@ "passport": "^0.3.2", "passport-http-bearer": "^1.0.1", "passport-oauth2-client-password": "^0.1.2", + "pg": "^8.10.0", "request": "^2.88.0", + "sequelize": "^6.31.0", + "sequelize-cli": "^6.6.0", "sqlstring": "^2.3.1", "squel": "^5.12.2", "winston": "^2.4.4" diff --git a/script_req.sh b/script_req.sh new file mode 100755 index 0000000000000000000000000000000000000000..125204b86fb256e0608e25f161dccddb4cbc1ddc --- /dev/null +++ b/script_req.sh @@ -0,0 +1,10 @@ +curl -X 'POST' \ + 'http://10.254.221.20:3000/api/v1//auth/token' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "email": "eduardomsouza@ufpr.br", + "password": "teste123", + "client_secret": "LDE", + "grant_type": "password" +}' \ No newline at end of file diff --git a/src/libs/api_mongo.txt b/src/libs/api_mongo.txt new file mode 100644 index 0000000000000000000000000000000000000000..58f659659e0ed9d275a7375126a840823d782e20 --- /dev/null +++ b/src/libs/api_mongo.txt @@ -0,0 +1,6 @@ +*downloads.js +*resetToken.js (V) +*pqr.js +*simulation.js +*user.js (V) +*verifyToken.js (V) diff --git a/src/libs/app.js b/src/libs/app.js index b8b953c1ca4b23d2cc743611d6570b1d500de1e1..bab5e52d57d27260c16c60719855c60f4be71255 100644 --- a/src/libs/app.js +++ b/src/libs/app.js @@ -14,14 +14,11 @@ const config = require(`${libs}/config`); const app = express(); -const api = require('./routes/api'); +const api_v1 = require('./routes_v1/api'); +const api_v2 = require('./routes_v2/api'); const passport = require('passport'); -const mongoose = require(`${libs}/db/mongoose`); - -const db = mongoose(); - require(`${libs}/middlewares/passport`); app.use(bodyParser.json({limit: '50mb'})); @@ -65,7 +62,10 @@ app.use((req, res, next) => { next(); }); // Mounts all API routes under /api/v1 -app.use('/api/v1', api); +app.use('/api/v1', api_v1); + +// Mounts all API routes under /api/v2 +app.use('/api/v2', api_v2); // Catch 404 and forward to error handler app.use((req, res, next) => { diff --git a/src/libs/convert/admDependencyPub.js b/src/libs/convert/admDependencyPub.js new file mode 100644 index 0000000000000000000000000000000000000000..0522b2373916c27d0aa8531435d24d9c901cd96b --- /dev/null +++ b/src/libs/convert/admDependencyPub.js @@ -0,0 +1,32 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +module.exports = function admDependencyPub(id) { + switch (id) { + case 1: + return 'Rede pública'; + case 2: + return 'Rede estadual'; + case 3: + return 'Rede municipal'; + default: + return 'Não classificada'; + } +}; diff --git a/src/libs/convert/level.js b/src/libs/convert/level.js new file mode 100644 index 0000000000000000000000000000000000000000..e52a331bd7cf9ebd936ded24e2f48fa0c7099388 --- /dev/null +++ b/src/libs/convert/level.js @@ -0,0 +1,32 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +module.exports = function level(id) { + switch(id) { + case 1: + return 'Brasil'; + case 2: + return 'Estadual'; + case 3: + return 'Municipal'; + default: + return 'Não especificado'; + } +} \ No newline at end of file diff --git a/src/libs/convert/scholarDependency.js b/src/libs/convert/scholarDependency.js new file mode 100644 index 0000000000000000000000000000000000000000..25684b9b1981f20e655289e61f67f772767bb694 --- /dev/null +++ b/src/libs/convert/scholarDependency.js @@ -0,0 +1,76 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +module.exports = function scholarDependency(id) { + switch (id) { + case 1: + return "Biblioteca"; + case 2: + return "Sala de leitura"; + case 3: + return "Laboratório de informática"; + case 4: + return "Laboratório de ciências"; + case 5: + return "Parque infantil"; + case 6: + return "Quadra poliesportiva"; + case 7: + return "Quadras a serem cobertas"; + case 8: + return "Pátio"; + case 9: + return "Pátios a serem cobertos"; + case 10: + return "Sala de direção"; + case 11: + return "Secretaria"; + case 12: + return "Sala de professores"; + case 13: + return "Cozinha"; + case 14: + return "Despensa"; + case 15: + return "Almoxarifado"; + case 16: + return "Internet"; + case 17: + return "Internet banda larga"; + case 18: + return "Banheiro dentro do prédio"; + case 19: + return "Banheiro adequado para educação infantil dentro do prédio"; + case 20: + return "Fornecimento de energia"; + case 21: + return "Abastecimento de água"; + case 22: + return "Água filtrada"; + case 23: + return "Coleta de esgoto"; + case 24: + return "Dependências adaptadas para pessoas com deficiências"; + case 25: + return "Banheiros adaptados para pessoas com deficiências"; + default: + return "Dependência escolar desconhecida"; + } +} \ No newline at end of file diff --git a/src/libs/convert/shift.js b/src/libs/convert/shift.js new file mode 100644 index 0000000000000000000000000000000000000000..effe0a5230e1b0517c7f6eefae29bf3bf887ac55 --- /dev/null +++ b/src/libs/convert/shift.js @@ -0,0 +1,30 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +module.exports = function shift(id) { + switch(id) { + case 1: + return 'Parcial'; + case 2: + return 'Integral'; + default: + return 'Não especificado'; + } +} \ No newline at end of file diff --git a/src/libs/convert/supplyDimension.js b/src/libs/convert/supplyDimension.js new file mode 100644 index 0000000000000000000000000000000000000000..40f5ca9ace759598ad128fbfd74fd509ad4150d5 --- /dev/null +++ b/src/libs/convert/supplyDimension.js @@ -0,0 +1,36 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +module.exports = function supplyDimension(id) { + switch(id) { + case 1: + return 'Número de matrículas'; + case 2: + return 'Número de turmas'; + case 3: + return 'Número de salas'; + case 4: + return 'Número de professores'; + case 5: + return 'Número de funcionários'; + default: + return 'Não especificado'; + } +} \ No newline at end of file diff --git a/src/libs/convert/type.js b/src/libs/convert/type.js new file mode 100644 index 0000000000000000000000000000000000000000..6ffaf010c52ccdfda27e3ab5a1b51e953cc0930c --- /dev/null +++ b/src/libs/convert/type.js @@ -0,0 +1,30 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +module.exports = function type(id) { + switch(id) { + case 1: + return 'Plano'; + case 2: + return 'Rede'; + default: + return 'Não especificado'; + } +} \ No newline at end of file diff --git a/src/libs/db/mongoose.js b/src/libs/db/mongoose.js deleted file mode 100644 index f9d2ed8ef59767e262f77fa21e2a93d444139145..0000000000000000000000000000000000000000 --- a/src/libs/db/mongoose.js +++ /dev/null @@ -1,21 +0,0 @@ -const libs = `${process.cwd()}/libs`; - -const config = require(`${libs}/config`); - -const log = require(`${libs}/log`)(module); - -const mongoose = require('mongoose'); - -mongoose.Promise = global.Promise; - -module.exports = () => { - // Get mongodb URI (ip and port) in config file - const mongoUri = process.env.MONGO_URI || config.mongodb.uri; - log.info(`Connecting to MongoDB on URI ${mongoUri}`); - // Connection singleton - const db = mongoose.connect(mongoUri); - - mongoose.connection.once('open', () => { log.info("MongoDB connected"); }); - - return db; -}; diff --git a/src/libs/db/postgres.js b/src/libs/db/postgres.js new file mode 100644 index 0000000000000000000000000000000000000000..c60d28c6932491dbee5ba88a5f86412d707cda23 --- /dev/null +++ b/src/libs/db/postgres.js @@ -0,0 +1,8 @@ +const Sequelize = require('sequelize'); + +// if you are using postgres, your DB URL will look like this +const DATABASE_URL = 'postgres://postgres:postgres@localhost:5432/postgres' + +const db = new Sequelize(DATABASE_URL) + +module.exports = db \ No newline at end of file diff --git a/src/libs/middlewares/authorize.js b/src/libs/middlewares/authorize.js new file mode 100644 index 0000000000000000000000000000000000000000..592c193bedc33e136d23f95019cc0c0515ca7455 --- /dev/null +++ b/src/libs/middlewares/authorize.js @@ -0,0 +1,39 @@ +const express = require('express'); + +const pubApp = express(); + +const libs = `${process.cwd()}/libs`; + +const PermissionRole = require(`${libs}/models/permissionRole`) + +const mapPermission = { + 'criar publicacao': '1', + 'editar publicacao': '2', + 'apagar publicacao': '3', + 'criar atividade': '4', + 'editar atividade': '5', + 'apagar atividade': '6', +} + +function authorized(permission) { + return async function (req, res, next) { + const permission_id = mapPermission[permission] + const userRole = req.user.role_id; // Assuming user role is stored in req.user.role + const hasPermission = await PermissionRole.findOne({where:{role_id:userRole, permission_id: permission_id}}).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }); + if (hasPermission) { + // User has permission, proceed to next middleware or route handler + next(); + } else { + // User does not have permission, return unauthorized response + res.status(403).json({ message: 'Unauthorized' }); + } + }; +} + +module.exports = authorized + diff --git a/src/libs/middlewares/downloadDatabase.js b/src/libs/middlewares/downloadDatabase.js index c4672ff0bf5d925d7d8d0466a260d3025fbc4e09..6f2dec6fb0271e43dce8580794b8c766c3ba9c9c 100644 --- a/src/libs/middlewares/downloadDatabase.js +++ b/src/libs/middlewares/downloadDatabase.js @@ -10,11 +10,11 @@ const config = require(`${libs}/config`); const Download = require(`${libs}/models/download`); -module.exports = function download(table, mappingTable) { +module.exports = function download(table, mapping_table) { return (req, res, next) => { // First, query the mapping - execute(`SELECT target_name, name FROM ${mappingTable}`, undefined, (err, result) => { - if(err) { + execute(`SELECT target_name, name FROM ${mapping_table}`, undefined, (err, result) => { + if (err) { log.error(err.stack); next(new Error('Request could not be satisfied due to a database error.')); } else { @@ -23,7 +23,7 @@ module.exports = function download(table, mappingTable) { result.forEach((field) => { req.sql.field(`CASE ${table}.${field.name} WHEN true THEN 1 WHEN false THEN 0 ELSE ${table}.${field.name} END AS ${field.target_name}`); // req.sql.field(table + '.' + field.name, field.target_name); - if(header === '') header += field.target_name; + if (header === '') header += field.target_name; else header = header + ';' + field.target_name; }); @@ -36,53 +36,51 @@ module.exports = function download(table, mappingTable) { header }; - request.post(config.cdn.url + '/api/v1/file', {form}, (err, response, body) => { - if(err) { + request.post(config.cdn.url + '/api/v1/file', { form }, async (err, response, body) => { + if (err) { log.error(err); - return res.json({error: err}); + return res.json({ error: err }); } - Download.findOne({query: req.sql.toString()}, (err, download) => { - if(download) { - download.updatedAt = Date.now(); - if(download.userId != req.user._id) { - let dl = new Download({ - userId: req.user._id, - table, - name: req.query.name, - mappingTable, - query: req.sql.toString(), - status: 'Enviando', - expired: false - }); - console.log(dl); - dl.save((err) => { - if(err) log.error(err); - }); - } - } else { - download = new Download({ - userId: req.user._id, + let download = await Download.findOne({ where: { query: req.sql.toString() } }).catch(function (err) { + if (err) { + log.error(err); + } + }) + if (download) { + download.updated_at = new Date(); + if (download.user_id != req.user.id) { + let dl = await Download.create({ + user_id: req.user.id, table, name: req.query.name, - mappingTable, - query: req.sql.toString(), + mapping_table, query: req.sql.toString(), status: 'Enviando', expired: false }); - console.log(download); + console.log(dl); + dl.save().catch(function (err) { + if (err) log.error(err); + }); } - - download.save((err) => { - if(err) { - log.error(err); - } - res.json({msg: 'Wait for download email', waitForIt: true}); + } else { + download = await Download.create({ + user_id: req.user.id, + table, + name: req.query.name, + mapping_table, + query: req.sql.toString(), + status: 'Enviando', + expired: false }); - }); + console.log(download); + } + + await download.save() + res.json({ msg: 'Wait for download email', waitForIt: true }); }); - } + }; }); } -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/libs/middlewares/email.js b/src/libs/middlewares/email.js index 4d1d51711566a586fc5d29c0bf8ba7953f7da0f1..679b06414717367fec4666c060cab9032c6f41eb 100644 --- a/src/libs/middlewares/email.js +++ b/src/libs/middlewares/email.js @@ -32,8 +32,10 @@ module.exports = function send(options, cb) { let opt = Object.assign({}, mailOptions, options); transporter.sendMail(opt, (err, info) => { if(err) { + console.log("Erro email"); return cb(err); } + console.log("OK email"); cb(null, info); }); }; diff --git a/src/libs/middlewares/id2str.js b/src/libs/middlewares/id2str.js index bd5c83c0d108d55d8e91b154f499f17b6221bfab..cb549d3d57326365f2289d6f7786123941cf2a87 100644 --- a/src/libs/middlewares/id2str.js +++ b/src/libs/middlewares/id2str.js @@ -95,6 +95,12 @@ const enrollmentSituation = require(`${libs}/convert/enrollmentSituation`); const diffLocation = require(`${libs}/convert/diffLocation`); const peePorCategoria = require(`${libs}/convert/peePorCategoria`); const pee = require(`${libs}/convert/booleanVariable`); +const shift = require(`${libs}/convert/shift`); +const admDependencyPub = require(`${libs}/convert/admDependencyPub`); +const supplyDimension = require(`${libs}/convert/supplyDimension`); +const type = require(`${libs}/convert/type`); +const level = require(`${libs}/convert/level`); +const scholarDependency = require(`${libs}/convert/scholarDependency`); const ids = { gender_id: gender, @@ -106,6 +112,7 @@ const ids = { education_level_short_id: educationLevelShort, adm_dependency_id: admDependency, adm_dependency_detailed_id: admDependencyPriv, + adm_dependency_public_id: admDependencyPub, location_id: location, rural_location_id: ruralLocation, location_detailed_id: ruralLocation, @@ -181,7 +188,12 @@ const ids = { enrollment_situation: enrollmentSituation, diff_location_id: diffLocation, pee_por_categoria: peePorCategoria, - pee_id: pee + pee_id: pee, + shift_id: shift, + supply_dimension_id: supplyDimension, + type_id: type, + level_id: level, + scholar_dependency_id: scholarDependency }; function transform(removeId=false) { @@ -295,5 +307,7 @@ module.exports = { enrollmentSituation, diffLocation, peePorCategoria, - pee + pee, + shift, + admDependencyPub }; diff --git a/src/libs/middlewares/multer.config.js b/src/libs/middlewares/multer.config.js new file mode 100644 index 0000000000000000000000000000000000000000..d4c7263fcb7c80451d81242186ce3c881a458b69 --- /dev/null +++ b/src/libs/middlewares/multer.config.js @@ -0,0 +1,6 @@ +const multer = require('multer'); + +var storage = multer.memoryStorage() +var upload = multer({storage: storage}); + +module.exports = upload; diff --git a/src/libs/middlewares/oauth2.js b/src/libs/middlewares/oauth2.js index cc9a45ede4a3158bc055166202c6d20fb84a6dff..bb3fe88d0dd65361d08f4b300a68bfd480050a9d 100644 --- a/src/libs/middlewares/oauth2.js +++ b/src/libs/middlewares/oauth2.js @@ -7,11 +7,15 @@ const libs = `${process.cwd()}/libs`; const config = require(`${libs}/config`); const log = require(`${libs}/log`)(module); -const db = require(`${libs}/db/mongoose`); const User = require(`${libs}/models/user`); const AccessToken = require(`${libs}/models/accessToken`); const RefreshToken = require(`${libs}/models/refreshToken`); +const origin_to_secret = { + 'SimCAQ': 'FcmZp9bZpk8yxSJA', + 'LDE': 'LDE' +}; + // create OAuth 2.0 server let aserver = oauth2orize.createServer() @@ -23,86 +27,74 @@ let errFn = (cb, err) => { } // Destroys any old tokens and generates a new access and refresh token -let generateTokens = (data, done) => { +let generateTokens = (userId, clientId,userRole, done) => { // curries in `done` callback so we don't need to pass it - let errorHandler = errFn.bind(undefined, done); - let refreshToken; let refreshTokenValue; - let token; let tokenValue; + let admin = false; - RefreshToken.remove(data, errorHandler); - AccessToken.remove(data, errorHandler); + RefreshToken.destroy({where:{"user_id": userId, "client_id": clientId}}); + AccessToken.destroy({where:{"user_id": userId, "client_id": clientId}}); tokenValue = crypto.randomBytes(32).toString('hex'); refreshTokenValue = crypto.randomBytes(32).toString('hex'); - data.token = tokenValue; - token = new AccessToken(data); - - data.token = refreshTokenValue; - refreshToken = new RefreshToken(data); + AccessToken.create({ + user_id:userId, + client_id:clientId, + token:tokenValue + }) - refreshToken.save(errorHandler); + let refreshed_token = refreshTokenValue; - token.save((err) => { - if (err) { - log.error(err); - return done(err); - } - done(null, tokenValue, refreshTokenValue, { - 'expires_in': config.security.tokenLife - }); + RefreshToken.create({ + user_id:userId, + client_id:clientId, + token:refreshed_token }) -}; + if(userRole == 1){ + admin = true; + } + done(null, tokenValue, refreshTokenValue, {'admin': admin},{ + 'expires_in': config.security.tokenLife + }); -// Exchange username & password for access token. -aserver.exchange(oauth2orize.exchange.password((client, username, password, scope, done) => { - User.findOne({ email: username }, (err, user) => { - if (err) { - return done(err); - } +}; - if (!user || !user.checkPassword(password)) { - return done(null, false); - } - var model = { - userId: user._id, - clientId: client._id - }; - log.info(`Gerando token para usuário ${user.name}`); - generateTokens(model, done); - }) +// Exchange username & password for access token. +aserver.exchange(oauth2orize.exchange.password(function(client, username, password, scope, done) { + User.findOne({ + where: {email:username} + }).then(function(user) { + if(user == null|| !user.checkPassword(user, password)){ + return done(null, false); + } + + if(origin_to_secret[user.dataValues.origin] != client.client_secret){ + console.log(origin_to_secret[user.dataValues.origin]); + console.log("Erro de client_secret"); + //return done(null, false); + } + log.info(`Gerando token para usuário ${user.name}`); + generateTokens(user.dataValues.id, client.id, user.dataValues.role_id, done); + }).catch(function(error) { + return done(error); + }); + })); -})); // Exchange refreshToken for access token. aserver.exchange(oauth2orize.exchange.refreshToken((client, refreshToken, scope, done) =>{ - RefreshToken.findOne({ token: refreshToken, clientId: client._id }, (err, token) => { - if (err) { - return done(err); - } - + RefreshToken.findOne({where: {token: refreshToken, client_id: client.id }}).then(function(token){ if (!token) { return done(null, false); } - - User.findById(token.userId, (err, user) => { - if (err) { - log.error(err); - return done(err); - } + User.findByPk(token.user_id).then(function(user){ if (!user) { return done(null, false); } - - var model = { - userId: user._id, - clientId: client._id - }; - - generateTokens(model, done); + generateTokens(user.id, client.id, done); }) }) })) @@ -114,6 +106,12 @@ aserver.exchange(oauth2orize.exchange.refreshToken((client, refreshToken, scope, // exchange middleware will be invoked to handle the request. Clients must // authenticate when making requests to this endpoint. + +// ,function(err, user) { +// if (err) { console.log("Erro de autenticação"); } +// if (!user) { console.log("Erro de usuario ausente");} +// } + exports.token = [ passport.authenticate(['oauth2-client-password'], { session: false }), aserver.token(), diff --git a/src/libs/middlewares/passport.js b/src/libs/middlewares/passport.js index ab895a9604072e3b77a6384ac0c0f9066dcf6753..7e8d5120f6ea9d258e98f76621d252218c84a3c7 100644 --- a/src/libs/middlewares/passport.js +++ b/src/libs/middlewares/passport.js @@ -8,60 +8,51 @@ const config = require(`${libs}/config`); const User = require(`${libs}/models/user`); const Client = require(`${libs}/models/client`); const AccessToken = require(`${libs}/models/accessToken`); -const RefreshToken = require(`${libs}/models/refreshToken`); -const email = require(`${libs}/middlewares/email`); -passport.use(new ClientPasswordStrategy( (clientId, clientSecret, done) => { - Client.findOne({ _id: clientId }, (err, client) => { - if (err) { - return done(err); - } +passport.use(new ClientPasswordStrategy( + function (client_id, client_secret, done) { + Client.findOne({ + where: { id: client_id } + }).then(function (client) { if (!client) { + console.log("Erro de cliente"); return done(null, false); } - - if (client.clientSecret !== clientSecret) { + if (client.client_secret !== client_secret) { + console.log("Erro de Chave Secreta"); return done(null, false); } - return done(null, client); - }) + }).catch(function (error) { + return done(error); + }); } )); -passport.use(new BearerStrategy( (accessToken, done) => { - AccessToken.findOne({ token: accessToken }, (err, token) => { - if (err) { - return done(err); - } - - if (!token) { - return done(null, false); - } - - if( Math.round((Date.now()-token.created)/1000) > config.security.tokenLife) { - AccessToken.remove({ token: accessToken }, (err) => { - if (err) { - return done(err); - } - }); +passport.use(new BearerStrategy(async (accessToken, done) => { + const token = await AccessToken.findOne({ where: { token: accessToken } }) + if (!token) { + console.log("ERRO Token"); + return done(null, false); + } - return done(null, false, { msg: 'Token expired' }); + if (Math.round((Date.now() - token.created) / 1000) > config.security.tokenLife) { + AccessToken.destroy({where:{ token: accessToken} }).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); } + }); - User.findById(token.userId, function(err, usuario) { - if (err) { - return done(err); - } - - if (!usuario) { - return done(null, false, { msg: 'Unknown user' }); - } - - var info = { scope: '*' }; - done(null, usuario, info); - }) - }) + return done(null, false, { msg: 'Token expired' }); } -)); + User.findByPk(token.user_id).then(function (usuario) { + if (!usuario) { + console.log("ERRO NAO USUARIO"); + return done(null, false, { msg: 'Unknown user' }); + } + var info = { scope: '*' }; + done(null, usuario, info); + }) +})); diff --git a/src/libs/middlewares/query.js b/src/libs/middlewares/query.js index b724d93dd8e36709033eb171cceaafe9b6ff7659..3b734957fe255458687f0cffaf25cd94c1af3997 100644 --- a/src/libs/middlewares/query.js +++ b/src/libs/middlewares/query.js @@ -10,6 +10,8 @@ function query(req, res, next) { execute(sql.text, sql.values, (err, result) => { if(err) { log.error(err.stack); + console.log(sql.text); + console.log(sql.values); next(new Error('Request could not be satisfied due to a database error.')); } else { req.result = result; diff --git a/src/libs/middlewares/reqBody.js b/src/libs/middlewares/reqBody.js new file mode 100644 index 0000000000000000000000000000000000000000..9df7ebcaeb827836d5a93dbc85f28e0ba33b702d --- /dev/null +++ b/src/libs/middlewares/reqBody.js @@ -0,0 +1,59 @@ +class ReqBody { + constructor() { + + } + + add_metrics(req, column, metricsArray) { + for (let i in metricsArray) { + switch(metricsArray[i]["function"]) { + case "max": + req.sql.field("max(" + column + ")", metricsArray[i]["return_name"]); + req.hasMetrics = true; + break; + case "min": + req.sql.field("min(" + column + ")", metricsArray[i]["return_name"]); + req.hasMetrics = true; + break; + case "count": + req.sql.field("count(" + column + ")", metricsArray[i]["return_name"]); + req.hasMetrics = true; + break; + case "sum": + req.sql.field("sum(" + column + ")", metricsArray[i]["return_name"]); + req.hasMetrics = true; + break; + default: + break; + } + } + } + + parse() { + return(req, res, next) => { + // Gets body of the HTTP requisition + let body = req.body; + + // Chooses operation based on the mode field of the body + switch(body["mode"]) { + case "add_metrics": + // adds flag to check whether it runs the default query or not + req.hasMetrics = false; + // Gets all column names + let columns = Object.keys(body["add_metrics"]); + // Calls function to add metrics that were specified to req.sql + for (let i in columns) { + this.add_metrics(req, columns[i], body["add_metrics"][columns[i]]); + } + + break; + + default: + break; + } + + next(); + } + } +} + +module.exports = ReqBody; \ No newline at end of file diff --git a/src/libs/models/accessToken.js b/src/libs/models/accessToken.js index daab5898a66b952f72359d9685e951b1acf980b7..54e4a4ba8e3b375e2bd0a4b73414e4d59096974d 100644 --- a/src/libs/models/accessToken.js +++ b/src/libs/models/accessToken.js @@ -1,29 +1,32 @@ -const mongoose = require('mongoose'); -const Schema = mongoose.Schema; +const Sequelize = require("sequelize"); +const db = require('../db/postgres.js') const libs = `${process.cwd()}/libs`; const User = require(`${libs}/models/user`); const Client = require(`${libs}/models/client`); -let AccessToken = new Schema({ - userId: { - type: Schema.Types.ObjectId, - required: true, - ref: 'User' +var AccessToken = db.define("AccessToken",{ + user_id: { + type: Sequelize.STRING, + allowNull: false }, - clientId: { - type: Schema.Types.ObjectId, - required: true, - ref: 'Client' + client_id:{ + type: Sequelize.STRING, + allowNull: false }, - token: { - type: String, + token:{ + type: Sequelize.STRING, + allowNull: false, unique: true, - required: true + primaryKey: true }, - createdAt: { - type: Date, - default: Date.now - } -}); + created_at:{ + type: Sequelize.DATE, + defaultValue: Date.now + }}, + {timestamps: false} +); -module.exports = mongoose.model('AccessToken', AccessToken); +AccessToken.hasOne(User, { foreignKey: 'id' }); +AccessToken.hasOne(Client, { foreignKey: 'id' }); + +module.exports = AccessToken; diff --git a/src/libs/models/activity.js b/src/libs/models/activity.js new file mode 100644 index 0000000000000000000000000000000000000000..92fc6f087fba744219badcd69ad7785b2d4b3b61 --- /dev/null +++ b/src/libs/models/activity.js @@ -0,0 +1,80 @@ +const Sequelize = require("sequelize"); +const db = require('../db/postgres.js'); +const libs = `${process.cwd()}/libs`; + +var Activity = db.define("Activity",{ + id:{ + type: Sequelize.STRING, + allowNull:false, + unique: true, + primaryKey: true + }, + type:{ + type: Sequelize.STRING, + allowNull:false + }, + title:{ + type: Sequelize.STRING, + allowNull:false, + }, + subtitle:{ + type: Sequelize.STRING + }, + date:{ + type: Sequelize.STRING, + allowNull:false + }, + authors:{ + type: Sequelize.STRING, + }, + text:{ + type: Sequelize.STRING, + allowNull: false + }, + name_headline:{ + type: Sequelize.STRING, + allowNull:false + }, + resume_headline:{ + type:Sequelize.STRING, + allowNull:false + }, + date_headline:{ + type: Sequelize.STRING, + allowNull:false + }, + local_headline:{ + type:Sequelize.STRING, + allowNull:false + }, + additional_headline:{ + type:Sequelize.STRING + }, + is_draft:{ + type:Sequelize.BOOLEAN, + allowNull:false, + defaultValue: true + }, + is_headline:{ + type:Sequelize.BOOLEAN, + allowNull: false, + defaultValue: false + } + +}, +{timestamps: false}); + +Activity.generateObjectId = function(){ + var timestamp = (new Date().getTime() / 1000 | 0).toString(16); + return timestamp + 'xxxxxxxxxxxxxxxx'.replace(/[x]/g, function() { + return (Math.random() * 16 | 0).toString(16); + }).toLowerCase(); +} + +const setObjectId = act => { + act.id = Activity.generateObjectId() +}; + +Activity.beforeCreate(setObjectId); + +module.exports = Activity; \ No newline at end of file diff --git a/src/libs/models/client.js b/src/libs/models/client.js index 8ac80d8d158705f63efbbecc72de37d1fef6a3ac..b4eabcbca46ed440b8655cc77b6b5b147e35c54c 100644 --- a/src/libs/models/client.js +++ b/src/libs/models/client.js @@ -1,17 +1,24 @@ -const mongoose = require('mongoose'); -const Schema = mongoose.Schema; +const Sequelize = require("sequelize"); +const db = require('../db/postgres.js'); -let Client = new Schema({ - name: { - type: String, +var Client = db.define("client",{ + id:{ + type: Sequelize.STRING, + allowNull:false, unique: true, - required: true + primaryKey: true }, - clientSecret: { - type: String, - required: true, + name:{ + type: Sequelize.STRING, + allowNull:false, unique: true - } -}); + }, + client_secret:{ + type: Sequelize.STRING, + allowNull:false, + unique:true + }, +}, +{timestamps: false}); -module.exports = mongoose.model('Client', Client); +module.exports = Client; \ No newline at end of file diff --git a/src/libs/models/download.js b/src/libs/models/download.js index 989896d9a2b6547c11c9b1bc71019db3bb7617a5..3d59249aad2592bf6ae5f7bcc668bdd71d0de1f6 100644 --- a/src/libs/models/download.js +++ b/src/libs/models/download.js @@ -1,53 +1,60 @@ -const mongoose = require('mongoose'); -const Schema = mongoose.Schema; +const Sequelize = require("sequelize"); +const crypto = require('crypto'); +const db = require('../db/postgres.js'); const libs = `${process.cwd()}/libs`; -const log = require(`${libs}/log`)(module); const User = require(`${libs}/models/user`); -let Download = new Schema({ - userId: { - type: Schema.Types.ObjectId, - required: true, - ref: 'User' - }, - table: { - type: String, - required: true - }, - name: { - type: String, - required: true - }, - mappingTable: { - type: String, - required: true +var Download = db.define("Download",{ + id:{ + type: Sequelize.INTEGER, + allowNull: false, + autoIncrement: true, + unique: true, + primaryKey: true + }, + user_id: { + type: Sequelize.STRING, + allowNull: false + }, + table:{ + type: Sequelize.STRING, + allowNull: false, + }, + name:{ + type: Sequelize.STRING, + allowNull: false, + }, + mapping_table:{ + type: Sequelize.STRING, + allowNull:false }, query: { - type: String, - required: true + type: Sequelize.STRING, + allowNull:false }, - createdAt: { - type: Date, - required: true, - default: Date.now - }, - updatedAt: { - type: Date, - required: true, - default: Date.now + created_at:{ + type: Sequelize.DATE, + defaultValue: Date.now + }, + updated_at: { + type: Sequelize.DATE, + defaultValue: Date.now }, status: { - type: String + type: Sequelize.STRING }, size: { - type: Number + type: Sequelize.NUMBER }, expired: { - type: Boolean + type: Sequelize.BOOLEAN }, link: { - type: String - } -}); + type: Sequelize.STRING, + }}, + {timestamps: false} +); + +Download.hasOne(User,{ foreignKey: 'id' }); -module.exports = mongoose.model('Download', Download); +module.exports = Download diff --git a/src/libs/models/file.js b/src/libs/models/file.js new file mode 100644 index 0000000000000000000000000000000000000000..aa6ba077e60ae1b400e401d470f46aa7f2bc53e3 --- /dev/null +++ b/src/libs/models/file.js @@ -0,0 +1,39 @@ + +const Sequelize = require("sequelize"); +const db = require('../db/postgres.js'); +const libs = `${process.cwd()}/libs`; + +var File = db.define("File",{ + id: { + type: Sequelize.STRING, + allowNull:false, + unique: true, + primaryKey: true + }, + type:{ + type: Sequelize.STRING + }, + name: { + type: Sequelize.STRING + }, + data: { + type: Sequelize.BLOB('long') + } +}, +{timestamps: false}); + +File.generateObjectId = function(){ + var timestamp = (new Date().getTime() / 1000 | 0).toString(16); + return timestamp + 'xxxxxxxxxxxxxxxx'.replace(/[x]/g, function() { + return (Math.random() * 16 | 0).toString(16); + }).toLowerCase(); +} + +const setObjectId = file => { + file.id = File.generateObjectId() +}; + +File.beforeCreate(setObjectId); + +module.exports=File; + diff --git a/src/libs/models/permission.js b/src/libs/models/permission.js new file mode 100644 index 0000000000000000000000000000000000000000..ba35c4ce57dcb2f4655cb038d76814f4d54933f8 --- /dev/null +++ b/src/libs/models/permission.js @@ -0,0 +1,39 @@ +const Sequelize = require("sequelize"); +const db = require('../db/postgres.js'); +const libs = `${process.cwd()}/libs`; +const Role = require(`${libs}/models/role`); + +var Permission = db.define("PermissionRole",{ + id:{ + type: Sequelize.STRING, + allowNull:false, + unique: true, + primaryKey: true + }, + permission_name:{ + type: Sequelize.STRING, + allowNull:false, + }, + permission_description:{ + type: Sequelize.STRING, + allowNull:false + } +}, +{timestamps: false}); + +Permission.generateObjectId = function(){ + var timestamp = (new Date().getTime() / 1000 | 0).toString(16); + return timestamp + 'xxxxxxxxxxxxxxxx'.replace(/[x]/g, function() { + return (Math.random() * 16 | 0).toString(16); + }).toLowerCase(); +} + +const setObjectId = permission => { + permission.id = Permission.generateObjectId() +}; + +Permission.beforeCreate(setObjectId); + + +module.exports = Permission; + diff --git a/src/libs/models/permissionRole.js b/src/libs/models/permissionRole.js new file mode 100644 index 0000000000000000000000000000000000000000..e415acc697f2db9af4be231efdb8e855cbd9ec53 --- /dev/null +++ b/src/libs/models/permissionRole.js @@ -0,0 +1,29 @@ +const Sequelize = require("sequelize"); +const db = require('../db/postgres.js'); +const libs = `${process.cwd()}/libs`; +const Role = require(`${libs}/models/role`); +const Permission = require(`${libs}/models/permission`); + +var PermissionRole = db.define("PermissionRole",{ + id:{ + type: Sequelize.INTEGER, + allowNull:false, + unique: true, + primaryKey: true + }, + role_id:{ + type: Sequelize.INTEGER, + allowNull:false, + }, + permission_id:{ + type: Sequelize.INTEGER, + allowNull:false + } +}, +{timestamps: false}); + +PermissionRole.hasMany(Role, {foreignKey: 'id'}); +PermissionRole.hasMany(Permission, {foreignKey: 'id'}); + +module.exports = PermissionRole; + diff --git a/src/libs/models/pqr.js b/src/libs/models/pqr.js index f92703188323cef17807f70f1f2198b54a13aa1b..2a9fb9dd657d13494efd9d57fa3f1a0c59a3c59d 100644 --- a/src/libs/models/pqr.js +++ b/src/libs/models/pqr.js @@ -1,16 +1,19 @@ -const mongoose = require('mongoose') +const Sequelize = require("sequelize"); +const db = require('../db/postgres.js'); -const libs = `${process.cwd()}/libs`; -const log = require(`${libs}/log`)(module); -const User = require(`${libs}/models/user`); - -const Schema = mongoose.Schema; - -let PQRSchema = new Schema({ +var PQR = db.define("pqr",{ + id:{ + type: Sequelize.INTEGER, + allowNull: false, + unique: true, + primaryKey: true + }, content: { - type: String, - required: true, + type: Sequelize.STRING, + allowNull: false } -}); +}, +{timestamps: false}); + -module.exports = mongoose.model('PQR', PQRSchema); +module.exports = PQR; diff --git a/src/libs/models/publication.js b/src/libs/models/publication.js new file mode 100644 index 0000000000000000000000000000000000000000..bd537bc0825b44a0e79d384e5bf631537784ef69 --- /dev/null +++ b/src/libs/models/publication.js @@ -0,0 +1,83 @@ +const Sequelize = require("sequelize"); +const db = require('../db/postgres.js'); +const libs = `${process.cwd()}/libs`; + +var Publication = db.define("Publication",{ + id:{ + type: Sequelize.STRING, + allowNull:false, + unique: true, + primaryKey: true + }, + filter:{ + type: Sequelize.ENUM("Artigo", "Tese", "Dissertação", "Relatório", "Periódico"), + allowNull:false, + validate: { + notNull: { msg: "O campo categoria é obrigatória e aceita apenas os valores 'Artigo', 'Tese', 'Dissertação', 'Relatório', 'Periódico."}, + isIn:{ + args: [["Artigo", "Tese", "Dissertação", "Relatório", "Periódico"]], + msg: "O campo categoria é obrigatória e aceita apenas os valores 'Artigo', 'Tese', 'Dissertação', 'Relatório', 'Periódico'." + } + } + }, + title:{ + type: Sequelize.STRING, + allowNull:false, + }, + authors:{ + type: Sequelize.STRING, + allowNull:false + }, + organization:{ + type: Sequelize.STRING, + allowNull:false + }, + year:{ + type:Sequelize.STRING, + allowNull:false + }, + text:{ + type: Sequelize.ENUM("Baixar","Acessar"), + allowNull:false, + validate: { + notNull: { msg: "O campo origem é obrigatória e aceita apenas os valores 'Baixar', 'Acessar'."}, + isIn:{ + args: [["Baixar", "Acessar"]], + msg: "O campo origem é obrigatória e aceita apenas os valores 'Baixar', 'Acessar'."} + } + }, + link:{ + type: Sequelize.STRING + }, + upload:{ + type: Sequelize.STRING + }, + is_draft:{ + type:Sequelize.BOOLEAN, + allowNull:false, + defaultValue: true + }, + is_headline:{ + type:Sequelize.BOOLEAN, + allowNull: false, + defaultValue: false + } +},{timestamp:true, + createdAt: 'created_at', + updatedAt: 'updated_at'} +); + +Publication.generateObjectId = function(){ + var timestamp = (new Date().getTime() / 1000 | 0).toString(16); + return timestamp + 'xxxxxxxxxxxxxxxx'.replace(/[x]/g, function() { + return (Math.random() * 16 | 0).toString(16); + }).toLowerCase(); +} + +const setObjectId = pb => { + pb.id = Publication.generateObjectId() +}; + +Publication.beforeCreate(setObjectId); + +module.exports = Publication; \ No newline at end of file diff --git a/src/libs/models/refreshToken.js b/src/libs/models/refreshToken.js index c5f8fd63cdd30733bb60f341e6617420d945b037..aebdd9b2ec4d8e32acb6e8a03c1264b88305b9a7 100644 --- a/src/libs/models/refreshToken.js +++ b/src/libs/models/refreshToken.js @@ -1,30 +1,33 @@ -const mongoose = require('mongoose'); -const Schema = mongoose.Schema; +const Sequelize = require("sequelize"); const libs = `${process.cwd()}/libs`; +const db = require('../db/postgres.js'); const User = require(`${libs}/models/user`); const Client = require(`${libs}/models/client`); -let RefreshToken = new Schema({ - userId: { - type: Schema.Types.ObjectId, - required: true, - ref: 'User' +var RefreshToken = db.define("RefreshToken",{ + user_id: { + type: Sequelize.STRING, + allowNull: false }, - clientId: { - type: Schema.Types.ObjectId, - required: true, - ref: 'Client' + client_id:{ + type: Sequelize.STRING, + allowNull: false }, - token: { - type: String, + token:{ + type: Sequelize.STRING, + allowNull: false, unique: true, - required: true + primaryKey: true }, - createdAt: { - type: Date, - default: Date.now - } -}); + created_at:{ + type: Sequelize.DATE, + defaultValue: Date.now + }}, + {timestamps: false} +); -module.exports = mongoose.model('RefreshToken', RefreshToken); +RefreshToken.hasOne(User, { foreignKey: 'id' }); +RefreshToken.hasOne(Client, { foreignKey: 'id' }); + +module.exports = RefreshToken; diff --git a/src/libs/models/resetToken.js b/src/libs/models/resetToken.js index 322d528188a78525b4e003a65c6355fc0c2039c6..071cf8ce97191b2a0bfd5973808efad1c6a44508 100644 --- a/src/libs/models/resetToken.js +++ b/src/libs/models/resetToken.js @@ -1,46 +1,41 @@ -const mongoose = require('mongoose'); -const Schema = mongoose.Schema; +const Sequelize = require("sequelize"); const libs = `${process.cwd()}/libs`; -const log = require(`${libs}/log`)(module); +const db = require('../db/postgres.js'); const User = require(`${libs}/models/user`); const uuid = require('node-uuid'); -let ResetToken = new Schema({ - userId: { - type: Schema.Types.ObjectId, - required: true, - ref: 'User' +var ResetToken = db.define("ResetToken",{ + user_id: { + type: Sequelize.STRING, + allowNull: false }, - token: { - type: String, - required: true + token:{ + type: Sequelize.STRING, + allowNull: false, + unique: true, + primaryKey: true }, - reset: { - type: Boolean, - required: true, - default: false + reset:{ + type: Sequelize.BOOLEAN, + allowNull: false, + defaultValue: false }, - createdAt: { - type: Date, - required: true, - default: Date.now - } -}); + created_at:{ + type: Sequelize.DATE, + defaultValue: Date.now + }}, + {timestamps: false} +); -ResetToken.methods.createResetToken = function (done) { - let resetToken = this; - let token = uuid.v4(); - resetToken.set('token', token); - resetToken.reset = false; - resetToken.save(function(err) { - if (err) - return done(err); - return done(null, token); - }) -} -ResetToken.methods.hasExpired = function () { +ResetToken.prototype.hasExpired = function () { var now = new Date(); - return (now - this.createdAt) > 86400; //Expire if token is 1 day old + console.log(now); + console.log(this.created_at); + console.log(now - this.created_at); + return (now - this.created_at) > 86400; //Expire if token is 1 day old }; -module.exports = mongoose.model('ResetToken', ResetToken); +ResetToken.hasOne(User,{ foreignKey: 'id' }); + + +module.exports = ResetToken diff --git a/src/libs/models/role.js b/src/libs/models/role.js new file mode 100644 index 0000000000000000000000000000000000000000..d594b061a5dd082a26c2bf41f4d80e6b78214230 --- /dev/null +++ b/src/libs/models/role.js @@ -0,0 +1,23 @@ +const Sequelize = require("sequelize"); +const db = require('../db/postgres.js'); + +var Role = db.define("Role",{ + id:{ + type: Sequelize.INTEGER, + allowNull:false, + unique: true, + primaryKey: true + }, + role_name:{ + type: Sequelize.STRING, + allowNull:false, + }, + // token:{ + // type: Sequelize.STRING, + // allowNull:false, + // } +}, +{timestamps: false}); + +module.exports = Role; + diff --git a/src/libs/models/simulation.js b/src/libs/models/simulation.js index f1d3b0bd2448fe7640affd57e3d33d330ad7912c..21d2de89547e34a8118ab2579b410a44ff969d0e 100644 --- a/src/libs/models/simulation.js +++ b/src/libs/models/simulation.js @@ -1,34 +1,39 @@ -const mongoose = require('mongoose') +const Sequelize = require("sequelize"); +const db = require('../db/postgres.js') +const User = require(`./user.js`); -const libs = `${process.cwd()}/libs`; -const log = require(`${libs}/log`)(module); -const User = require(`${libs}/models/user`); - -const Schema = mongoose.Schema; - -let SimulationSchema = new Schema({ - userId: { - type: Schema.Types.ObjectId, - required: true, - ref: 'User' +var Simulation = db.define("Simulation",{ + id:{ + type: Sequelize.INTEGER, + allowNull: false, + autoIncrement: true, + unique: true, + primaryKey: true }, - content: { - type: String, - required: true, + user_id: { + type: Sequelize.STRING, + allowNull: false + }, + content:{ + type: Sequelize.STRING, + allowNull: false }, name: { - type: String + type: Sequelize.STRING, }, - createdAt: { - type: Date, - required: true, - default: Date.now + created_at:{ + type: Sequelize.DATE, + allowNull: false, + defaultValue: Date.now }, - updatedAt: { + updated_at: { type: Date, required: true, default: Date.now } -}); +}, +{timestamps: false}); + +Simulation.hasOne(User,{ foreignKey: 'id' }); -module.exports = mongoose.model('Simulation', SimulationSchema); +module.exports = Simulation; diff --git a/src/libs/models/user.js b/src/libs/models/user.js index be62f4a5cf87074e2f84695f3d1e190c20b8c118..405909eb1e39ea94a0b283aed9c1fedf8295ec25 100644 --- a/src/libs/models/user.js +++ b/src/libs/models/user.js @@ -1,119 +1,202 @@ -const mongoose = require('mongoose'); -const crypto = require('crypto') +const Sequelize = require("sequelize"); +const crypto = require('crypto'); +const db = require('../db/postgres.js'); const libs = `${process.cwd()}/libs`; -const log = require(`${libs}/log`)(module); -const Schema = mongoose.Schema; +const Role = require(`${libs}/models/role`); -// set up a mongoose model -var UserSchema = new Schema({ - email: { - type: String, +// set up a sequelize model +var User = db.define("User",{ + id:{ + type: Sequelize.STRING, + allowNull:false, unique: true, - required: [true, 'O campo Email é obrigatório.'] + primaryKey: true }, - hashedPassword: { - type: String, - required: [true, 'O campo Senha é obrigatório.'] + email: { + type: Sequelize.STRING, + allowNull: false, + unique: true, + validate: { + notNull: { msg: "O campo Email é obrigatório." }, + notEmpty: { msg: "O campo Email é obrigatório." } + } }, - salt: { - type: String, - required: true + password:{ + type: Sequelize.VIRTUAL }, - name: { - type: String, - required: [true, 'O campo Nome é obrigatório.'] + hashed_password:{ + type: Sequelize.STRING, + allowNull: false, }, - nickname: { - type: String, - required: [true, 'O campo Apelido é obrigatório.'] + salt: { + type: Sequelize.STRING, + allowNull: false, + }, + name:{ + type: Sequelize.STRING, + allowNull: false, + validate: { + notNull: { msg: "O campo Nome é obrigatório." }, + notEmpty: { msg: "O campo Nome é obrigatório." } + } + }, + nickname:{ + type: Sequelize.STRING, + allowNull: false, + validate: { + notNull: { msg: "O campo Apelido é obrigatório." }, + notEmpty: { msg: "O campo Apelido é obrigatório." } + } }, cpf:{ - type: String, + type: Sequelize.STRING, + allowNull: false, unique: true, - required: [true, 'O campo CPF é obrigatório.'] + validate: { + notNull: { msg: "O campo CPF é obrigatório." }, + notEmpty: { msg: "O campo CPF é obrigatório." } + } }, cep:{ - type: String, - required: [true, 'O campo CEP é obrigatório.'] - }, - schooling: { - type: String, - required: [true, 'O campo Formação é obrigatório.'] - }, - course: { - type: String, - }, - complement: { - type: String, - }, - address: { - type: String, - }, - phone: { - type: String, - }, - segment: { - type: String, - required: [true, 'O campo Segmento é obrigatório.'] - }, - role: { - type: String, - required: [true, 'O campo Função é obrigatório.'] - }, - institutionName: { - type: String, - required: [true, 'O campo Instituição em que trabalha ou estuda é obrigatório.'] - }, - state: { - type: String, - required: [true, 'O campo Estado é obrigatório.'] - }, - city: { - type: String, - required: [true, 'O campo Cidade é obrigatório.'] - }, - receiveEmails: { - type: Boolean - }, - createdAt: { - type: Date, - default: Date.now - }, - origin: { - type: String, - enum: ['LDE', 'SimCAQ', 'MAPFOR'], - required: [true, 'O campo origem é obrigatória e aceita apenas os valores "LDE", "SimCAQ" e "MAPFOR"'] - }, - verified: { - type: Boolean, - default: false - }, - citesegment: { - type: String - }, - citerole: { - type: String - }, - admin: { - type: Boolean, - default: false + type: Sequelize.STRING, + allowNull: false, + validate: { + notNull: { msg: "O campo CEP é obrigatório." }, + notEmpty: { msg: "O campo CEP é obrigatório." } + } + }, + schooling:{ + type: Sequelize.STRING, + allowNull: false, + validate: { + notNull: { msg: "O campo Formação é obrigatório." }, + notEmpty: { msg: "O campo Formação é obrigatório." } + } + }, + course:{ + type: Sequelize.STRING, + }, + complement:{ + type: Sequelize.STRING + }, + address:{ + type: Sequelize.STRING, + }, + phone:{ + type: Sequelize.STRING, + }, + segment:{ + type: Sequelize.STRING, + allowNull: false, + validate: { + notNull: { msg: "O campo Segmento é obrigatório." }, + notEmpty: { msg: "O campo Segmento é obrigatório." } + } + }, + role:{ + type: Sequelize.STRING, + allowNull: false, + validate: { + notNull: { msg: "O campo Função é obrigatório." }, + notEmpty: { msg: "O campo Função é obrigatório." } + } + }, + institution_name:{ + type: Sequelize.STRING, + allowNull: false, + validate: { + notNull: { msg: "O campo Instituição em que trabalha ou estuda é obrigatório." }, + notEmpty: { msg: "O campo Instituição em que trabalha ou estuda é obrigatório." } + } + }, + state:{ + type: Sequelize.STRING, + allowNull: false, + validate: { + notNull: { msg: "O campo Estado é obrigatório." }, + notEmpty: { msg: "O campo Estado é obrigatório." } + } + }, + city:{ + type: Sequelize.STRING, + allowNull: false, + validate: { + notNull: { msg: "O campo Cidade é obrigatório." }, + notEmpty: { msg: "O campo Cidade é obrigatório." } + } + }, + receive_email:{ + type: Sequelize.BOOLEAN, + }, + created_at:{ + type: Sequelize.DATE, + defaultValue: Date.now + }, + origin:{ + type: Sequelize.ENUM("LDE", "SimCAQ", "MAPFOR"), + allowNull:false, + validate: { + notNull: { msg: "O campo origem é obrigatória e aceita apenas os valores 'LDE', 'SimCAQ' e 'MAPFOR'."}, + notEmpty: { msg: "O campo origem é obrigatória e aceita apenas os valores 'LDE', 'SimCAQ' e 'MAPFOR'."} + } + }, + verified:{ + type: Sequelize.BOOLEAN, + defaultValue:false + }, + citesegment:{ + type: Sequelize.STRING, + }, + citerole:{ + type: Sequelize.STRING + }, + admin:{ + type: Sequelize.BOOLEAN, + defaultValue:false + }, + role_id:{ + type: Sequelize.NUMBER, + allowNull:false, + defaultValue: 0 } -}); +}, + {timestamps: false} +); + +User.hasOne(Role, {foreignKey: 'id'}); + +User.generateSalt = function() { + return crypto.randomBytes(128).toString('hex'); +} + +User.encryptPassword = function(password, salt) { + return crypto.pbkdf2Sync(password+'', salt, 10000, 512, 'sha512').toString('hex'); +} + +User.generateObjectId = function(){ + var timestamp = (new Date().getTime() / 1000 | 0).toString(16); + return timestamp + 'xxxxxxxxxxxxxxxx'.replace(/[x]/g, function() { + return (Math.random() * 16 | 0).toString(16); + }).toLowerCase(); +} + +const setSaltAndPassword = user => { + if (user.changed('password')) { + user.salt = User.generateSalt() + user.hashed_password = User.encryptPassword(user.password, user.salt).toString('hex'); + } +} -UserSchema.methods.encryptPassword = function(password) { - return crypto.pbkdf2Sync(password+'', this.salt, 10000, 512, 'sha512'); +const setObjectId = user => { + user.id = User.generateObjectId() }; -UserSchema.virtual('password').set(function(password) { - this._plainPassword = password+''; - this.salt = crypto.randomBytes(128).toString('hex'); - this.hashedPassword = this.encryptPassword(password).toString('hex'); -}).get(function() { - return this._plainPassword; -}); +User.beforeCreate(setSaltAndPassword) +User.beforeCreate(setObjectId) +User.beforeUpdate(setSaltAndPassword) -UserSchema.methods.checkPassword = function(password) { - return this.encryptPassword(password).toString('hex') === this.hashedPassword; +User.prototype.checkPassword = function(user, enteredPassword) { + return User.encryptPassword(enteredPassword, user.salt) === user.hashed_password } -module.exports = mongoose.model('User', UserSchema); +module.exports = User; diff --git a/src/libs/models/userActivity.js b/src/libs/models/userActivity.js new file mode 100644 index 0000000000000000000000000000000000000000..2c1f8b56003b6e05243e4746ef6185cedad7df1b --- /dev/null +++ b/src/libs/models/userActivity.js @@ -0,0 +1,29 @@ +const Sequelize = require("sequelize"); +const db = require('../db/postgres.js'); +const libs = `${process.cwd()}/libs`; +const User = require(`${libs}/models/user`); +const Activity = require(`${libs}/models/activity`); + +var userActivity = db.define("userActivity",{ + id:{ + type: Sequelize.INTEGER, + allowNull:false, + unique: true, + primaryKey: true + }, + user_id:{ + type: Sequelize.STRING, + allowNull:false, + }, + activity_id:{ + type: Sequelize.STRING, + allowNull:false + } +}, +{timestamps: false}); + +userActivity.hasMany(User, {foreignKey: 'id'}); +userActivity.hasMany(Activity, {foreignKey: 'id'}); + +module.exports = userActivity; + diff --git a/src/libs/models/userPublication.js b/src/libs/models/userPublication.js new file mode 100644 index 0000000000000000000000000000000000000000..654dd3c33827fb926fa4b5d1e7e48241a03689df --- /dev/null +++ b/src/libs/models/userPublication.js @@ -0,0 +1,29 @@ +const Sequelize = require("sequelize"); +const db = require('../db/postgres.js'); +const libs = `${process.cwd()}/libs`; +const User = require(`${libs}/models/user`); +const Publication = require(`${libs}/models/publication`); + +var userPublication = db.define("userPublication",{ + id:{ + type: Sequelize.INTEGER, + allowNull:false, + unique: true, + primaryKey: true + }, + user_id:{ + type: Sequelize.STRING, + allowNull:false, + }, + publication_id:{ + type: Sequelize.STRING, + allowNull:false + } +}, +{timestamps: false}); + +userPublication.hasMany(User, {foreignKey: 'id'}); +userPublication.hasMany(Publication, {foreignKey: 'id'}); + +module.exports = userPublication; + diff --git a/src/libs/models/verificationToken.js b/src/libs/models/verificationToken.js index ef7e109e16364874ea7d3f4b07b6e19ce74c3eae..9038cac1961db16f3f88522c89efe089243a3819 100644 --- a/src/libs/models/verificationToken.js +++ b/src/libs/models/verificationToken.js @@ -1,41 +1,31 @@ -const mongoose = require('mongoose'); -const Schema = mongoose.Schema; -const libs = `${process.cwd()}/libs`; -const log = require(`${libs}/log`)(module); -const User = require(`${libs}/models/user`); +const Sequelize = require("sequelize"); +const db = require('../db/postgres.js') +const User = require(`./user.js`); const uuid = require('node-uuid'); -let VerificationToken = new Schema({ - userId: { - type: Schema.Types.ObjectId, - required: true, - ref: 'User' +var VerificationToken = db.define("VerificationToken",{ + user_id: { + type: Sequelize.STRING, + allowNull: false }, - token: { - type: String, - required: true + token:{ + type: Sequelize.STRING, + allowNull: false, + primaryKey: true }, - verified: { - type: Boolean, - required: true, - default: false + verified:{ + type: Sequelize.BOOLEAN, + allowNull: false, + defaultValue: false }, - createdAt: { - type: Date, - required: true, - default: Date.now + created_at:{ + type: Sequelize.DATE, + allowNull: false, + defaultValue: Date.now } -}); +}, +{timestamps: false}); -VerificationToken.methods.createVerificationToken = function(done) { - let verificationToken = this; - let token = uuid.v4(); - verificationToken.set('token', token); - verificationToken.verified = false; - verificationToken.save(function(err) { - if (err) return done(err); - return done(null, token); - }) -} +VerificationToken.hasOne(User,{ foreignKey: 'id' }); -module.exports = mongoose.model('VerificationToken', VerificationToken); +module.exports = VerificationToken; diff --git a/src/libs/routes_v1/activity.js b/src/libs/routes_v1/activity.js new file mode 100644 index 0000000000000000000000000000000000000000..51ef67ea1ae60d35636dc42f3770f62b0fd9b29b --- /dev/null +++ b/src/libs/routes_v1/activity.js @@ -0,0 +1,207 @@ +const express = require('express'); + +const activityApp = express(); + +const libs = `${process.cwd()}/libs`; + +const config = require(`${libs}/config`); + +const log = require(`${libs}/log`)(module); + +const Activity = require(`${libs}/models/activity`); + +const response = require(`${libs}/middlewares/response`); + +const email = require(`${libs}/middlewares/email`); + +const passport = require('passport'); + +const fileWorker = require('./file.controller.js'); + +let upload = require('../middlewares/multer.config.js'); + +const authorized = require(`${libs}/middlewares/authorize.js`); + +function emailSyntax(email) { + const regex = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; + return regex.test(email); +} + +activityApp.get('/', async (req, res, next) => { + const page = parseInt(req.query.page) || 1; + const pageSize = parseInt(req.query.pageSize) || 5; + try { + const totalCount = await Activity.count(); + const offset = (page - 1) * pageSize; + + const acts = await Activity.findAll({ + offset, + limit: pageSize, + order:[ + ['date', 'DESC']] + }); + + res.json({ + page, + pageSize, + totalCount, + data: acts, + }); + } catch (error) { + console.error(error); + res.status(500).json({ error: 'An error occurred' }); + } +}); + +activityApp.get('/drafts', async (req, res, next) => { + const page = parseInt(req.query.page) || 1; + const pageSize = parseInt(req.query.pageSize) || 5; + try { + const totalCount = await Activity.count({where: { + is_draft: true + }}); + const offset = (page - 1) * pageSize; + + const acts = await Activity.findAll({ + offset, + limit: pageSize, + where: { + is_draft: true + }, + order:[ + ['date', 'DESC']] + }); + + res.json({ + page, + pageSize, + totalCount, + data: acts, + }); + } catch (error) { + console.error(error); + res.status(500).json({ error: 'An error occurred' }); + } + }); + +activityApp.get('/:id', (req, res, next) => { + Activity.findByPk(req.params.id).then((act) => { + if (!act) { + res.statusCode = 404; + res.json({ msg: "A atividade não está cadastrada" }); + } else { + req.result = act.toJSON(); + next(); + } + }).catch(function (err) { + log.error(err); + return next(err); + }); +}, response('activity')); + + +function transformDateFormat(dateString) { + // Split the date string into day, month, and year components + var parts = dateString.split('/'); + + // Extract day, month, and year values + var day = parts[0]; + var month = parts[1]; + var year = parts[2]; + + // Concatenate the components in "yyyy/mm/dd" format + var transformedDate = year + '/' + month + '/' + day; + + return transformedDate; +} + + + +activityApp.post('/', passport.authenticate('bearer', { session: false }), authorized('criar atividade'), async (req, res, next) => { + console.log(req.body); + let act = await Activity.create({ + id: 0, + type:req.body.tipo, + title: req.body.titulo, + subtitle: req.body.subtitulo, + date: transformDateFormat(req.body.dataDePostagem), + authors:req.body.autor, + text: req.body.texto, + name_headline: req.body.nome, + resume_headline: req.body.resumo, + date_headline: transformDateFormat(req.body.dataAtividade), + local_headline: req.body.local, + additional_headline: req.body.informacoes, + is_draft: req.body.rascunho, + is_headline: req.body.is_headline + }).catch(function (err) { + log.error(err); + let errors = []; + for (let errName in err.errors) { + errors.push(err.errors[errName].message); + } + log.error(errors); + res.statusCode = 400; + return res.json({ err, errors }); + // handle error; + }); + if(!act){ + res.statusCode = 400; + return res; + } + req.result = act.toJSON(); + next(); +}, response('activity')); + +activityApp.put('/:id', passport.authenticate('bearer', { session: false }), authorized('editar atividade'), async (req, res, next) => { + let act = await Activity.findByPk(req.params.id).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }) + if (!act) { + res.statusCode = 404; + return next({ + err: { + message: 'Atividade não encontrada' + } + }); + } + console.log("TEste"); + act.type = req.body.type || act.type; + act.title = req.body.title || act.title; + act.subtitle = req.body.subtitle || act.subtitle; + act.date = req.body.date || act.date; + act.authors = req.body.autores || act.authors; + act.text= req.body.text || act.text; + act.name_headline= req.body.name_headline || act.name_headline; + act.resume_headline= req.body.resume_headline || act.resume_headline; + act.date_headline= req.body.date_headline || act.date_headline; + act.local_headline= req.body.local_headline || act.local_headline; + act.additional_headline= req.body.additional_headline || act.additional_headline; + act.is_draft= req.body.is_draft || act.is_draft; + act.is_headline= req.body.is_headline || act.is_headline; + + act.save().catch(err => { + if (err) { + log.error(err); + return next({ message: 'Erro ao atualizar publicacao' }); + } + }) + let activity = act.toJSON(); + res.json({ activity: activity}); + +}); + +activityApp.delete('/:id', passport.authenticate('bearer', { session: false }), authorized('editar atividade'), async (req, res, next) => { + await Activity.destroy({where:{id:req.params.id}}).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } +}); + return next({ msg: 'Activity Deleted', status: 200 }); +}); + +module.exports = activityApp; diff --git a/src/libs/routes/api.js b/src/libs/routes_v1/api.js similarity index 61% rename from src/libs/routes/api.js rename to src/libs/routes_v1/api.js index f6715eaa36c611eb5632d801cf3546ccd528fa16..75a8e663f013e2716c8f01fdd99225b2265fb51e 100644 --- a/src/libs/routes/api.js +++ b/src/libs/routes_v1/api.js @@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public License along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. */ + const express = require('express'); const api = express(); @@ -26,6 +27,8 @@ const libs = `${process.cwd()}/libs`; const config = require(`${libs}/config`); +const test = require('./test'); + const classes = require('./class'); const enrollment = require('./enrollment'); @@ -66,79 +69,84 @@ const idhml = require('./idhml'); const oauth2 = require(`${libs}/middlewares/oauth2`); -const verifyToken = require(`${libs}/routes/verifyToken`); +const verifyToken = require(`${libs}/routes_v1/verifyToken`); -const resetToken = require(`${libs}/routes/resetToken`); +const resetToken = require(`${libs}/routes_v1/resetToken`); -const educationYears = require(`${libs}/routes/educationYears`); +const educationYears = require(`${libs}/routes_v1/educationYears`); -const downloads = require(`${libs}/routes/downloads`); +const downloads = require(`${libs}/routes_v1/downloads`); -const infrastructure = require(`${libs}/routes/infrastructure`); +const infrastructure = require(`${libs}/routes_v1/infrastructure`); -const schoolInfrastructure = require(`${libs}/routes/schoolInfrastructure`); +const schoolInfrastructure = require(`${libs}/routes_v1/schoolInfrastructure`); -const distributionFactor = require(`${libs}/routes/distributionFactor`); +const distributionFactor = require(`${libs}/routes_v1/distributionFactor`); -const siope = require(`${libs}/routes/siope`); +const siope = require(`${libs}/routes_v1/siope`); -const verifyTeacher = require(`${libs}/routes/portalMec`); +const verifyTeacher = require(`${libs}/routes_v1/portalMec`); -const outOfSchool = require(`${libs}/routes/outOfSchool`); +const outOfSchool = require(`${libs}/routes_v1/outOfSchool`); -const classroomCount = require(`${libs}/routes/classroomCount`); +const classroomCount = require(`${libs}/routes_v1/classroomCount`); const transport = require(`./transport`); -const auxiliar = require(`${libs}/routes/auxiliar`); +const auxiliar = require(`${libs}/routes_v1/auxiliar`); + +const dailyChargeAmount = require(`${libs}/routes_v1/dailyChargeAmount`); -const dailyChargeAmount = require(`${libs}/routes/dailyChargeAmount`); +const cub = require(`${libs}/routes_v1/cub`); -const cub = require(`${libs}/routes/cub`); +const classCount = require(`${libs}/routes_v1/classCount`); -const classCount = require(`${libs}/routes/classCount`); +const portalMecInep = require(`${libs}/routes_v1/portalMecInep`); -const portalMecInep = require(`${libs}/routes/portalMecInep`); +const enrollmentProjection = require(`${libs}/routes_v1/enrollmentProjection`); -const enrollmentProjection = require(`${libs}/routes/enrollmentProjection`); +const employees = require(`${libs}/routes_v1/employees`); -const employees = require(`${libs}/routes/employees`); +const financial = require(`${libs}/routes_v1/financial`); -const financial = require(`${libs}/routes/financial`); +const universityEnrollment = require(`${libs}/routes_v1/universityEnrollment`); -const universityEnrollment = require(`${libs}/routes/universityEnrollment`); +const courseCount = require(`${libs}/routes_v1/courseCount`); -const courseCount = require(`${libs}/routes/courseCount`); +const university = require(`${libs}/routes_v1/university`); -const university = require(`${libs}/routes/university`); +const universityTeacher = require(`${libs}/routes_v1/universityTeacher`); -const universityTeacher = require(`${libs}/routes/universityTeacher`); +const educationalBudget = require(`${libs}/routes_v1/educationalBudget`); -const educationalBudget = require(`${libs}/routes/educationalBudget`); +const schoolLocation = require(`${libs}/routes_v1/schoolLocation`); -const schoolLocation = require(`${libs}/routes/schoolLocation`); +const studentsAee = require(`${libs}/routes_v1/studentsAee`); -const studentsAee = require(`${libs}/routes/studentsAee`); +const mesoregion = require(`${libs}/routes_v1/mesoregion`); -const mesoregion = require(`${libs}/routes/mesoregion`); +const microregion = require(`${libs}/routes_v1/microregion`); -const microregion = require(`${libs}/routes/microregion`); +const location = require(`${libs}/routes_v1/location`); -const location = require(`${libs}/routes/location`); +const disciplines = require(`${libs}/routes_v1/disciplines`); -const disciplines = require(`${libs}/routes/disciplines`); +const universityLocalOffer = require(`${libs}/routes_v1/universityLocalOffer`); -const universityLocalOffer = require(`${libs}/routes/universityLocalOffer`); +const message = require(`${libs}/routes_v1/message`); -const message = require(`${libs}/routes/message`); +const courseStudents = require(`${libs}/routes_v1/courseStudents`); -const courseStudents = require(`${libs}/routes/courseStudents`); +const publication = require(`${libs}/routes_v1/publication`); + +const activity = require(`${libs}/routes_v1/activity`); api.get('/', (req, res) => { - res.json({ msg: 'SimCAQ API is running' }); + res.json({ msg: 'SimCAQ API v1 is running' }); }); -// mount API routes +// mount API routes_v1 +api.use('/test', test); api.use('/user', user); api.use('/simulation', simulation); api.use('/class', classes); @@ -193,4 +201,10 @@ api.use('/universityLocalOffer', universityLocalOffer); api.use('/message', message); api.use('/course_students', courseStudents); +//Publication +api.use('/publication', publication); + +//Activity +api.use('/activity', activity); + module.exports = api; diff --git a/src/libs/routes/auxiliar.js b/src/libs/routes_v1/auxiliar.js similarity index 100% rename from src/libs/routes/auxiliar.js rename to src/libs/routes_v1/auxiliar.js diff --git a/src/libs/routes/city.js b/src/libs/routes_v1/city.js similarity index 100% rename from src/libs/routes/city.js rename to src/libs/routes_v1/city.js diff --git a/src/libs/routes/class.js b/src/libs/routes_v1/class.js similarity index 100% rename from src/libs/routes/class.js rename to src/libs/routes_v1/class.js diff --git a/src/libs/routes/classCount.js b/src/libs/routes_v1/classCount.js similarity index 100% rename from src/libs/routes/classCount.js rename to src/libs/routes_v1/classCount.js diff --git a/src/libs/routes/classroom.js b/src/libs/routes_v1/classroom.js similarity index 100% rename from src/libs/routes/classroom.js rename to src/libs/routes_v1/classroom.js diff --git a/src/libs/routes_v1/classroomCount.js b/src/libs/routes_v1/classroomCount.js new file mode 100644 index 0000000000000000000000000000000000000000..a1dbc69cfedcf13265c49baa6020a01cde7e4ab9 --- /dev/null +++ b/src/libs/routes_v1/classroomCount.js @@ -0,0 +1,1238 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + + +const express = require('express'); + +const classroomCountApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValueToField({ + name: 'city', + table: 'municipio', + tableField: 'nome', + resultField: 'city_name', + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: '@' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: '@' + } +}, 'filter').addValueToField({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: '@' + } +}, 'dims').addValueToField({ + name: 'state', + table: 'estado', + tableField: 'nome', + resultField: 'state_name', + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: '@' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: '@' + } +}, 'filter').addValueToField({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id', + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: '@' + } +}, 'dims').addValueToField({ + name: 'school', + table: 'escola', + tableField: ['nome_escola', 'id', 'dependencia_adm_id'], // Dado de dependencia administrativa sempre deve ser retornado com escola + resultField: ['school_name', 'school_id', 'adm_dependency_id'], + where: { + relation: '=', + type: 'integer', + field: 'id', + }, + join: { + primary: ['id', 'ano_censo'], + foreign: ['escola_id', 'ano_censo'], + foreignTable: '@' + } +}, 'dims').addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: '@' + } +}).addValue({ + name: 'min_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'school_year', + table: '@', + tableField: 'serie_ano_id', + resultField: 'school_year_id', + where: { + relation: '=', + type: 'integer', + field: 'serie_ano_id' + } +}).addValue({ + name: 'location', + table: '@', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'period', + table: '@', + tableField: 'turma_turno_id', + resultField: 'period_id', + where: { + relation: '=', + type: 'integer', + field: 'turma_turno_id' + } +}).addValue({ + name: 'school_building', + table: 'escola', + tableField: 'local_func_predio_escolar', + resultField: 'school_building', + where: { + relation: '=', + type: 'boolean', + field: 'local_func_predio_escolar' + } +}).addValue({ + name: 'night_time', + table: 'matricula', + tableField: 'periodo_noturno', + resultField: 'night_time', + where: { + relation: '=', + type: 'boolean', + field: 'periodo_noturno' + } +}).addValue({ + name: 'formation_level', + table: 'docente_por_formacao', + tableField: 'tipo_formacao', + resultField: 'formation_level', + where: { + relation: '=', + type: 'integer', + field: 'tipo_formacao' + } +}).addValueToField({ + name: 'adm_dependency', + table: '@', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}, 'filter') .addValue({ + name: 'integral_time', + table: 'matricula', + tableField: 'tempo_integral', + resultField: 'integral_time_id', + where: { + relation: '=', + type: 'integer', + field: 'tempo_integral' + } +}).addValue({ + name: 'education_level_short', + table: 'matricula', + tableField: 'etapa_resumida', + resultField: 'education_level_short_id', + where: { + relation: '=', + type: 'integer', + field: 'etapa_resumida' + } +}); + +function minimunClasses(education_level_short_id) { + switch(education_level_short_id) { + case 3: // Ensino Fundamental - anos iniciais + return 5; + case 4: // Ensino Fundamental - anos finais + return 4; + case 5: // Ensino Médio + return 3; + case 6: // EJA + return 2; + default: + return 0; + } +} + +function minimunEnrollment (ed_level) { + switch (ed_level) { + case 3: // Ensino Fundamental - anos iniciais + return 60; + case 4: // Ensino Fundamental - anos finais + return 52; + case 5: // Ensino Médio + return 39; + case 6: // EJA + return 24; + default: + return 0; + } +} + +classroomCountApp.post('/', rqf.parse(), (req, res, next) => { + let classSize = JSON.parse(req.body.class_size) || null; + let integralTime = JSON.parse(req.body.integral_time) || null; + let enrollmentProjection = (req.body.projections !== undefined) ? JSON.parse(req.body.projections) : null; + + if(classSize == null || integralTime == null) { + res.statusCode = 400; + return res.json({err: {message: "There was an error processing class_size or integral_time. Check your JSON sintax and be sure you're sending both paramenters."}}); + } + req.classSize = classSize; + req.integralTime = integralTime; + req.projections = (enrollmentProjection !== null) ? enrollmentProjection : false; + + req.dims.state = true; + req.dims.city = true; + req.dims.school_year = true; + req.dims.location = true; + + req.sql.field('sum(dia_total)', 'total_day') + .field('sum(noite_total)', 'total_night') + .field("'Brasil'", 'name') + .field('matricula_por_localizacao.ano_censo', 'year') + .from('matricula_por_localizacao') + .where('matricula_por_localizacao.serie_ano_id < 15') + .group('matricula_por_localizacao.ano_censo') + .order('matricula_por_localizacao.ano_censo') + + next(); +}, rqf.build(), query, id2str.transform(), (req, res, next) => { + req.enrollment = req.result; + + // Gera a relação etapa de ensino X ano escolar + req.educationSchoolYear = {}; + for(let i = 1; i < 15; ++i) { + if(id2str.educationLevelSchoolYear(i) !== id2str.educationLevelSchoolYear(99)) { + let educationLevelId = (i > 10) ? Math.floor(i/10) : i; + + let classSize = req.classSize.find((el) => {return el.id === educationLevelId || el.id === i}); + let integralTime = req.integralTime.find((el) => {return el.id === educationLevelId}); + + let numberStudentClass = (typeof classSize !== 'undefined') ? classSize.numberStudentClass : null; + // Usa o offerGoal que é passado como parâmetro (Brasil inteiro). Atenção para isso. + let integralTimeOfferGoal = (typeof integralTime !== 'undefined') ? integralTime.offerGoal : null; + + let teacherByClass = (typeof classSize !== 'undefined') ? classSize.teacherByClass : null; + + req.educationSchoolYear[i] = { + id: educationLevelId, + name: id2str.educationLevelShort(educationLevelId), + numberStudentClass, + integralTimeOfferGoal, + teacherByClass + }; + } + } + + delete req.dims; + delete req.filter; + req.resetSql(); + next(); +}, rqf.parse(), (req, res, next) => { + + req.dims.state = true; + req.dims.city = true; + req.dims.location = true; + req.dims.school_building = true; + + req.sql.field('SUM(escola.qtde_salas_utilizadas_dentro)', 'total') + .field("'Brasil'", 'name') + .field('escola.ano_censo', 'year') + .from('escola') + .group('escola.ano_censo') + .order('escola.ano_censo') + .where('escola.situacao_de_funcionamento = 1') + .where('escola.dependencia_adm_id < 4') + .where('escola.ensino_regular = 1 OR escola.ensino_eja = 1 OR escola.educacao_profissional = 1'); + + next(); +}, rqf.build(), query, id2str.transform(), (req, res, next) => { + req.classroom = req.result; + + delete req.dims; + delete req.filter; + req.resetSql(); + next(); +}, rqf.parse(), (req, res, next) => { + if (req.body.teacher_journey !== undefined) { + // req.teacherJourney = JSON.parse(req.body.teacher_journey) || null; + + let schoolDays = JSON.parse(req.body.school_days) || null; + let teacherFormation = JSON.parse(req.body.teacher_formation) || null; + let teachingHours = JSON.parse(req.body.teaching_hours) || null; + + let schoolDaysParsed = []; + let teachingHoursParsed = []; + for(let i = 1; i <= 6; i++) { // Adciona turnos faltantes, corrige ordem dos id's + schoolDaysParsed.push(schoolDays.find((el) => {return el.id === i})) + + let schoolYear = teachingHours.find((el) => {return el.id === i}) + let shifts = [] + for (let j = 1; j <= 3; j++) { + let turno = schoolYear.shifts.find((el) => {return el.id === j}) + if (turno === undefined) { + turno = {"id": j, value: 0} + } + + shifts.push(turno) + } + schoolYear.shifts = shifts + teachingHoursParsed.push(schoolYear) + } + + req.schoolDays = schoolDaysParsed; + req.teachingHours = teachingHoursParsed; + + let teacherFormationParsed = [] + for (let i of [2, 4, 6, 7, 8]) { + teacherFormationParsed.push(teacherFormation.find((el) => {return el.idFormationLevel === i})) + } + req.teacherFormation = teacherFormationParsed; + + req.teacherCalc = true; + } + + req.dims.state = true; + req.dims.city = true; + req.dims.formation_level = true; + req.sql.field('count(distinct docente_por_formacao.id_docente)', 'total') + .field("'Brasil'", 'name') + .field('docente_por_formacao.ano_censo', 'year') + .from('docente_por_formacao') + .group('docente_por_formacao.ano_censo') + .order('docente_por_formacao.ano_censo'); + + next(); +}, rqf.build(), query, id2str.transform(), (req, res, next) => { + req.teacher = req.result; + + delete req.dims; + delete req.filter; + req.resetSql(); + next(); +}, rqf.parse(), (req, res, next) => { + req.dims.state = true; + req.dims.city = true; + req.dims.education_level_short = true; + req.dims.integral_time = true; + req.sql.field('COUNT(*)', 'total') + .field('matricula.ano_censo', 'year') + .from('matricula') + .group('matricula.ano_censo') + .order('matricula.ano_censo') + .where('((matricula.tipo<=3 OR matricula.tipo IS NULL) AND (matricula.tipo_atendimento_turma IS NULL OR matricula.tipo_atendimento_turma <= 2) AND matricula.turma_turno_id <> 99)'); + next(); +}, rqf.build() ,query, id2str.transform(), (req, res, next) => { + // constrói objeto de tempo integral e calcula diagnósticos + var integral_time_result = req.result + req.integral_time = {} + for (let i = 0; i < integral_time_result.length; ++i){ + // Se cidade não foi criada, cria + let integral_time = integral_time_result[i]; + let code = '' + integral_time.year + integral_time.city_id + if (req.dims.school) code = code + integral_time.school_id + + let currentCodeObj = req.integral_time[code] + + // Cria município/escola caso não exista + if (currentCodeObj === undefined){ + let obj = { + year: integral_time.year, + city_id: integral_time.city_id, + city_name: integral_time.city_name, + integral_time: {} + } + if (req.dims.school){ + obj.school_id = integral_time.school_id + obj.school_name = integral_time.school_name + obj.adm_dependency_id = integral_time.adm_dependency_id + obj.adm_dependency_name = integral_time.adm_dependency_name + } + req.integral_time[code] = obj + currentCodeObj = obj; + } + + // Pega objeto com dados do nível atual + var level = integral_time.education_level_short_id + var levelObj = currentCodeObj.integral_time[level] + if (levelObj === undefined){ + levelObj = { + id: level, + integralTime: 0, + total: 0, + } + } + + // Soma no total em integralTime, caso seja 1 + levelObj.total += integral_time.total + if (integral_time.integral_time_id === 1){ + levelObj.integralTime += integral_time.total + } + + currentCodeObj.integral_time[level] = levelObj + + } + for (let i in req.integral_time){ + let curObj = req.integral_time[i] + // Adiciona diagnóstico aos objetos + for (let key in curObj.integral_time){ + let cur = curObj.integral_time[key] + cur["diagnosis"] = cur.total ? (cur.integralTime/cur.total)*100.0 : 0.0; + curObj.integral_time[key] = cur + } + } + + delete req.dims; + delete req.filter; + req.resetSql(); + next() +}, rqf.parse(), rqf.build(), (req, res, next) => { + + // Talvez dê para remover todos os req.projections. + let enrollmentProjectionNight = []; + let enrollmentProjectionDay = []; + if (req.projections) { + for (let i = 0; i < req.projections.length; i++) { + if (req.projections[i].periods === 3) { + enrollmentProjectionNight.push(req.projections[i]); + } else { + enrollmentProjectionDay.push(req.projections[i]); + } + } + } + let qntYears = 1; + if (req.projections) { + qntYears = enrollmentProjectionDay[0].stagesEnrollments[0].seriesEnrollments[0].enrollments.length; + } + let result = []; + + // Cria estrutura de resposta requisitada (itera por anos de projeção): + for(let yearCount = 0; yearCount < qntYears; yearCount++) { + let i = 0; + let j = 0; + let hashSet = new Set(); + let enrollments = [...req.enrollment]; + + let ti = 0; // index for teacher table + + while (i < req.classroom.length) { + let classroom = req.classroom[i]; + // Cria hash única para cada espacialidade, dado um ano + let hash = '' + yearCount + classroom.state_id + classroom.city_id; + if (req.dims.school) + hash = hash + classroom.school_id + // Estrutura do objeto do resultado final + let obj = { + year: classroom.year + yearCount, + name: classroom.name, + state_id: classroom.state_id, + state_name: classroom.state_name, + city_id: classroom.city_id, + city_name: classroom.city_name, + }; + if (req.dims.school){ + obj.school_id = classroom.school_id, + obj.school_name = classroom.school_name, + obj.adm_dependency_id = classroom.adm_dependency_id, + obj.adm_dependency_name = classroom.adm_dependency_name + } + if (req.teacherCalc) + obj.percentage_teacher_career = []; + obj.locations = [] + + // Inserimos a localidade no array de locations da sala + let location = { + location_id: classroom.location_id, + location_name: classroom.location_name, + total_classroom: (classroom.school_building == 1) ? parseInt(classroom.total, 10) : 0, // Conta apenas salas de prédios próprios + total_classroom_be_built: 0, + education_level: [] + }; + + // Ajusta estrutura de localização do último [município/escola] e inicializa variáveis para o atual + let currentClassroomObj = null; + if( !hashSet.has(hash) ) { // Nunca passou por esse município/escola + if (result[result.length - 1] !== undefined) { // Após mudar de cidade, passamos pela cidade anterior e juntamos o valor to_be_built de localizações com o mesmo id + let last_city = result[result.length - 1] + let last_locations = result[result.length - 1].locations + for (let i = 0; i < last_locations.length - 1; i++) { + if (last_locations[i].location_id === last_locations[i+1].location_id) { + last_locations[i].total_classroom_be_built += last_locations[i+1].total_classroom_be_built; + last_locations[i].total_classroom += last_locations[i+1].total_classroom; + last_locations.splice(i+1, 1); + } + } + for (let i = 0; i < last_locations.length; i++) { // Passamos agora para não deixar to_be_built < 0 + last_locations[i].total_classroom_be_built = (last_locations[i].total_classroom_be_built < 0) ? 0 : last_locations[i].total_classroom_be_built; + } + + if (req.teacherCalc) executeTeacherCalc(last_city, ti); + } + hashSet.add(hash); + result.push(obj); + currentClassroomObj = obj; + + var id_attribute = req.dims.school ? "school_id" : "city_id" + + var old_ti = ti; + while (ti < req.teacher.length && req.teacher[ti][id_attribute] !== classroom[id_attribute]) // match da tabela de professores. + ti++; + + if (ti === req.teacher.length) { + console.log(classroom[id_attribute], "not found") + while (classroom[id_attribute] === enrollments[j][id_attribute]) + enrollments.splice(j, 1) + ti = old_ti; + i++; + continue; + } + + } else { // Se a hash já existe, já temos a cidade nos resultados. Como está ordenado, é o último valor nos resultados + currentClassroomObj = result[result.length - 1]; + } + currentClassroomObj.locations.push(location); + + // Partimos para as etapas de ensino/anos escolares + let enrollmentMatch = true; + j = 0; + let educationLevelSet = new Set(); + let schoolYearSet = new Set(); + let enrollment; + while(enrollmentMatch && j < enrollments.length) { + enrollment = enrollments[j]; + + if(typeof enrollment === 'undefined') { + ++j; + continue; + } + + if (req.dims.school){ + if(classroom.school_id !== enrollment.school_id) { // Se as escolas não são iguais, já passamos do range + enrollmentMatch = false; + continue; + } + } + else{ + if(classroom.city_id !== enrollment.city_id) { // Se as cidades não são iguais, já passamos do range + enrollmentMatch = false; + continue; + } + } + + if(enrollment.year != classroom.year || enrollment.location_id != classroom.location_id) { // Se ano ou localização são diferentes, passa para o próximo + ++j; + continue; + } + + + // Temos uma matrícula com cidade/escola, ano e localidades certos + // "Consome" a matrícula (remove do vetor de matrículas) + enrollments.splice(j, 1); + + // Cria a etapa de ensino adequada + let enrollmentEducationLevel = req.educationSchoolYear[enrollment.school_year_id]; + // Se não há um número de alunos por turna para a etapa de ensino, ignoramos a entrada + + if(enrollmentEducationLevel.numberStudentClass == null) continue; + + // Adiciona nível de educação para município/escola + let educationLevel = null; + if(!educationLevelSet.has(enrollmentEducationLevel.id)) { // cria e insere ordenadamente novo education level + educationLevelSet.add(enrollmentEducationLevel.id); + + let itHash = '' + enrollment.year + enrollment.city_id + if (req.dims.school) itHash += enrollment.school_id + + let cur_education_level_short = enrollmentEducationLevel.id + + let level_diagnosis = 0 + let integral_time = 0; + let integral_time_total = 0; + if (req.integral_time[itHash].integral_time[cur_education_level_short]){ + level_diagnosis = parseFloat( (req.integral_time[itHash].integral_time[cur_education_level_short].diagnosis).toFixed(2) ) + integral_time = req.integral_time[itHash].integral_time[cur_education_level_short].integralTime + integral_time_total = req.integral_time[itHash].integral_time[cur_education_level_short].total + } + + educationLevel = { + education_level_short_id: enrollmentEducationLevel.id, + education_level_short_name: enrollmentEducationLevel.name, + enrollment: { + integral_percentage: req.dims.school ? level_diagnosis : Math.max(level_diagnosis, enrollmentEducationLevel.integralTimeOfferGoal), + integral_time: req.dims.school ? integral_time : Math.round((integral_time_total * Math.max(level_diagnosis, enrollmentEducationLevel.integralTimeOfferGoal)/100) * 10) / 10, + integral_time_total: integral_time_total, + total_enrollment_day: 0, + total_enrollment_night: 0, + full_period_classes: 0, + day_classes: 0, + night_classes: 0, + total_classrooms_needed: 0 + } + }; + + if(enrollmentEducationLevel.id == 1) { + educationLevel.classes_school_year = []; + } + + // Para manter a ordem da etapa de ensino (insertion sort) + if (location.education_level.length == 0) { + location.education_level.push(educationLevel); + } else { + let k = location.education_level.length - 1; + let el = location.education_level[k]; + while (k >= 0) { + if(educationLevel.education_level_short_id < el.education_level_short_id) { + --k; + if(k>=0) el = location.education_level[k]; + } else break; + } + k++; + location.education_level.splice(k, 0, educationLevel); + } + } else { // pega o objeto de education level já existente + let k = 0; + let el = location.education_level[k]; + while(k < location.education_level.length) { + if(el.education_level_short_id != enrollmentEducationLevel.id) { + ++k; + if(k<location.education_level.length) el = location.education_level[k]; + } else break; + } + if(k >= location.education_level.length) --k; + educationLevel = location.education_level[k]; + } + + // Adiciona as séries da creche + let currentSchoolYear = null; + if(enrollmentEducationLevel.id == 1){ + let schoolYearHash = '' + enrollment.year + enrollment.city_id + enrollment.location_id + enrollment.school_year_id; + if (req.dims.shool) schoolYearHash = schoolYearHash + enrollment.shcool_id + + if(schoolYearSet.has(schoolYearHash)) { // Busca a série escolar + let k = 0; + let el = educationLevel.classes_school_year[k]; + while(k < educationLevel.classes_school_year.length) { + if(el.school_year_id != enrollment.school_year_id) { + ++k; + if(k < educationLevel.classes_school_year.length) el = educationLevel.classes_school_year[k]; + } else break; + } + if(k >= educationLevel.classes_school_year.length) --k; + currentSchoolYear = educationLevel.classes_school_year[k]; + } else { // Adiciona uma nova série escolar + let school_year = { + school_year_id: enrollment.school_year_id, + school_year_name: enrollment.school_year_name, + total_enrollment_day: 0, + total_enrollment_night: 0, + full_period_classes: 0, + day_classes: 0, + night_classes: 0, + total_classrooms_needed: 0 + } + schoolYearSet.add(schoolYearHash); + // Busca a posição para inserir + let k = 0; + let el = educationLevel.classes_school_year[k]; + while((typeof el !== 'undefined') && school_year.school_year_id > el.school_year_id) { + el = educationLevel.classes_school_year[++k]; + } + // educationLevel.classes_school_year.push(school_year); + educationLevel.classes_school_year.splice(k, 0, school_year); + currentSchoolYear = school_year; + } + } + + let currentIntegralOfferGoal = educationLevel.enrollment.integral_percentage; + + let currentNumberStudentClass = (enrollment.location_id == 1) ? enrollmentEducationLevel.numberStudentClass.urban : enrollmentEducationLevel.numberStudentClass.country; + + // Soma os totais de matrícula da etapa de ensino + educationLevel.enrollment.total_enrollment_day += enrollment.total_day; + educationLevel.enrollment.total_enrollment_night += (educationLevel.education_level_short_id > 2) ? enrollment.total_night : 0; //Não contamos matrículas noturnos de pré-escola e creche + + // Calcula o número de turmas parcial + // Turmas de período integral + educationLevel.enrollment.full_period_classes = parseFloat(((educationLevel.enrollment.total_enrollment_day * (currentIntegralOfferGoal/100)) / currentNumberStudentClass).toFixed(2)); + + // Turmas diurnas (matrículas diurnas - matrículas integrais) + educationLevel.enrollment.day_classes = parseFloat(((educationLevel.enrollment.total_enrollment_day * (1 - currentIntegralOfferGoal/100)) / currentNumberStudentClass).toFixed(2)); + + // Turmas noturnas + educationLevel.enrollment.night_classes = parseFloat((educationLevel.enrollment.total_enrollment_night / currentNumberStudentClass).toFixed(2)) || 0; + + // Total de salas + educationLevel.enrollment.total_classrooms_needed = (educationLevel.enrollment.full_period_classes + educationLevel.enrollment.day_classes/2); + + if(educationLevel.enrollment.night_classes > (educationLevel.enrollment.day_classes/2)) educationLevel.enrollment.total_classrooms_needed += (educationLevel.enrollment.night_classes - (educationLevel.enrollment.day_classes/2)); + + educationLevel.enrollment.total_classrooms_needed = parseFloat(educationLevel.enrollment.total_classrooms_needed.toFixed(2)); + + + let currentEnrollmentOfferDay; + let currentEnrollmentOfferNight; + if (req.projections) { + currentEnrollmentOfferDay = enrollmentProjectionDay[enrollment.location_id - 1].stagesEnrollments[educationLevel.education_level_short_id - 1]; + currentEnrollmentOfferNight = enrollmentProjectionNight[enrollment.location_id - 1].stagesEnrollments[educationLevel.education_level_short_id - 1]; + } + + // Faz os mesmos cálculos para a série escolar + if(currentSchoolYear) { + // Totais de matrícula + currentSchoolYear.total_enrollment_day += enrollment.total_day; + + // Número de turmas parcial + currentSchoolYear.full_period_classes = parseFloat(((currentSchoolYear.total_enrollment_day * (currentIntegralOfferGoal/100)) / currentNumberStudentClass).toFixed(2)); + + currentSchoolYear.day_classes = parseFloat(((currentSchoolYear.total_enrollment_day * (1 - currentIntegralOfferGoal/100)) / currentNumberStudentClass).toFixed(2)); + + + // Total de salas + currentSchoolYear.total_classrooms_needed = (currentSchoolYear.full_period_classes + currentSchoolYear.day_classes/2); + + currentSchoolYear.total_classrooms_needed = parseFloat(currentSchoolYear.total_classrooms_needed.toFixed(2)); + + function reducer(key) { return (sum, elem) => sum + elem[key]} + educationLevel.enrollment.total_enrollment_day = educationLevel.classes_school_year.reduce(reducer('total_enrollment_day'), 0); + educationLevel.enrollment.full_period_classes = educationLevel.classes_school_year.reduce(reducer('full_period_classes'), 0); + educationLevel.enrollment.day_classes = educationLevel.classes_school_year.reduce(reducer('day_classes'), 0); + educationLevel.enrollment.total_classrooms_needed = educationLevel.classes_school_year.reduce(reducer('total_classrooms_needed'), 0); + + } + + enrollment = enrollments[j]; + } + + // Calculamos o total classroom be built para o município usando reduce + location.total_classroom_be_built = location.education_level.reduce((total, atual) => { + return total + atual.enrollment.total_classrooms_needed; + }, 0) - location.total_classroom; + ++i; + } + + // Tratamento do último resultado, para remover double location, tirar negativo do to_be_built. + if (result[result.length - 1] !== undefined) { // Após mudar de cidade, passamos pela cidade anterior e juntamos o valor to_be_built de localizações com o mesmo id + let last_city = result[result.length - 1] + let last_locations = result[result.length - 1].locations + for (let i = 0; i < last_locations.length - 1; i++) { + if (last_locations[i].location_id === last_locations[i+1].location_id) { + last_locations[i].total_classroom_be_built += last_locations[i+1].total_classroom_be_built; + last_locations[i].total_classroom += last_locations[i+1].total_classroom; + last_locations.splice(i+1, 1); + } + } + for (let i = 0; i < last_locations.length; i++) { // Passamos agora para não deixar to_be_built < 0 + last_locations[i].total_classroom_be_built = (last_locations[i].total_classroom_be_built < 0) ? 0 : last_locations[i].total_classroom_be_built; + } + + if (req.teacherCalc) executeTeacherCalc(last_city, ti); + } + } + + // Agregar por estado e brasil + let reduction = null; + + if(req.dims.state || (!req.dims.city && !req.dims.school)) { // Se um dos dois acontecer, sabemos que devemos agregar + let i = 0; + reduction = []; + let reductionSet = new Set(); + while (i < result.length) { + let city = result[i]; + let obj = { + year: city.year, + name: city.name, + count: 1 + } + + if(req.dims.state) { + obj.state_id = city.state_id; + obj.state_name = city.state_name; + } + obj.percentage_teacher_career = [] + obj.locations = []; + + let hash = '' + city.year; + if(req.dims.state) hash += '' + city.state_id; + + let currentObj = null; + if(!reductionSet.has(hash)) { + reductionSet.add(hash); + reduction.push(obj); + currentObj = obj; + } else { // Está ordenado, podemos pegar o último + currentObj = reduction[reduction.length - 1]; + currentObj.count++; + } + + if (currentObj.count == 1) + currentObj.percentage_teacher_career = city.percentage_teacher_career + else { + // Incrementa valores percentuais de cada nivel de carreira no objeto atual + currentObj.percentage_teacher_career.forEach((item, ind, thisArr) => { + thisArr[ind].percentage += city.percentage_teacher_career[ind].percentage + }) + } + + // Fazer "merge" do array locations da cidade com o da agregação + if(currentObj.locations.length == 0) { + // Pode ser que a cidade atual tenha menos localidades que o total (só urbana ou só rural) + currentObj.locations = [...city.locations]; + if (currentObj.locations.length === 1) { // Se a cidade só tinha uma, adcionamos a outra manualmente. + currentObj.locations[1] = { + location_id: (currentObj.locations[0].location_id === 1) ? 2 : 1, // Oposto da adcionada + location_name: (currentObj.locations[0].location_id === 1) ? 'Rural' : 'Urbana', // Oposto da adcionada + total_classroom: 0, + total_classroom_be_built: 0, + education_level: [] + } + } + } else { + let j = 0; + let k = 0; + let cityLocation = null; + let currentLocation = null; + while((typeof cityLocation !== 'undefined') && (typeof currentLocation !== 'undefined')) { + cityLocation = city.locations[j]; + currentLocation = currentObj.locations[k]; + if(cityLocation.location_id < currentLocation.location_id) { + ++j; + cityLocation = city.locations[j]; + continue; + } else if(cityLocation.location_id > currentLocation.location_id) { + ++k; + currentLocation = currentObj.locations[k]; + continue; + } + + // Faz "merge" do array education_level + // Se a localidade atual não tem o vetor + if(currentLocation.education_level.length == 0) { + currentLocation.education_level = [...cityLocation.education_level]; + } else { // Caso já tenha, atualiza os valores + let l = 0; + while(l < cityLocation.education_level.length) { + let cityEducation = cityLocation.education_level[l]; + let m = 0; + let currentEducation = currentLocation.education_level[m]; + while(m < currentLocation.education_level.length && cityEducation.education_level_short_id > currentEducation.education_level_short_id) { + ++m; + currentEducation = currentLocation.education_level[m]; + } + if(m >= currentLocation.education_level.length) --m; + currentEducation = currentLocation.education_level[m]; + + if(currentEducation.education_level_short_id == cityEducation.education_level_short_id) { + currentEducation.enrollment.integral_time += cityEducation.enrollment.integral_time; + currentEducation.enrollment.integral_time_total += cityEducation.enrollment.integral_time_total; + currentEducation.enrollment.total_enrollment_day += cityEducation.enrollment.total_enrollment_day; + currentEducation.enrollment.total_enrollment_night += cityEducation.enrollment.total_enrollment_night; + currentEducation.enrollment.full_period_classes += cityEducation.enrollment.full_period_classes; + currentEducation.enrollment.day_classes += cityEducation.enrollment.day_classes; + currentEducation.enrollment.night_classes += cityEducation.enrollment.night_classes; + currentEducation.enrollment.total_classrooms_needed += cityEducation.enrollment.total_classrooms_needed; + + // Caso tenha feito o cálculo de professores, atualiza os valores + if (req.teacherCalc) { + currentEducation.teacherNumber.total_teacher += cityEducation.teacherNumber.total_teacher; + currentEducation.teacherNumber.total_teacher_full_period += cityEducation.teacherNumber.total_teacher_full_period; + currentEducation.teacherNumber.total_teacher_partial += cityEducation.teacherNumber.total_teacher_partial; + + currentEducation.teacherNumber.careerLevels.forEach((currentLevel, i) => { + currentLevel.total_teacher_career += cityEducation.teacherNumber.careerLevels[i].total_teacher_career; + currentLevel.total_teacher_full_period_career += cityEducation.teacherNumber.careerLevels[i].total_teacher_full_period_career; + currentLevel.total_teacher_partial_career += cityEducation.teacherNumber.careerLevels[i].total_teacher_partial_career; + }) + } + + // Insere as séries escolares, se existirem + if((typeof cityEducation.classes_school_year !== 'undefined') && (typeof currentEducation.classes_school_year !== 'undefined')) { + let n = 0; + let o = 0; + let currentClass = currentEducation.classes_school_year[n]; + let cityClass = cityEducation.classes_school_year[o]; + while((typeof cityClass !== 'undefined') && (typeof currentClass !== 'undefined')) { + currentClass = currentEducation.classes_school_year[n]; + cityClass = cityEducation.classes_school_year[o]; + + // Se a série escolar é menor que a atual, ela não está no vetor, pois o vetor está ordenado e tem range limitado + if(cityClass.school_year_id < currentClass.school_year_id) { + currentEducation.classes_school_year.splice(n, 0, cityClass); + currentClass = currentEducation.classes_school_year[n]; + cityClass = cityEducation.classes_school_year[++o]; + continue; + } else if(cityClass.school_year_id > currentClass.school_year_id) { + currentClass = currentEducation.classes_school_year[++n]; + // Se o ano escolar da cidade é maior que do objeto atual E o vetor de ano escolar do objeto atual + // acaba, então este ano escolar falta no objeto atual, pois os anos escolares estão ordenados + if((typeof currentClass == 'undefined') && (typeof cityClass !== 'undefined')) { + currentEducation.classes_school_year[n] = cityClass; + currentClass = currentEducation.classes_school_year[n]; + } + continue; + } + + currentClass.total_enrollment_day += cityClass.total_enrollment_day; + currentClass.total_enrollment_night += cityClass.total_enrollment_night; + currentClass.full_period_classes += cityClass.full_period_classes; + currentClass.day_classes += cityClass.day_classes; + currentClass.night_classes += cityClass.night_classes; + currentClass.total_classrooms_needed += cityClass.total_classrooms_needed; + + // Caso tenha feito o cálculo de professores, atualiza os valores + if (req.teacherCalc) { + currentClass.teacherNumber.total_teacher += cityClass.teacherNumber.total_teacher; + currentClass.teacherNumber.total_teacher_full_period += cityClass.teacherNumber.total_teacher_full_period; + currentClass.teacherNumber.total_teacher_partial += cityClass.teacherNumber.total_teacher_partial; + + // currentClass.teacherNumber.careerLevels.forEach((currentLevel, i) => { + // currentLevel.total_teacher_career += cityClass.teacherNumber.careerLevels[i].total_teacher_career; + // currentLevel.total_teacher_full_period_career += cityClass.teacherNumber.careerLevels[i].total_teacher_full_period_career; + // currentLevel.total_teacher_partial_career += cityClass.teacherNumber.careerLevels[i].total_teacher_partial_career; + // }) + } + + cityClass = cityEducation.classes_school_year[++o]; + } + + } + } else { + if(currentEducation.education_level_short_id < cityEducation.education_level_short_id) { + currentLocation.education_level.splice(++m, 0, cityEducation); + } else { + currentLocation.education_level.splice(m, 0, cityEducation); + } + } + ++l; + } + } + // Reinicia vetor percentage_teacher_career e calcula porcentagens pelos totais + + currentLocation.total_classroom += cityLocation.total_classroom; + currentLocation.total_classroom_be_built += cityLocation.total_classroom_be_built; + + ++j; + cityLocation = city.locations[j]; + } + } + ++i; + } + for (let state of reduction){ + state.percentage_teacher_career.forEach((item, ind, thisArr) => { + thisArr[ind].percentage = Number((thisArr[ind].percentage / state.count).toFixed(2)) + }) + delete state.count + for (let location of state.locations){ + for (let educationLevel of location.education_level){ + let total = educationLevel.enrollment.integral_time_total; + let integralTime = educationLevel.enrollment.integral_time; + educationLevel.enrollment.integral_percentage = total ? parseFloat( (100*(integralTime / total)).toFixed(2) ) : 0 + } + } + } + } + + req.result = reduction || result; + + + function executeTeacherCalc(lastCity, index) { + let lastLocations = lastCity.locations + let teacherByFormation = []; // Vetor com a porcentagem de professores por formação. + let teacherTotal = req.teacher[index].total; + + let i = index + 1; + for (let j of [2, 4, 6, 7, 8]) { // Calcula a porcentagem de professores por formação. + if (req.teacher[i] === undefined || j !== req.teacher[i].formation_level) { // Nesse caso a cidade não possuí professores com a formação atual, adcionamos 0. + teacherByFormation.push(0); + } + else { + teacherByFormation.push(parseFloat((req.teacher[i].total / teacherTotal).toFixed(3))); + i++; + } + } + + // verifica se a soma de porcentagens vale 100. + let sum = 0; + for (let value of teacherByFormation) { + sum += value; + } + teacherByFormation[1] += teacherByFormation[0] + teacherByFormation[0] = 0 + + let diff = 1 - sum; + + // Se soma de porcentagens for menor/maior que 100, faz correção + if (Math.abs(diff) > 0.0001) { + // Garante que a porcentagem corrigida não ficará negativa + let indDiff = 1; + while (teacherByFormation[indDiff] + diff < 0) indDiff++; + teacherByFormation[indDiff] += diff; + } + + // Cria vetor de porcentagens de carreira dos professores + req.teacherFormation.forEach((formation, i) => { + lastCity.percentage_teacher_career.push({ + formation_level_id: formation.idFormationLevel, + percentage: Number((teacherByFormation[i]*100).toFixed(2)), + }) + }); + + lastLocations.forEach((location) => { + location.education_level.forEach((educationLevel) => { + let educationLevelId = educationLevel.education_level_short_id; + + let currentTeachingHours = req.teachingHours[educationLevelId-1].shifts; + + if(educationLevelId === 1) { // Devido a divisão da creche é necessário tratá-la separadamente. + educationLevel.classes_school_year.forEach((schoolYear) => { // Aplicamos os cálculos para os anos da creche + let teachingTimeFullPeriod = schoolYear.full_period_classes * currentTeachingHours[2].value * req.schoolDays[educationLevelId-1].value; + let teachingTimeNight = schoolYear.night_classes * currentTeachingHours[1].value * req.schoolDays[educationLevelId-1].value; + let teachingTimeDay = schoolYear.day_classes * currentTeachingHours[0].value * req.schoolDays[educationLevelId-1].value; + + let currentTeacherByClass = (location.location_id === 1) ? req.educationSchoolYear[schoolYear.school_year_id].teacherByClass.urban : req.educationSchoolYear[schoolYear.school_year_id].teacherByClass.country; + + let numberOfTeacherFullPeriod = 0; + let numberOfTeacherNight = 0; + let numberOfTeacherDay = 0; + lastCity.percentage_teacher_career.forEach(career => { + let journeyObj = req.teacherFormation.find(formation => formation.idFormationLevel === career.formation_level_id) + let journey = journeyObj.journeyWithInteraction/100 * journeyObj.journeyTotal; + numberOfTeacherFullPeriod += (teachingTimeFullPeriod / journey) * currentTeacherByClass * career.percentage/100; + numberOfTeacherNight += (teachingTimeNight / journey) * currentTeacherByClass * career.percentage/100; + numberOfTeacherDay += (teachingTimeDay / journey) * currentTeacherByClass * career.percentage/100; + }) + numberOfTeacherFullPeriod = parseFloat(numberOfTeacherFullPeriod.toFixed(2)); + numberOfTeacherNight = parseFloat(numberOfTeacherNight.toFixed(2)); + numberOfTeacherDay = parseFloat(numberOfTeacherDay.toFixed(2)); + + schoolYear.teacherNumber = { + total_teacher : numberOfTeacherDay + numberOfTeacherNight + numberOfTeacherFullPeriod, + total_teacher_full_period : numberOfTeacherFullPeriod, + total_teacher_partial : numberOfTeacherNight + numberOfTeacherDay + } + }) + + // Calculamos para o educationLevel usando reduce + function reducer(key) { return (sum, elem) => sum + elem.teacherNumber[key]} + educationLevel.teacherNumber = { + total_teacher : educationLevel.classes_school_year.reduce(reducer('total_teacher'), 0), + total_teacher_full_period : educationLevel.classes_school_year.reduce(reducer('total_teacher_full_period'), 0), + total_teacher_partial : educationLevel.classes_school_year.reduce(reducer('total_teacher_partial'), 0) + } + + // function reducerList(idx, key) { return (sum, elem) => sum + elem.teacherNumber.careerLevels[idx][key]} + educationLevel.teacherNumber.careerLevels = []; + req.teacherFormation.forEach((formation, i) => { + let totalTeacherFullPeriodCareer = educationLevel.teacherNumber.total_teacher_full_period * teacherByFormation[i]; + let totalTeacherPartialCareer = educationLevel.teacherNumber.total_teacher_partial * teacherByFormation[i]; + + educationLevel.teacherNumber.careerLevels.push({ + sequence: formation.sequence, + denomination: formation.denomination, + formation_level_id: formation.idFormationLevel, + total_teacher_career: totalTeacherFullPeriodCareer + totalTeacherPartialCareer, + total_teacher_full_period_career: totalTeacherFullPeriodCareer, + total_teacher_partial_career:totalTeacherPartialCareer, + }) + }) + } + + else { + + let ed_level = educationLevel.education_level_short_id; + let minimun_enrollment = minimunEnrollment(ed_level); + let minimun_classes = minimunClasses(ed_level); + let partial_day_enrollment = educationLevel.enrollment.total_enrollment_day - educationLevel.enrollment.integral_time; + + + // Matrículas diurnas + if (partial_day_enrollment >= minimun_enrollment) { + if (educationLevel.enrollment.day_classes < minimun_classes) { + educationLevel.enrollment.day_classes = minimun_classes; + } + } + // Matrículas integrais + if (educationLevel.enrollment.integral_time >= minimun_enrollment) { + if (educationLevel.enrollment.full_period_classes < minimun_classes) { + educationLevel.enrollment.full_period_classes = minimun_classes; + } + } + // Matrículas noturnas + if (educationLevel.enrollment.total_enrollment_night >= minimun_enrollment) { + if (educationLevel.enrollment.night_classes < minimun_classes) { + educationLevel.enrollment.night_classes = minimun_classes; + } + } + + let teachingTimeFullPeriod = educationLevel.enrollment.full_period_classes * currentTeachingHours[2].value * req.schoolDays[educationLevelId-1].value; + let teachingTimeNight = educationLevel.enrollment.night_classes * currentTeachingHours[1].value * req.schoolDays[educationLevelId-1].value; + let teachingTimeDay = educationLevel.enrollment.day_classes * currentTeachingHours[0].value * req.schoolDays[educationLevelId-1].value; + + let currentTeacherByClass = (location.location_id === 1) ? req.educationSchoolYear[educationLevelId].teacherByClass.urban : req.educationSchoolYear[educationLevelId].teacherByClass.country; + + let numberOfTeacherFullPeriod = 0; + let numberOfTeacherNight = 0; + let numberOfTeacherDay = 0; + lastCity.percentage_teacher_career.forEach(career => { + let journeyObj = req.teacherFormation.find(formation => formation.idFormationLevel === career.formation_level_id) + let journey = journeyObj.journeyWithInteraction/100 * journeyObj.journeyTotal; + numberOfTeacherFullPeriod += (teachingTimeFullPeriod / journey) * currentTeacherByClass * career.percentage/100; + numberOfTeacherNight += (teachingTimeNight / journey) * currentTeacherByClass * career.percentage/100; + numberOfTeacherDay += (teachingTimeDay / journey) * currentTeacherByClass * career.percentage/100; + }) + numberOfTeacherFullPeriod = parseFloat(numberOfTeacherFullPeriod.toFixed(2)); + numberOfTeacherNight = parseFloat(numberOfTeacherNight.toFixed(2)); + numberOfTeacherDay = parseFloat(numberOfTeacherDay.toFixed(2)); + + educationLevel.teacherNumber = { + total_teacher : numberOfTeacherDay + numberOfTeacherNight + numberOfTeacherFullPeriod, + total_teacher_full_period : numberOfTeacherFullPeriod, + total_teacher_partial : numberOfTeacherNight + numberOfTeacherDay + } + + educationLevel.teacherNumber.careerLevels = []; + req.teacherFormation.forEach((formation, i) => { + if (educationLevel.teacherNumber.total_teacher < 1) { + educationLevel.teacherNumber.total_teacher_full_period = 1; + educationLevel.teacherNumber.total_teacher_partial = 1; + } + + let totalTeacherFullPeriodCareer = educationLevel.teacherNumber.total_teacher_full_period * teacherByFormation[i]; + let totalTeacherPartialCareer = educationLevel.teacherNumber.total_teacher_partial * teacherByFormation[i]; + + educationLevel.teacherNumber.careerLevels.push({ + sequence: formation.sequence, + denomination: formation.denomination, + formation_level_id: formation.idFormationLevel, + total_teacher_career: totalTeacherFullPeriodCareer + totalTeacherPartialCareer, + total_teacher_full_period_career: totalTeacherFullPeriodCareer, + total_teacher_partial_career:totalTeacherPartialCareer, + }) + }) + + } + }) + }) + } + + next(); +}, response('classroom_count')); + +module.exports = classroomCountApp; + diff --git a/src/libs/routes/courseCount.js b/src/libs/routes_v1/courseCount.js similarity index 100% rename from src/libs/routes/courseCount.js rename to src/libs/routes_v1/courseCount.js diff --git a/src/libs/routes/courseStudents.js b/src/libs/routes_v1/courseStudents.js similarity index 100% rename from src/libs/routes/courseStudents.js rename to src/libs/routes_v1/courseStudents.js diff --git a/src/libs/routes/cub.js b/src/libs/routes_v1/cub.js similarity index 100% rename from src/libs/routes/cub.js rename to src/libs/routes_v1/cub.js diff --git a/src/libs/routes/dailyChargeAmount.js b/src/libs/routes_v1/dailyChargeAmount.js similarity index 100% rename from src/libs/routes/dailyChargeAmount.js rename to src/libs/routes_v1/dailyChargeAmount.js diff --git a/src/libs/routes/disciplines.js b/src/libs/routes_v1/disciplines.js similarity index 100% rename from src/libs/routes/disciplines.js rename to src/libs/routes_v1/disciplines.js diff --git a/src/libs/routes/distributionFactor.js b/src/libs/routes_v1/distributionFactor.js similarity index 100% rename from src/libs/routes/distributionFactor.js rename to src/libs/routes_v1/distributionFactor.js diff --git a/src/libs/routes_v1/downloads.js b/src/libs/routes_v1/downloads.js new file mode 100644 index 0000000000000000000000000000000000000000..cd6cad0b127ce0186ba204aab70b9e5638b57813 --- /dev/null +++ b/src/libs/routes_v1/downloads.js @@ -0,0 +1,51 @@ +const express = require('express'); + +const downloadApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const Download = require(`${libs}/models/download`); + +const passport = require('passport'); + +const request = require(`request`); + +const config = require(`${libs}/config`); + +downloadApp.get('/', passport.authenticate('bearer', { session: false }), (req, res, next) => { + request.get(config.cdn.url + '/api/v1/file', async (err, response, body) => { + let cdn = JSON.parse(body); + const downloads = await Download.findAll({ where: { user_id: req.user.id } }).catch(function (err) { + if (err) { + log.error(err); + return next(err); + } + }); + if (!downloads) { + res.statusCode = 404; + return res.json({ msg: 'Nenhum download encontrado' }); + } else { + downloads.forEach((dl) => { + for (let i = 0; i < cdn.length; ++i) { + if (cdn[i].query == dl.query) { + dl.status = cdn[i].expired ? 'Expirado' : 'Enviado'; + dl.size = cdn[i].size; + dl.expired = cdn[i].expired; + dl.updatedAt = cdn[i].lastAccess; + dl.link = config.cdn.download + '/' + cdn[i]._id; + + dl.save((err) => { + if (err) log.error(err); + }); + return; + } + } + }); + } + res.json(downloads); + }); +}); + +module.exports = downloadApp; diff --git a/src/libs/routes/educationYears.js b/src/libs/routes_v1/educationYears.js similarity index 100% rename from src/libs/routes/educationYears.js rename to src/libs/routes_v1/educationYears.js diff --git a/src/libs/routes/educationalBudget.js b/src/libs/routes_v1/educationalBudget.js similarity index 100% rename from src/libs/routes/educationalBudget.js rename to src/libs/routes_v1/educationalBudget.js diff --git a/src/libs/routes/employees.js b/src/libs/routes_v1/employees.js similarity index 100% rename from src/libs/routes/employees.js rename to src/libs/routes_v1/employees.js diff --git a/src/libs/routes/enrollment.js b/src/libs/routes_v1/enrollment.js similarity index 100% rename from src/libs/routes/enrollment.js rename to src/libs/routes_v1/enrollment.js diff --git a/src/libs/routes/enrollmentProjection.js b/src/libs/routes_v1/enrollmentProjection.js similarity index 100% rename from src/libs/routes/enrollmentProjection.js rename to src/libs/routes_v1/enrollmentProjection.js diff --git a/src/libs/routes_v1/file.controller.js b/src/libs/routes_v1/file.controller.js new file mode 100644 index 0000000000000000000000000000000000000000..06464342676c391e309e061ace568b4390e3515b --- /dev/null +++ b/src/libs/routes_v1/file.controller.js @@ -0,0 +1,41 @@ +var stream = require('stream'); +const libs = `${process.cwd()}/libs`; +const File = require(`${libs}/models/file`); + +exports.uploadFile = async (_file) => { + let file = await File.create({ + id: 0, + type: _file.mimetype, + name: _file.originalname, + data: _file.buffer + }).catch(err => { + console.log(err); + res.json({msg: 'Error', detail: err}); + }); + return file.id; +} + +exports.listAllFiles = (req, res) => { + File.findAll({attributes: ['id', 'name']}).then(files => { + res.json(files); + }).catch(err => { + console.log(err); + res.json({msg: 'Error', detail: err}); + }); +} + +exports.downloadFile = (req, res) => { + File.findByPk(req.params.id).then(file => { + var fileContents = Buffer.from(file.data, "base64"); + var readStream = new stream.PassThrough(); + readStream.end(fileContents); + + res.set('Content-disposition', 'attachment; filename=' + file.name); + res.set('Content-Type', file.type); + + readStream.pipe(res); + }).catch(err => { + console.log(err); + res.json({msg: 'Error', detail: err}); + }); +} diff --git a/src/libs/routes/financial.js b/src/libs/routes_v1/financial.js similarity index 100% rename from src/libs/routes/financial.js rename to src/libs/routes_v1/financial.js diff --git a/src/libs/routes/glossEnrollmentRatio.js b/src/libs/routes_v1/glossEnrollmentRatio.js similarity index 100% rename from src/libs/routes/glossEnrollmentRatio.js rename to src/libs/routes_v1/glossEnrollmentRatio.js diff --git a/src/libs/routes/idhm.js b/src/libs/routes_v1/idhm.js similarity index 100% rename from src/libs/routes/idhm.js rename to src/libs/routes_v1/idhm.js diff --git a/src/libs/routes/idhme.js b/src/libs/routes_v1/idhme.js similarity index 100% rename from src/libs/routes/idhme.js rename to src/libs/routes_v1/idhme.js diff --git a/src/libs/routes/idhml.js b/src/libs/routes_v1/idhml.js similarity index 100% rename from src/libs/routes/idhml.js rename to src/libs/routes_v1/idhml.js diff --git a/src/libs/routes/idhmr.js b/src/libs/routes_v1/idhmr.js similarity index 100% rename from src/libs/routes/idhmr.js rename to src/libs/routes_v1/idhmr.js diff --git a/src/libs/routes/infrastructure.js b/src/libs/routes_v1/infrastructure.js similarity index 100% rename from src/libs/routes/infrastructure.js rename to src/libs/routes_v1/infrastructure.js diff --git a/src/libs/routes/liquidEnrollmentRatio.js b/src/libs/routes_v1/liquidEnrollmentRatio.js similarity index 100% rename from src/libs/routes/liquidEnrollmentRatio.js rename to src/libs/routes_v1/liquidEnrollmentRatio.js diff --git a/src/libs/routes/location.js b/src/libs/routes_v1/location.js similarity index 100% rename from src/libs/routes/location.js rename to src/libs/routes_v1/location.js diff --git a/src/libs/routes/mesoregion.js b/src/libs/routes_v1/mesoregion.js similarity index 100% rename from src/libs/routes/mesoregion.js rename to src/libs/routes_v1/mesoregion.js diff --git a/src/libs/routes/message.js b/src/libs/routes_v1/message.js similarity index 100% rename from src/libs/routes/message.js rename to src/libs/routes_v1/message.js diff --git a/src/libs/routes/microregion.js b/src/libs/routes_v1/microregion.js similarity index 100% rename from src/libs/routes/microregion.js rename to src/libs/routes_v1/microregion.js diff --git a/src/libs/routes/outOfSchool.js b/src/libs/routes_v1/outOfSchool.js similarity index 100% rename from src/libs/routes/outOfSchool.js rename to src/libs/routes_v1/outOfSchool.js diff --git a/src/libs/routes/pibpercapita.js b/src/libs/routes_v1/pibpercapita.js similarity index 100% rename from src/libs/routes/pibpercapita.js rename to src/libs/routes_v1/pibpercapita.js diff --git a/src/libs/routes/population.js b/src/libs/routes_v1/population.js similarity index 100% rename from src/libs/routes/population.js rename to src/libs/routes_v1/population.js diff --git a/src/libs/routes/portalMec.js b/src/libs/routes_v1/portalMec.js similarity index 100% rename from src/libs/routes/portalMec.js rename to src/libs/routes_v1/portalMec.js diff --git a/src/libs/routes/portalMecInep.js b/src/libs/routes_v1/portalMecInep.js similarity index 100% rename from src/libs/routes/portalMecInep.js rename to src/libs/routes_v1/portalMecInep.js diff --git a/src/libs/routes_v1/publication.js b/src/libs/routes_v1/publication.js new file mode 100644 index 0000000000000000000000000000000000000000..45afc9cd4d57f727d91624465594a1826d084423 --- /dev/null +++ b/src/libs/routes_v1/publication.js @@ -0,0 +1,208 @@ +const express = require('express'); + +const pubApp = express(); + +const libs = `${process.cwd()}/libs`; + +const config = require(`${libs}/config`); + +const log = require(`${libs}/log`)(module); + +const Publication = require(`${libs}/models/publication`); + +const File = require(`${libs}/models/file`); + +const response = require(`${libs}/middlewares/response`); + +const email = require(`${libs}/middlewares/email`); + +const passport = require('passport'); + +const fileWorker = require('./file.controller.js'); + +let upload = require('../middlewares/multer.config.js'); + +const authorized = require(`${libs}/middlewares/authorize.js`); + +function emailSyntax(email) { + const regex = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; + return regex.test(email); +} + +pubApp.get('/', async (req, res, next) => { + const page = parseInt(req.query.page) || 1; // Current page number + const pageSize = parseInt(req.query.pageSize) || 5; // Number of items per page + try { + const totalCount = await Publication.count(); + const offset = (page - 1) * pageSize; + + const publis = await Publication.findAll({ + offset, + limit: pageSize, + }); + + res.json({ + page, + pageSize, + totalCount, + data: publis, + }); + } catch (error) { + console.error(error); + res.status(500).json({ error: 'An error occurred' }); + } +}); + +pubApp.get('/drafts', async (req, res, next) => { + const page = parseInt(req.query.page) || 1; // Current page number + const pageSize = parseInt(req.query.pageSize) || 5; // Number of items per page + + try { + // Count total number of items + const totalCount = await Publication.count({ where: { + is_draft: true + }}); + + // Calculate offset based on page and pageSize + const offset = (page - 1) * pageSize; + + // Query the database with pagination options + const drafts = await Publication.findAll({ + offset, + limit: pageSize, + where: { + is_draft: true + } + }); + + res.json({ + page, + pageSize, + totalCount, + data: drafts, + }); + } catch (error) { + console.error(error); + res.status(500).json({ error: 'An error occurred' }); + } +}); + + +pubApp.get('/:id', async (req, res, next) => { + let pb = await Publication.findByPk(req.params.id).catch(function (err) { + log.error(err); + return next(err);} + ); + if (!pb) { + res.statusCode = 404; + res.json({ msg: "A publicação não está cadastrada" }); + } + else { + let publ = pb.toJSON(); + publ.Filename = null; + const file_ = await File.findByPk(pb.upload).catch((err) => { + log.error(err); + return next(err); + }); + if(file_){ + publ.Filename = file_.name; + } + req.result = publ; + next(); + } + }, response('publication')); + +pubApp.post('/', passport.authenticate('bearer', { session: false }), authorized('criar publicacao'), upload.single('file'), async (req, res, next) => { + let _file_id = null + if(req.file){ + _file_id = await fileWorker.uploadFile(req.file); + if(!_file_id) + console.log("NAO ARQUIVO");} + let data = JSON.parse(req.body.data); + let pb = await Publication.create({ + id: 0, + filter: data.categoria, + title: data.title, + authors: data.autores, + organization: data.organizacao, + year: data.ano, + text: data.texto, + link: data.link, + upload: _file_id, + is_draft: data.rascunho, + is_homepage: data.homepage + }).catch(function (err) { + log.error(err); + let errors = []; + for (let errName in err.errors) { + errors.push(err.errors[errName].message); + } + log.error(errors); + res.statusCode = 400; + return res.json({ err, errors }); + // handle error; + }); + req.result = pb.toJSON(); + next(); +}, response('publication')); + +pubApp.post('/edit', passport.authenticate('bearer', { session: false }), authorized('editar publicacao'), upload.single('file'), async (req, res, next) => { + let _file_id = null + if(req.file){ + _file_id = await fileWorker.uploadFile(req.file); + if(!_file_id) + console.log("NAO ARQUIVO");} + let data = JSON.parse(req.body.data); + console.log(data); + req.response = {'This is a test':'This is a test'}; + next(); +}, response('publication')); + +pubApp.put('/edit/:id', passport.authenticate('bearer', { session: false }), authorized('editar publicacao'), async (req, res, next) => { + console.log(req); + let pb = await Publication.findByPk(req.params.id).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }) + if (!pb) { + res.statusCode = 404; + return next({ + err: { + message: 'Publicação não encontrada' + } + }); + } + pb.filter = req.body.categoria || pb.filter; + pb.title = req.body.title || pb.title; + pb.authors = req.body.autores || pb.authors; + pb.organization= req.body.organizacao || pb.organization; + pb.year= req.body.ano || pb.year; + pb.text= req.body.texto || pb.text; + pb.link= req.body.link || pb.link; + pb.upload= req.body.upload || pb.upload; + pb.is_homepage= req.body.homepage || pb.is_homepage; + console.log(pb); + pb.save().catch(err => { + if (err) { + log.error(err); + return next({ message: 'Erro ao atualizar publicacao' }); + } + }) + let p = pb.toJSON(); + res.json({ publication: p }); + +}); + +pubApp.delete('/:id', passport.authenticate('bearer', { session: false }), authorized('apagar publicacao'), async (req, res, next) => { + await Publication.destroy({where:{id:req.params.id}}).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } +}); + return next({ msg: 'Publication Deleted', status: 200 }); +}); + +module.exports = pubApp; diff --git a/src/libs/routes/rateSchool.js b/src/libs/routes_v1/rateSchool.js similarity index 100% rename from src/libs/routes/rateSchool.js rename to src/libs/routes_v1/rateSchool.js diff --git a/src/libs/routes/region.js b/src/libs/routes_v1/region.js similarity index 100% rename from src/libs/routes/region.js rename to src/libs/routes_v1/region.js diff --git a/src/libs/routes_v1/resetToken.js b/src/libs/routes_v1/resetToken.js new file mode 100644 index 0000000000000000000000000000000000000000..a3813ab9dea0de24d7ee83557b358c1ce7a40155 --- /dev/null +++ b/src/libs/routes_v1/resetToken.js @@ -0,0 +1,82 @@ +const express = require('express'); + +const resetTokenApp = express(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const ResetToken = require(`${libs}/models/resetToken`); + +const User = require(`${libs}/models/user`); + +resetTokenApp.get('/:token', async (req, res, next) => { + let token = req.params.token; + let rToken = await ResetToken.findOne({where:{ token: token} }).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }); + console.log(rToken); + if (!rToken) { + res.statusCode = 401; + return next({ msg: 'Token not found', status: 401 }); + } + if (rToken.hasExpired()) { + res.statusCode = 410; + await ResetToken.destroy({where:{ token: token}}).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }) + return next({ msg: 'Token expired', status: 410 }); + } + let _user = await User.findByPk(rToken.user_id).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }) + let u = _user.toJSON(); + delete u.salt; + delete u.hashed_password; + res.json({ user: u }); +}); + +resetTokenApp.post('/:token', async (req, res, next) => { + let token = req.params.token; + let rToken = await ResetToken.findOne({where:{ token: token}}).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }) + if (!rToken) { + res.statusCode = 404; + return next({ msg: 'Token not found', status: 404 }); + } + let _user = await User.findByPk(rToken.user_id).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }) + await _user.update({password:req.body.password}); + _user.save().catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }) + await ResetToken.destroy({where:{token: token} }).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }) + res.json({ msg: "Senha alterada com sucesso" }); +}); + +module.exports = resetTokenApp; diff --git a/src/libs/routes/school.js b/src/libs/routes_v1/school.js similarity index 97% rename from src/libs/routes/school.js rename to src/libs/routes_v1/school.js index 172361c16aa1c2801f288e7cbd8c73a59ecaa72f..768325c314d7c6e9bdd0059bd8a420880ebdf83a 100644 --- a/src/libs/routes/school.js +++ b/src/libs/routes_v1/school.js @@ -281,6 +281,16 @@ rqf.addField({ type: 'integer', field: 'ano_censo' } +}).addValue({ + name: 'adm_dependency', + table: 'escola', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } }).addField({ name: 'search', field: true, @@ -328,6 +338,16 @@ rqf.addField({ type: 'integer', field: 'localizacao_diferenciada_par' } +}).addValue({ + name: 'adm_dependency', + table: 'escola', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } }); rqfCount.addField({ diff --git a/src/libs/routes/schoolInfrastructure.js b/src/libs/routes_v1/schoolInfrastructure.js similarity index 100% rename from src/libs/routes/schoolInfrastructure.js rename to src/libs/routes_v1/schoolInfrastructure.js diff --git a/src/libs/routes/schoolLocation.js b/src/libs/routes_v1/schoolLocation.js similarity index 100% rename from src/libs/routes/schoolLocation.js rename to src/libs/routes_v1/schoolLocation.js diff --git a/src/libs/routes_v1/simulation.js b/src/libs/routes_v1/simulation.js new file mode 100644 index 0000000000000000000000000000000000000000..cc0ab38025dc0a9b2c39c4ebaa3f8a962d178525 --- /dev/null +++ b/src/libs/routes_v1/simulation.js @@ -0,0 +1,161 @@ +const express = require('express'); + +const simulationApp = express(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const Simulation = require(`${libs}/models/simulation`); + +const PQR = require(`${libs}/models/pqr`); + +const passport = require('passport'); + +simulationApp.get('/time', (req, res, next) => { + const maxTime = parseInt(req.query.max_time, 10); + if (isNaN(maxTime)) { + res.status(400); + next({ + status: 400, + message: 'Invalid value for mandatory parameter max_time' + }); + } + res.json({ + result: Array.apply(null, { length: maxTime }).map(Number.call, Number).map((i) => i + 1) + }); +}); + +simulationApp.get('/pqr', async (req, res) => { + let pqr = await PQR.findOne({ attributes: ['content'] }).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }); + if (pqr) + res.json(pqr); +}); + +simulationApp.put('/pqr', passport.authenticate('bearer', { session: false }), async (req, res, next) => { + let user = req.user; + let pqr = await PQR.findOne().catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }); + if (!user.admin) { + log.info(`Usuário ${user.email} tentou alterar o PQR, mas não tem privilégio`); + res.statusCode = 401; + return next({ err: { msg: 'Unauthorized' } }); + } + + if(pqr){ + let _content = req.body.content || pqr.content; + pqr.content = _content; + await pqr.save({fields:['content']}).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + });} + + res.json({ msg: 'PQR updated' }) + +}); + +simulationApp.get('/', passport.authenticate('bearer', { session: false }), async (req, res) => { + let user = req.user; + let simulations = await Simulation.findAll({ where: { user_id: user.id } }, { attributes: ['user_id', 'name', 'created_at', 'updated_at'] }).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }) + if (!simulations){ + res.json("Simulations not found"); + } + res.json(simulations); + + // Simulation.find({userId: user._id}, (err, simulations) => { + // if(err) { + // log.error(err); + // return next({err}); + // } + + // res.json(simulations); + // }); +}); + +simulationApp.post('/', passport.authenticate('bearer', { session: false }), async (req, res, next) => { + let user = req.user; + + let simulation = await Simulation.create({ + user_id: user.id, + content: req.body.content, + name: req.body.name + }); + + await simulation.save().catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }); + + res.json({ msg: 'Simulation created', simulation }); +}) + +simulationApp.get('/:id', passport.authenticate('bearer', { session: false }), async (req, res) => { + let user = req.user; + + let simulation = await Simulation.findOne({where:{id: req.params.id, user_id: user.id }}).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }); + res.json(simulation); + +}); + +simulationApp.put('/:id', passport.authenticate('bearer', { session: false }), async (req, res, next) => { + let user = req.user; + + let simulation = await Simulation.findOne({ where: { id: req.params.id, user_id: user.id } }).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }); + + if (!simulation) { + res.statusCode = 404; + return next({ err: { msg: 'Simulation not found' } }); + } + + simulation.content = req.body.content || simulation.content; + simulation.name = req.body.name || simulation.name; + simulation.updated_at = new Date(); + await simulation.save({fields:['content','name','updated_at']}).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }); + res.json({ msg: 'Simulation created', simulation }); +}); + +simulationApp.delete('/:id', passport.authenticate('bearer', { session: false }), async (req, res, next) => { + let user = req.user; + await Simulation.destroy({where: { "id": req.params.id, "user_id": user.id } }).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }); + res.json({ msg: 'Simulation removed' }); +}); + +module.exports = simulationApp; diff --git a/src/libs/routes/siope.js b/src/libs/routes_v1/siope.js similarity index 100% rename from src/libs/routes/siope.js rename to src/libs/routes_v1/siope.js diff --git a/src/libs/routes/spatial.js b/src/libs/routes_v1/spatial.js similarity index 100% rename from src/libs/routes/spatial.js rename to src/libs/routes_v1/spatial.js diff --git a/src/libs/routes/state.js b/src/libs/routes_v1/state.js similarity index 100% rename from src/libs/routes/state.js rename to src/libs/routes_v1/state.js diff --git a/src/libs/routes/studentsAee.js b/src/libs/routes_v1/studentsAee.js similarity index 100% rename from src/libs/routes/studentsAee.js rename to src/libs/routes_v1/studentsAee.js diff --git a/src/libs/routes/teacher.js b/src/libs/routes_v1/teacher.js similarity index 100% rename from src/libs/routes/teacher.js rename to src/libs/routes_v1/teacher.js diff --git a/src/libs/routes_v1/test.js b/src/libs/routes_v1/test.js new file mode 100644 index 0000000000000000000000000000000000000000..9e8482dcf3bbdcb52faf269d9a7e7f57d37069cf --- /dev/null +++ b/src/libs/routes_v1/test.js @@ -0,0 +1,100 @@ +const express = require('express'); +const oauth2orize = require('oauth2orize'); +const passport = require('passport'); +const ClientPasswordStrategy = require('passport-oauth2-client-password'); +const testApp = express(); +const libs = `${process.cwd()}/libs`; + +const Client = require(`${libs}/models/client`); +const User = require(`${libs}/models/user`) +var server = oauth2orize.createServer(); + +passport.use(new ClientPasswordStrategy( + function(client_id, client_secret, done) { + Client.findOne({where: {client_id: client_id} + }).then(function(err, client) { + if(err){ + console.log("Erro de requisicao"); + return done(err); + } + if(!client){ + console.log("Erro de cliente"); + return done(null, false); + } + if (client.client_secret !== client_secret){ + console.log("Erro de geracao Chave Secreta"); + return done(null, false); + } + console.log("Tudo certo nesse use"); + return done(null, client); + }) + } + )); + +let generateTokens = (userId, clientId, done) => { + // curries in `done` callback so we don't need to pass it + let refreshTokenValue; + let token; + let tokenValue; + + RefreshToken.destroy({where:{"user_id": userId, "client_id": clientId}}); + AccessToken.destroy({where:{"user_id": userId, "client_id": clientId}}); + + tokenValue = crypto.randomBytes(32).toString('hex'); + refreshTokenValue = crypto.randomBytes(32).toString('hex'); + + AccessToken.create({ + user_id:userId, + client_id:clientId, + token:tokenValue + }) + + let refreshed_token = refreshTokenValue; + + RefreshToken.create({ + user_id:userId, + client_id:clientId, + token:refreshed_token + }) + + token.save((err) => { + if (err) { + log.error(err); + return done(err); + } + done(null, tokenValue, refreshTokenValue, { + 'expires_in': config.security.tokenLife + }); + }) +}; + + +let entrar = function(client, username, done) { + User.findOne({ + where: {email:username} + }).then(function(user) { + console.log(user) + if(user == null){ + return done(null, false); + } + if(user.dataValues.origin != client.client_secret){ + console.log("Erro de client_secret"); + return done(null, false); + } + log.info(`Gerando token para usuário ${user.name}`); + generateTokens(user._id, client._id, done); + }).catch(function(error) { + return done(error); + }); + }; + + + + + +testApp.post('/', (req, res, next) =>{ + entrar(req.body, req.body.username); +}); + + +module.exports = testApp; \ No newline at end of file diff --git a/src/libs/routes/transport.js b/src/libs/routes_v1/transport.js similarity index 100% rename from src/libs/routes/transport.js rename to src/libs/routes_v1/transport.js diff --git a/src/libs/routes/university.js b/src/libs/routes_v1/university.js similarity index 100% rename from src/libs/routes/university.js rename to src/libs/routes_v1/university.js diff --git a/src/libs/routes/universityEnrollment.js b/src/libs/routes_v1/universityEnrollment.js similarity index 100% rename from src/libs/routes/universityEnrollment.js rename to src/libs/routes_v1/universityEnrollment.js diff --git a/src/libs/routes/universityLocalOffer.js b/src/libs/routes_v1/universityLocalOffer.js similarity index 100% rename from src/libs/routes/universityLocalOffer.js rename to src/libs/routes_v1/universityLocalOffer.js diff --git a/src/libs/routes/universityTeacher.js b/src/libs/routes_v1/universityTeacher.js similarity index 100% rename from src/libs/routes/universityTeacher.js rename to src/libs/routes_v1/universityTeacher.js diff --git a/src/libs/routes_v1/user.js b/src/libs/routes_v1/user.js new file mode 100644 index 0000000000000000000000000000000000000000..95949bc3d2a40ab25578090a0662728918bc9d36 --- /dev/null +++ b/src/libs/routes_v1/user.js @@ -0,0 +1,341 @@ +const express = require('express'); + +const userApp = express(); + +const libs = `${process.cwd()}/libs`; + +const config = require(`${libs}/config`); + +const log = require(`${libs}/log`)(module); + +const User = require(`${libs}/models/user`); + +const VerificationToken = require(`${libs}/models/verificationToken`); + +const ResetToken = require(`${libs}/models/resetToken`); + +const response = require(`${libs}/middlewares/response`); + +const email = require(`${libs}/middlewares/email`); + +const passport = require('passport'); + +const uuid = require('node-uuid'); + +function emailSyntax(email) { + const regex = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; + return regex.test(email); +} + +userApp.get('/schooling', (req, res, next) => { + req.result = [ + 'Não estudou', + 'Ensino Fundamental Incompleto', + 'Ensino Fundamental Completo', + 'Ensino Médio', + 'Graduação', + 'Mestrado', + 'Doutorado' + ]; + next(); +}, response('schooling')); + +userApp.get('/segment', (req, res, next) => { + req.result = [ + 'Gestores e equipe gestora das secretarias e ministério da Educação', + 'Gestores dos órgãos de planejamento e finanças (das três esferas de governo)', + 'Agentes do poder legislativo', + 'Agentes dos conselhos de educação', + 'Profissionais da educação', + 'Sindicato', + 'Sociedade civil interessada no financiamento da Educação Básica de qualidade', + 'Comunidade acadêmica', + 'Imprensa', + 'Outro [citar segmento]' + ]; + next(); +}, response('segment')); + +userApp.get('/role', (req, res, next) => { + req.result = [ + { "Gestores e equipe gestora das secretarias e ministério da Educação": ["Dirigente municipal, estadual e federal", "Secretário do MEC", "Servidor da área de planejamento educacional", "Membro de associação de gestores (Ex. Undime, Consed, etc)", "Outro [citar função]"] }, + { "Gestores dos órgãos de planejamento e finanças (das três esferas de governo)": ["Equipe gestora dos órgãos de planejamento", "Equipe gestora dos órgãos de finanças", "Outro [citar função]"] }, + { "Agentes do poder legislativo": ["Parlamentar", "Assessor/a parlamentar", "Auditor/a dos tribunais de conta", "Conselheiro/a de tribunais de conta.", "Outro [citar função]"] }, + { "Agentes dos conselhos de educação": ["Conselheiro/a municipais, estaduais e federais", "Conselheiro/a do Fundeb", "Outro [citar função]"] }, + { "Profissionais da educação": ["Professor/a da Educação Básica", "Profissional da educação não-docente", "Outro [citar função]"] }, + { "Sindicato": ["Agente de sindicatos"] }, + { "Sociedade civil interessada no financiamento da Educação Básica de qualidade": ["Membro de fóruns educacionais", "Membro de ONGs e demais entidades sem fins lucrativos", "Estudante da educação básica e membro de entidades estudantis", "Pais e membros de entidades de pais", "Outro [citar função]"] }, + { "Comunidade acadêmica": ["Pesquisador/a", "Estudantes de graduação e pós-graduação", "Representantes de entidades de pesquisa (Ex.: ANPED, ANPAE e FINEDUCA)", "Outro [citar função]"] }, + { "Imprensa": ["Jornalista", "Outro [citar função]"] }, + { "Outro [citar segmento]": [] } + ] + next(); +}, response('role')); + +/* +userApp.get('/', passport.authenticate('bearer', {session: false}), (req, res, next) => { + User.find((err, users) => { + if(err) { + log.error(err); + return next(err); + } + + let result = []; + users.forEach((user) => { + let u = user.toObject(); + delete u.hashedPassword; + delete u.salt; + result.push(u); + }); + req.result = result; + next(); + }); +}, response('users')); +*/ + +userApp.get('/me', passport.authenticate('bearer', { session: false }), (req, res, next) => { + let u = req.user.toJSON(); + u._id = u.id; + u.institutionName = u.institution_name; + u.receiveEmails = u.receive_email; + u.receive_emails = u.receive_email; + delete u.id; + delete u.institution_name; + delete u.receive_email; + delete u.hashed_password; + delete u.salt; + + req.result = u; + next(); +}, response('user')); + +function isEmpty(str) { + return (!str || str.length === 0 ); +} + +userApp.get('/:id', (req, res, next) => { + User.findByPk(req.params.id).then((user) => { + if (!user) { + res.statusCode = 404; + res.json({ msg: "O usuário não está cadastrado" }); + } else { + let u = user.toJSON(); + u._id = u.id; + u.institutionName = u.institution_name; + u.receiveEmails = u.receive_email; + u.receive_emails = u.receive_email; + delete u.id; + delete u.institution_name; + delete u.receive_email; + delete u.hashed_password; + delete u.salt; + req.result = u; + next(); + } + }).catch(function (err) { + log.error(err); + return next(err); + }); +}, response('user')); + +userApp.post('/', async (req, res, next) => { + if (typeof req.body.password === 'undefined' || !req.body.password) { + res.statusCode = 400; + return res.json({ errors: ["O campo senha é obrigatório"] }); + } + else { + let user = await User.create({ + id: 0, + email: req.body.email, + password: req.body.password, + hashed_password: 0, + salt: 0, + name: req.body.name, + nickname: req.body.nickname, + cpf: req.body.cpf, + cep: req.body.cep, + complement: req.body.complement, + address: req.body.address, + phone: req.body.phone, + schooling: req.body.schooling, + course: req.body.course, + segment: req.body.segment, + role: req.body.role, + institution_name: req.body.institutionName, + state: req.body.state, + city: req.body.city, + receive_email: false || req.body.receiveEmails || req.body.receive_emails, + origin: req.body.origin, + citesegment: req.body.citesegment, + citerole: req.body.citerole, + admin: false, + role_id: 0 + }).catch(function (err) { + log.error(err); + let errors = []; + for (let errName in err.errors) { + errors.push(err.errors[errName].message); + } + log.error(errors); + res.statusCode = 400; + return res.json({ err, errors }); + // handle error; + }); + let tokenValue = uuid.v4(); + const verificationToken = VerificationToken.create({ + user_id: user.id, + token: tokenValue, + verified: false + }); + if (!verificationToken) { + res.statusCode = 404; + return res.json({ msg: "Couldn't create Verification Token" }); + } + let url = config.default.lde.url + '/verify'; + let text = `Olá, ${user.name}, seja bem vindo/a ao Laboratório de Dados Educacionais.\n\nClique neste link para confirmar sua conta: ${url}/${tokenValue}`; + // Send confirmation email + let mailOptions = { + to: `"${user.name} <${user.email}>"`, + subject: "Confirme seu cadastro - Laboratório de Dados Educacionais", + text + } + email(mailOptions, (err, info) => { + if (err) { + log.error(err); + res.json({ msg: 'Message not delivered, user created but not confirmed' }); + } + if (info) { + log.info(`Message ${info.messageId} sent: ${info.response}`); + log.info(`Usuário ${user.email} foi criado`); + } + res.json({ msg: 'User created' }); + }); + } +}); + +userApp.put('/:id', passport.authenticate('bearer', { session: false }), async (req, res, next) => { + let user = await User.findByPk(req.params.id).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }) + if (!user) { + res.statusCode = 404; + return next({ + err: { + message: 'Usuário não encontrado' + } + }); + } + + user.email = req.body.email || user.email; + user.name = req.body.name || user.name; + user.nickname = req.body.nickname || user.nickname || user.name; + user.cep = req.body.cep || user.cep; + user.complement = req.body.complement || user.complement; + user.address = req.body.address || user.address; + user.phone = req.body.phone || user.phone; + user.schooling = req.body.schooling || user.schooling; + user.course = req.body.course || user.course; + user.segment = req.body.segment || user.segment; + user.role = req.body.role || user.role; + user.institutionName = req.body.institutionName || user.institutionName; + user.state = req.body.state || user.state; + user.city = req.body.city || user.city; + user.receive_email = req.body.receiveEmails || req.body.receive_emails || user.receive_email; + user.citesegment = req.body.citesegment || user.citesegment; + user.citerole = req.body.citerole || user.citerole; + + if((!isEmpty(req.body.password)) && (!isEmpty(req.body.newpassword))){ + if (req.body.password != req.body.newpassword) { + if (user.checkPassword(user, req.body.password)) { + await user.update({password:req.body.newpassword}); + } + else { + res.statusCode = 500; + return res.json({ + error: { + message: 'A senha atual está incorreta' + } + }); + } + } else { + res.statusCode = 500; + return res.json({ + error: { + message: 'A nova senha é a mesma da senha atual' + } + }); + } + } + + user.save().catch(err => { + if (err) { + log.error(err); + return next({ message: 'Erro ao atualizar usuário' }); + }}) + let u = user.toJSON(); + u._id = u.id; + u.institutionName = u.institution_name; + u.receiveEmails = u.receive_email; + u.receive_emails = u.receive_email; + delete u.id; + delete u.institution_name; + delete u.receive_email; + delete u.hashed_password; + delete u.salt; + delete u.password; + res.json({ user: u }); + +}); + + +userApp.get('/reset/password', async (req, res, next) => { + let emailAddress = req.query.email; + let user = await User.findOne({ where: { email: emailAddress } }).catch(function (err) { + log.error(err); + let errors = []; + for (let errName in err.errors) { + errors.push(err.errors[errName].message); + } + log.error(errors); + res.statusCode = 400; + return res.json({ err, errors }); + // handle error; + }); + console.log(user); + if (!user) { + res.statusCode = 404; + res.json({ msg: "O usuário não está cadastrado" }); + } + else { + let tokenValue = uuid.v4(); + const rt = await ResetToken.create({ + user_id: user.id, + token: tokenValue, + reset: false + }); + if (!rt) { + res.statusCode = 404; + return res.json({ msg: "Couldn't create Reset Password Token" }); + } + let url = config.default.lde.url + '/reset-password'; + let text = `Olá, ${user.name}.\n\nRecebemos uma solicitação para redefinir sua senha do Laboratório de Dados Educacionais. Clique neste link para redefinir a sua senha: ${url}/${tokenValue}`; + let mailOptions = { + to: `"${user.name} <${user.email}>"`, + subject: "Redefinição de Senha - Laboratório de Dados Educacionais", + text + } + console.log(mailOptions); + email(mailOptions, (err, info) => { + if (err) { + log.error(err); + res.json({ msg: 'Undelivered Reset Password Mail' }); + } + res.json({ msg: 'Reset Password Mail Successfully Delivered' }); + }); + } +}); + +module.exports = userApp; diff --git a/src/libs/routes_v1/user.js.save b/src/libs/routes_v1/user.js.save new file mode 100644 index 0000000000000000000000000000000000000000..f8390c04555ed4ea96892476b8715d7d908a473d --- /dev/null +++ b/src/libs/routes_v1/user.js.save @@ -0,0 +1,340 @@ +const express = require('express'); + +const userApp = express(); + +const libs = `${process.cwd()}/libs`; + +const config = require(`${libs}/config`); + +const log = require(`${libs}/log`)(module); + +const User = require(`${libs}/models/user`); + +const VerificationToken = require(`${libs}/models/verificationToken`); + +const ResetToken = require(`${libs}/models/resetToken`); + +const response = require(`${libs}/middlewares/response`); + +const email = require(`${libs}/middlewares/email`); + +const passport = require('passport'); + +const uuid = require('node-uuid'); + +function emailSyntax(email) { + const regex = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; + return regex.test(email); +} + +userApp.get('/schooling', (req, res, next) => { + req.result = [ + 'Não estudou', + 'Ensino Fundamental Incompleto', + 'Ensino Fundamental Completo', + 'Ensino Médio', + 'Graduação', + 'Mestrado', + 'Doutorado' + ]; + next(); +}, response('schooling')); + +userApp.get('/segment', (req, res, next) => { + req.result = [ + 'Gestores e equipe gestora das secretarias e ministério da Educação', + 'Gestores dos órgãos de planejamento e finanças (das três esferas de governo)', + 'Agentes do poder legislativo', + 'Agentes dos conselhos de educação', + 'Profissionais da educação', + 'Sindicato', + 'Sociedade civil interessada no financiamento da Educação Básica de qualidade', + 'Comunidade acadêmica', + 'Imprensa', + 'Outro [citar segmento]' + ]; + next(); +}, response('segment')); + +userApp.get('/role', (req, res, next) => { + req.result = [ + { "Gestores e equipe gestora das secretarias e ministério da Educação": ["Dirigente municipal, estadual e federal", "Secretário do MEC", "Servidor da área de planejamento educacional", "Membro de associação de gestores (Ex. Undime, Consed, etc)", "Outro [citar função]"] }, + { "Gestores dos órgãos de planejamento e finanças (das três esferas de governo)": ["Equipe gestora dos órgãos de planejamento", "Equipe gestora dos órgãos de finanças", "Outro [citar função]"] }, + { "Agentes do poder legislativo": ["Parlamentar", "Assessor/a parlamentar", "Auditor/a dos tribunais de conta", "Conselheiro/a de tribunais de conta.", "Outro [citar função]"] }, + { "Agentes dos conselhos de educação": ["Conselheiro/a municipais, estaduais e federais", "Conselheiro/a do Fundeb", "Outro [citar função]"] }, + { "Profissionais da educação": ["Professor/a da Educação Básica", "Profissional da educação não-docente", "Outro [citar função]"] }, + { "Sindicato": ["Agente de sindicatos"] }, + { "Sociedade civil interessada no financiamento da Educação Básica de qualidade": ["Membro de fóruns educacionais", "Membro de ONGs e demais entidades sem fins lucrativos", "Estudante da educação básica e membro de entidades estudantis", "Pais e membros de entidades de pais", "Outro [citar função]"] }, + { "Comunidade acadêmica": ["Pesquisador/a", "Estudantes de graduação e pós-graduação", "Representantes de entidades de pesquisa (Ex.: ANPED, ANPAE e FINEDUCA)", "Outro [citar função]"] }, + { "Imprensa": ["Jornalista", "Outro [citar função]"] }, + { "Outro [citar segmento]": [] } + ] + next(); +}, response('role')); + +/* +userApp.get('/', passport.authenticate('bearer', {session: false}), (req, res, next) => { + User.find((err, users) => { + if(err) { + log.error(err); + return next(err); + } + + let result = []; + users.forEach((user) => { + let u = user.toObject(); + delete u.hashedPassword; + delete u.salt; + result.push(u); + }); + req.result = result; + next(); + }); +}, response('users')); +*/ + +userApp.get('/me', passport.authenticate('bearer', { session: false }), (req, res, next) => { + let u = req.user.toJSON(); + u._id = u.id; + u.institutionName = u.institution_name; + u.receiveEmails = u.receive_email; + u.receive_emails = u.receive_email; + delete u.id; + delete u.institution_name; + delete u.receive_email; + delete u.hashed_password; + delete u.salt; + + req.result = u; + next(); +}, response('user')); + +function isEmpty(str) { + return (!str || str.length === 0 ); +} + +userApp.get('/:id', (req, res, next) => { + User.findByPk(req.params.id).then((user) => { + if (!user) { + res.statusCode = 404; + res.json({ msg: "O usuário não está cadastrado" }); + } else { + let u = user.toJSON(); + u._id = u.id; + u.institutionName = u.institution_name; + u.receiveEmails = u.receive_email; + u.receive_emails = u.receive_email; + delete u.id; + delete u.institution_name; + delete u.receive_email; + delete u.hashed_password; + delete u.salt; + req.result = u; + next(); + } + }).catch(function (err) { + log.error(err); + return next(err); + }); +}, response('user')); + +userApp.post('/', async (req, res, next) => { + if (typeof req.body.password === 'undefined' || !req.body.password) { + res.statusCode = 400; + return res.json({ errors: ["O campo senha é obrigatório"] }); + } + else { + let user = await User.create({ + id: 0, + email: req.body.email, + password: req.body.password, + hashed_password: 0, + salt: 0, + name: req.body.name, + nickname: req.body.nickname, + cpf: req.body.cpf, + cep: req.body.cep, + complement: req.body.complement, + address: req.body.address, + phone: req.body.phone, + schooling: req.body.schooling, + course: req.body.course, + segment: req.body.segment, + role: req.body.role, + institution_name: req.body.institutionName, + state: req.body.state, + city: req.body.city, + receive_email: false || req.body.receiveEmails || req.body.receive_emails, + origin: req.body.origin, + citesegment: req.body.citesegment, + citerole: req.body.citerole, + admin: false, + role_id: 0 + }).catch(function (err) { + log.error(err); + let errors = []; + for (let errName in err.errors) { + errors.push(err.errors[errName].message); + } + log.error(errors); + res.statusCode = 400; + return res.json({ err, errors }); + // handle error; + }); + let tokenValue = uuid.v4(); + const verificationToken = VerificationToken.create({ + user_id: user.id, + token: tokenValue, + verified: false + }); + if (!verificationToken) { + res.statusCode = 404; + return res.json({ msg: "Couldn't create Verification Token" }); + } + let url = config.default.lde.url + '/verify'; + let text = `Olá, ${user.name}, seja bem vindo/a ao Laboratório de Dados Educacionais.\n\nClique neste link para confirmar sua conta: ${url}/${tokenValue}`; + // Send confirmation email + let mailOptions = { + to: `"${user.name} <${user.email}>"`, + subject: "Confirme seu cadastro - Laboratório de Dados Educacionais", + text + } + email(mailOptions, (err, info) => { + if (err) { + log.error(err); + res.json({ msg: 'Message not delivered, user created but not confirmed' }); + } + if (info) { + log.info(`Message ${info.messageId} sent: ${info.response}`); + log.info(`Usuário ${user.email} foi criado`); + } + res.json({ msg: 'User created' }); + }); + } +}); + +userApp.put('/:id', passport.authenticate('bearer', { session: false }), async (req, res, next) => { + let user = await User.findByPk(req.params.id).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }) + if (!user) { + res.statusCode = 404; + return next({ + err: { + message: 'Usuário não encontrado' + } + }); + } + + user.email = req.body.email || user.email; + user.name = req.body.name || user.name; + user.nickname = req.body.nickname || user.nickname || user.name; + user.cep = req.body.cep || user.cep; + user.complement = req.body.complement || user.complement; + user.address = req.body.address || user.address; + user.phone = req.body.phone || user.phone; + user.schooling = req.body.schooling || user.schooling; + user.course = req.body.course || user.course; + user.segment = req.body.segment || user.segment; + user.role = req.body.role || user.role; + user.institutionName = req.body.institutionName || user.institutionName; + user.state = req.body.state || user.state; + user.city = req.body.city || user.city; + user.receive_email = req.body.receiveEmails || req.body.receive_emails || user.receive_email; + user.citesegment = req.body.citesegment || user.citesegment; + user.citerole = req.body.citerole || user.citerole; + + if((!isEmpty(req.body.password)) && (!isEmpty(req.body.newpassword))){ + if (req.body.password != req.body.newpassword) { + if (user.checkPassword(user, req.body.password)) { + await user.update({password:req.body.newpassword}); + } + else { + res.statusCode = 500; + return res.json({ + error: { + message: 'A senha atual está incorreta' + } + }); + } + } else { + res.statusCode = 500; + return res.json({ + error: { + message: 'A nova senha é a mesma da senha atual' + } + }); + } + } + + user.save().catch(err => { + if (err) { + log.error(err); + return next({ message: 'Erro ao atualizar usuário' }); + }}) + let u = user.toJSON(); + u._id = u.id; + u.institutionName = u.institution_name; + u.receiveEmails = u.receive_email; + u.receive_emails = u.receive_email; + delete u.id; + delete u.institution_name; + delete u.receive_email; + delete u.hashed_password; + delete u.salt; + delete u.password; + res.json({ user: u }); + +}); + + +userApp.get('/reset/password', async (req, res, next) => { + let emailAddress = req.query.email; + let user = await User.findOne({ where: { email: emailAddress } }).catch(function (err) { + log.error(err); + let errors = []; + for (let errName in err.errors) { + errors.push(err.errors[errName].message); + } + log.error(errors); + res.statusCode = 400; + return res.json({ err, errors }); + // handle error; + }); + if (!user) { + res.statusCode = 404; + res.json({ msg: "O usuário não está cadastrado" }); + } + else { + let tokenValue = uuid.v4(); + const rt = await ResetToken.create({ + user_id: user.id, + token: tokenValue, + reset: false + }); + if (!rt) { + res.statusCode = 404; + return res.json({ msg: "Couldn't create Reset Password Token" }); + } + let url = config.default.lde.url + '/reset-password'; + let text = `Olá, ${user.name}.\n\nRecebemos uma solicitação para redefinir sua senha do Laboratório de Dados Educacionais. Clique neste link para redefinir a sua senha: ${url}/${tokenValue}`; + let mailOptions = { + to: `"${user.name} <${user.email}>"`, + subject: "Redefinição de Senha - Laboratório de Dados Educacionais", + text + } + console.log(mailOptions); + email(mailOptions, (err, info) => { + if (err) { + log.error(err); + res.json({ msg: 'Undelivered Reset Password Mail' }); + } + res.json({ msg: 'Reset Password Mail Successfully Delivered' }); + }); + } +}); + +module.exports = userApp; diff --git a/src/libs/routes_v1/verifyToken.js b/src/libs/routes_v1/verifyToken.js new file mode 100644 index 0000000000000000000000000000000000000000..81731fe3809df11cd7cb69d04c430642c58cc54c --- /dev/null +++ b/src/libs/routes_v1/verifyToken.js @@ -0,0 +1,54 @@ +const express = require('express'); + +const verifyTokenApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const VerificationToken = require(`${libs}/models/verificationToken`); + +const User = require(`${libs}/models/user`); + +verifyTokenApp.get('/:token', async (req, res, next) => { + let token = req.params.token; + let vToken = await VerificationToken.findOne({ where: { token: token } }).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }) + if (!vToken) { + // TODO: generate new verification token + res.statusCode = 404; + return next({ msg: 'Token not found', status: 404 }); + } + let _user = await User.findByPk(vToken.user_id).catch(function (err) { + if (err) { + log.error(err); + return next({ err }); + } + }) + if(!_user){ + return done(null, false); + } + await _user.update({verified:true}); + await _user.save().catch(err => { + if (err) { + log.error(err); + return next({ message: 'Erro ao atualizar usuário' }); + }}) + vToken.verified = true; + await vToken.save().catch(err => { + if (err) { + log.error(err); + next(err); + } + }); + let u = _user.toJSON(); + delete u['salt']; + delete u['hashed_password']; + res.json({ msg: 'User verified', u }); +}); + +module.exports = verifyTokenApp; diff --git a/src/libs/routes_v2/api.js b/src/libs/routes_v2/api.js new file mode 100644 index 0000000000000000000000000000000000000000..a8e1e1b7d0c62e8b5c62037b8b3d55d6f22165e8 --- /dev/null +++ b/src/libs/routes_v2/api.js @@ -0,0 +1,238 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const api = express(); + +const libs = `${process.cwd()}/libs`; + +const config = require(`${libs}/config`); + +const classes = require('./class'); + +const enrollment = require('./enrollment'); + +const state = require('./state'); + +const region = require('./region'); + +const city = require('./city'); + +const school = require('./school'); + +const simulation = require('./simulation'); + +const user = require('./user'); + +const classroom = require('./classroom'); + +const teacher = require('./teacher'); + +const idhme = require('./idhme'); + +const pibpercapita = require('./pibpercapita') + +const population = require('./population') + +const rateSchool = require('./rateSchool') + +const glossEnrollmentRatio = require('./glossEnrollmentRatio') + +const liquidEnrollmentRatio = require('./liquidEnrollmentRatio') + +const idhm = require('./idhm'); + +const idhmr = require('./idhmr'); + +const idhml = require('./idhml'); + +const oauth2 = require(`${libs}/middlewares/oauth2`); + +const verifyToken = require(`${libs}/routes_v2/verifyToken`); + +const resetToken = require(`${libs}/routes_v2/resetToken`); + +const educationYears = require(`${libs}/routes_v2/educationYears`); + +const downloads = require(`${libs}/routes_v2/downloads`); + +const infrastructure = require(`${libs}/routes_v2/infrastructure`); + +const schoolInfrastructure = require(`${libs}/routes_v2/schoolInfrastructure`); + +const distributionFactor = require(`${libs}/routes_v2/distributionFactor`); + +const siope = require(`${libs}/routes_v2/siope`); + +const verifyTeacher = require(`${libs}/routes_v2/portalMec`); + +const outOfSchool = require(`${libs}/routes_v2/outOfSchool`); + +const classroomCount = require(`${libs}/routes_v2/classroomCount`); + +const transport = require(`./transport`); + +const auxiliar = require(`${libs}/routes_v2/auxiliar`); + +const dailyChargeAmount = require(`${libs}/routes_v2/dailyChargeAmount`); + +const cub = require(`${libs}/routes_v2/cub`); + +const classCount = require(`${libs}/routes_v2/classCount`); + +const portalMecInep = require(`${libs}/routes_v2/portalMecInep`); + +const enrollmentProjection = require(`${libs}/routes_v2/enrollmentProjection`); + +const employees = require(`${libs}/routes_v2/employees`); + +const financial = require(`${libs}/routes_v2/financial`); + +const universityEnrollment = require(`${libs}/routes_v2/universityEnrollment`); + +const courseCount = require(`${libs}/routes_v2/courseCount`); + +const university = require(`${libs}/routes_v2/university`); + +const universityTeacher = require(`${libs}/routes_v2/universityTeacher`); + +const educationalBudget = require(`${libs}/routes_v2/educationalBudget`); + +const schoolLocation = require(`${libs}/routes_v2/schoolLocation`); + +const studentsAee = require(`${libs}/routes_v2/studentsAee`); + +const mesoregion = require(`${libs}/routes_v2/mesoregion`); + +const microregion = require(`${libs}/routes_v2/microregion`); + +const location = require(`${libs}/routes_v2/location`); + +const disciplines = require(`${libs}/routes_v2/disciplines`); + +const universityLocalOffer = require(`${libs}/routes_v2/universityLocalOffer`); + +const message = require(`${libs}/routes_v2/message`); + +const courseStudents = require(`${libs}/routes_v2/courseStudents`); + +const simcaqFirstReport = require(`${libs}/routes_v2/simcaqFirstReport`); + +const simcaqEnrollmentDiagnosis = require(`${libs}/routes_v2/simcaqEnrollmentDiagnosis`); + +const simcaqSecondReport = require(`${libs}/routes_v2/simcaqSecondReport`); + +const simcaqDivisionOfResponsibility = require(`${libs}/routes_v2/simcaqDivisionOfResponsibility`); + +const simcaqClassroomSize = require(`${libs}/routes_v2/simcaqClassroomSize`); + +const simcaqWorkload = require(`${libs}/routes_v2/simcaqWorkload`); + +const simcaqNumberOfEmployees = require(`${libs}/routes_v2/simcaqNumberOfEmployees`); + +const simcaqNewClasses = require(`${libs}/routes_v2/simcaqNewClasses`); + +const simcaqResult = require(`${libs}/routes_v2/simcaqResult`); + +const simcaqNumberOfTeachers = require(`${libs}/routes_v2/simcaqNumberOfTeachers`); + +const simcaqEnrollmentProjection = require(`${libs}/routes_v2/simcaqEnrollmentProjection`); + +const simcaqAggregatedEnrollment = require(`${libs}/routes_v2/simcaqAggregatedEnrollment`); + +const simcaqTeacherCityPlan = require(`${libs}/routes_v2/simcaqTeacherCityPlan`); + +const simcaqSchoolInfrastructure = require(`${libs}/routes_v2/simcaqSchoolInfrastructure`); + +api.get('/', (req, res) => { + res.json({ msg: 'SimCAQ API v2 is running' }); +}); + +// mount API routes_v2 +api.use('/user', user); +api.use('/simulation', simulation); +api.use('/class', classes); +api.use('/enrollment', enrollment); +api.use('/state', state); +api.use('/region', region); +api.use('/city', city); +api.use('/school', school); +api.use('/classroom', classroom); +api.use('/teacher', teacher); +api.use('/idhmr', idhmr); +api.use('/idhm', idhm); +api.use('/idhme', idhme); +api.use('/pibpercapita', pibpercapita); +api.use('/population', population); +api.use('/rate_school', rateSchool); +api.use('/gloss_enrollment_ratio', glossEnrollmentRatio); +api.use('/liquid_enrollment_ratio', liquidEnrollmentRatio); +api.use('/idhml', idhml); +api.use('/auth/token', oauth2.token); +api.use('/verify', verifyToken); +api.use('/reset', resetToken); +api.use('/education_years', educationYears); +api.use('/downloads', downloads); +api.use('/infrastructure', infrastructure); +api.use('/school_infrastructure', schoolInfrastructure); +api.use('/distribution_factor', distributionFactor); +api.use('/siope', siope); +api.use('/out_of_school', outOfSchool); +api.use('/classroom_count', classroomCount); +api.use('/daily_charge_amount', dailyChargeAmount); +api.use('/transport', transport); +api.use('/cub', cub); +api.use('/auxiliar', auxiliar); +api.use('/verify_teacher', verifyTeacher); +api.use('/class_count', classCount); +api.use('/portal_mec_inep', portalMecInep); +api.use('/enrollment_projection', enrollmentProjection); +api.use('/employees', employees); +api.use('/financial', financial); +api.use('/university_enrollment', universityEnrollment); +api.use('/university', university); +api.use('/university_teacher', universityTeacher); +api.use('/course_count', courseCount); +api.use('/school_location', schoolLocation); +api.use('/students_aee', studentsAee); +api.use('/mesoregion', mesoregion); +api.use('/microregion', microregion); +api.use('/location', location); +api.use('/disciplines', disciplines); +api.use('/universityLocalOffer', universityLocalOffer); +api.use('/message', message); +api.use('/course_students', courseStudents); +api.use('/simcaq_first_report', simcaqFirstReport); +api.use('/simcaq_enrollment_diagnosis', simcaqEnrollmentDiagnosis); +api.use('/simcaq_second_report', simcaqSecondReport); +api.use('/simcaq_division_of_responsibility', simcaqDivisionOfResponsibility); +api.use('/simcaq_classroom_size', simcaqClassroomSize); +api.use('/simcaq_workload', simcaqWorkload); +api.use('/simcaq_number_of_employees', simcaqNumberOfEmployees); +api.use('/simcaq_new_classes', simcaqNewClasses); +api.use('/simcaq_result', simcaqResult); +api.use('/simcaq_number_of_teachers', simcaqNumberOfTeachers); +api.use('/simcaq_enrollment_projection', simcaqEnrollmentProjection); +api.use('/simcaq_aggregated_enrollment', simcaqAggregatedEnrollment); +api.use('/simcaq_teacher_city_plan', simcaqTeacherCityPlan); +api.use('/simcaq_school_infrastructure', simcaqSchoolInfrastructure); + +module.exports = api; diff --git a/src/libs/routes_v2/auxiliar.js b/src/libs/routes_v2/auxiliar.js new file mode 100644 index 0000000000000000000000000000000000000000..ef5389611ae2b53dce22d3c513034db5f9bf64d9 --- /dev/null +++ b/src/libs/routes_v2/auxiliar.js @@ -0,0 +1,397 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const auxiliarApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const config = require(`${libs}/config`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +auxiliarApp.use(cache('15 day')); + +auxiliarApp.get('/year_range', (req, res, next) => { + req.sql.from('docente') + .field('MIN(docente.ano_censo)', 'start_year') + .field('MAX(docente.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +auxiliarApp.get('/years', (req, res, next) => { + req.sql.from('docente'). + field('DISTINCT docente.ano_censo', 'year') + next(); +}, query, response('years')); + +auxiliarApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'docente\''); + next(); +}, query, response('source')) + +auxiliarApp.get('/education_type', (req, res, next) => { + req.sql.from('docente') + .field('DISTINCT nivel_tipo_formacao', 'id') + .order('id'); + next(); +}, query, (req, res, next) => { + req.result.forEach((result) => { + result.name = id2str.educationType(result.id); + }); + next(); +}, response('education_type')); + +auxiliarApp.get('/adm_dependency_detailed', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 7; ++i) { + req.result.push({ + id: i, + name: id2str.admDependencyPriv(i) + }); + }; + next(); +}, response('adm_dependency_detailed')); + +auxiliarApp.get('/adm_dependency', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.admDependency(i) + }); + }; + next(); +}, response('adm_dependency')); + +auxiliarApp.get('/location', (req, res, next) => { + req.result = [ + {id: 1, name: 'Urbana'}, + {id: 2, name: 'Rural'} + ]; + next(); +}, response('location')); + +auxiliarApp.get('/diff_location', (req, res, next) => { + req.result = [ + {id: 0, name: "A escola não está em localidade diferenciada"}, + {id: 1, name: "Área de assentamento"}, + {id: 2, name: "Terra indígena"}, + {id: 3, name: "Terra remanescente de quilombos"}, + ]; + next(); +}, response('diff_location')); + +auxiliarApp.get('/education_level_mod', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 12; ++i) { + req.result.push({ + id: i, + name: id2str.educationLevelMod(i) + }); + } + + req.result.push({ + id: 99, + name: id2str.educationLevelMod(99) + }); + next(); +}, response('education_level_mod')); + +auxiliarApp.get('/gender', (req, res, next) => { + req.result = [ + {id: 1, name: 'Masculino'}, + {id: 2, name: 'Feminino'} + ]; + next(); +}, response('gender')); + +auxiliarApp.get('/ethnic_group', (req, res, next) => { + req.result = []; + for(let i = 0; i <=5; ++i) { + req.result.push({ + id: i, + name: id2str.ethnicGroup(i) + }); + } + next(); +}, response('ethnic_group')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'adm_dependency', + table: 'docente', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}).addValue({ + name: 'adm_dependency_detailed', + table: 'docente', + tableField: 'dependencia_adm_priv', + resultField: 'adm_dependency_detailed_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_priv' + } +}).addValue({ + name: 'education_type', + table: 'docente', + tableField: 'nivel_tipo_formacao', + resultField: 'education_type_id', + where: { + relation: '=', + type: 'integer', + field: 'nivel_tipo_formacao' + } +}).addValue({ + name: 'education_level_mod', + table: 'docente', + tableField: 'etapas_mod_ensino_segmento_id', + resultField: 'education_level_mod_id', + where: { + relation: '=', + type: 'integer', + field: 'etapas_mod_ensino_segmento_id' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_regiao_id', + foreignTable: 'docente' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_estado_id', + foreignTable: 'docente' + } +}).addValue({ + name: 'rural_location', + table: 'docente', + tableField: 'localidade_area_rural', + resultField: 'rural_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localidade_area_rural' + } +}).addValueToField({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_municipio_id', + foreignTable: 'docente' + } +}, 'dims').addValueToField({ + name: 'city', + table: 'municipio', + tableField: 'nome', + resultField: 'city_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_municipio_id', + foreignTable: 'docente' + } +}, 'filter').addValueToField({ + name: 'school', + table: 'escola', + tableField: ['nome_escola', 'id'], + resultField: ['school_name', 'school_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id', 'ano_censo'], + foreign: ['escola_id', 'ano_censo'], + foreignTable: 'docente' + } +}, 'dims').addValueToField({ + name: 'school', + table: 'escola', + tableField: 'nome_escola', + resultField: 'school_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id', 'ano_censo'], + foreign: ['escola_id', 'ano_censo'], + foreignTable: 'docente' + } +}, 'filter').addValue({ + name: 'location', + table: 'docente', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'diff_location', + table: 'docente', + tableField: 'localizacao_diferenciada_par', + resultField: 'diff_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_diferenciada_par' + } +}).addValue({ + name: 'min_year', + table: 'docente', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'docente', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'gender', + table: 'docente', + tableField: 'sexo', + resultField: 'gender_id', + where: { + relation: '=', + type: 'integer', + field: 'sexo' + } +}).addValue({ + name: 'ethnic_group', + table: 'docente', + tableField: 'cor_raca', + resultField: 'ethnic_group_id', + where: { + relation: '=', + type: 'integer', + field: 'cor_raca' + } +}); + +// LDE +auxiliarApp.get('/', rqf.parse(), (req, res, next) => { + req.sql.field('COUNT(DISTINCT docente.id_docente)', 'total') + .field("'Brasil'", 'name') + .field('docente.ano_censo', 'year') + .from('docente') + .join('turma', null, 'docente.turma_id=turma.id AND docente.ano_censo=turma.ano_censo') + .group('docente.ano_censo') + .order('docente.ano_censo') + .where('(docente.tipo_docente = 2) AND \ + ((docente.tipo_turma_id >= 0 AND docente.tipo_turma_id <= 3 AND docente.tipo_turma_atendimento_id is NULL) \ + OR ((docente.tipo_turma_atendimento_id = 1 OR docente.tipo_turma_atendimento_id = 2) AND docente.tipo_turma_id is NULL)) \ + AND (docente.ano_censo <> 2009 or (docente.escola_estado_id <> 42 AND docente.escola_estado_id <> 43))'); // não devemos trazer SC em 2009. + next(); +}, rqf.build(), query, addMissing(rqf), id2str.transform(), response('auxiliar')); + +// SimCAQ +auxiliarApp.get('/count', rqf.parse(), (req, res, next) => { + req.sql.field('COUNT(DISTINCT docente.id_docente)', 'total') + .field("'Brasil'", 'name') + .field('docente.ano_censo', 'year') + .from('docente') + .group('docente.ano_censo') + .order('docente.ano_censo') + .where('(tipo_turma_id <= 3) AND (tipo_docente=2) AND (dependencia_adm_id = 1 OR dependencia_adm_id = 2 OR dependencia_adm_id = 3) AND \ + (etapas_mod_ensino_segmento_id=1 OR etapas_mod_ensino_segmento_id=2 OR etapas_mod_ensino_segmento_id=4 OR \ + etapas_mod_ensino_segmento_id=5 OR etapas_mod_ensino_segmento_id=6 OR etapas_mod_ensino_segmento_id=8 OR etapas_mod_ensino_segmento_id=9)'); + + next(); +}, rqf.build(), query, addMissing(rqf), id2str.transform(), response('auxiliar')); + +module.exports = auxiliarApp; diff --git a/src/libs/routes_v2/city.js b/src/libs/routes_v2/city.js new file mode 100644 index 0000000000000000000000000000000000000000..fc697a9f5d146c48c5e87c49ec54572566b22f82 --- /dev/null +++ b/src/libs/routes_v2/city.js @@ -0,0 +1,151 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const cityApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +cityApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addValue({ + name: 'id', + table: 'municipio', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'municipio' + } +}).addValue({ + name: 'state_not', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '<>', + type: 'integer', + field: 'estado_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'municipio' + } +}).addField({ + name: 'search', + field: false, + where: true +}).addValueToField({ + name: 'name', + table: 'municipio', + tableField: 'nome', + where: { + relation: 'LIKE', + type: 'string', + field: 'nome' + } +}, 'search').addValue({ + name: 'mesoregion', + table: 'municipio', + tableField: 'mesorregiao_id', + where: { + relation: '=', + type: 'integer', + field: 'mesorregiao_id' + } +}).addValue({ + name: 'microregion', + table: 'municipio', + tableField: 'microrregiao_id', + where: { + relation: '=', + type: 'integer', + field: 'microrregiao_id' + } +}).addValueToField({ + name: 'region', + table: 'estado', + tableField: 'regiao_id', + resultField: 'region_id', + where: { + relation: '=', + type: 'integer', + field: 'regiao_id', + table: 'estado' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'municipio' + } +}, 'filter'); + +// Return all cities +cityApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('municipio') + .field('municipio.nome', 'name') + .field('municipio.id') + .field('municipio.estado_id', 'state_id') + .field('municipio.longitude', 'longitude') + .field('municipio.latitude', 'latitude') + .field('municipio.mesorregiao_id', 'mesoregion_id') + .field('municipio.microrregiao_id', 'microregion_id'); + next(); +}, query, response('city')); + + +module.exports = cityApp; diff --git a/src/libs/routes_v2/class.js b/src/libs/routes_v2/class.js new file mode 100644 index 0000000000000000000000000000000000000000..326bcf18f7ec4396d8f615f79aaba23e2bc921cf --- /dev/null +++ b/src/libs/routes_v2/class.js @@ -0,0 +1,402 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const classApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const config = require(`${libs}/config`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqfCount = new ReqQueryFields(); + +classApp.use(cache('15 day')); + +// Complete range of the enrollments dataset. +// Returns a tuple of start and ending years of the complete enrollments dataset. +classApp.get('/year_range', (req, res, next) => { + req.sql.from('turma') + .field('MIN(turma.ano_censo)', 'start_year') + .field('MAX(turma.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +classApp.get('/years', (req, res, next) => { + req.sql.from('turma') + .field('DISTINCT turma.ano_censo', 'year'); + next(); +}, query, response('years')); + +classApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'turma\''); + next(); +}, query, response('source')); + +classApp.get('/location', (req, res, next) => { + req.result = [ + {id: 1, name: 'Urbana'}, + {id: 2, name: 'Rural'} + ]; + next(); +}, response('location')); + +classApp.get('/diff_location', (req, res, next) => { + req.result = [ + {id: 0, name: "A escola não está em localidade diferenciada"}, + {id: 1, name: "Área de assentamento"}, + {id: 2, name: "Terra indígena"}, + {id: 3, name: "Terra remanescente de quilombos"}, + ]; + next(); +}, response('diff_location')); + +// Returns all adm dependencies +classApp.get('/adm_dependency', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.admDependency(i) + }); + }; + next(); +}, response('adm_dependency')); + +classApp.get('/adm_dependency_detailed', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 8; ++i) { + req.result.push({ + id: i, + name: id2str.admDependencyPriv(i) + }); + }; + next(); +}, response('adm_dependency_detailed')); + +// Returns all periods avaible +classApp.get('/period', (req, res, next) => { + req.result = []; + for(let i=1; i <= 3; ++i) { + req.result.push({ + id: i, + name: id2str.period(i) + }); + } + req.result.push({ + id: 99, + name: id2str.period(99) + }); + next(); +}, response('period')); + +// Returns integral-time avaible +classApp.get('/integral_time', (req, res, next) => { + req.result = []; + for(let i = 0; i <= 2; ++i) { + req.result.push({ + id: i, + name: id2str.integralTime(i) + }); + } + next(); +}, response('integral_time')); + +// Returns all educational levels avaible +classApp.get('/education_level_mod', (req, res, next) => { + req.result = []; + for(let i = 1; i <=12; ++i) { + req.result.push({ + id: i, + name: id2str.educationLevelMod(i) + }); + } + next(); +}, response('education_level_mod')); + +classApp.get('/education_level_short', (req, res, next) => { + req.result = [ + {id: null, name: 'Não classificada'}, + {id: 1, name: 'Creche'}, + {id: 2, name: 'Pré-Escola'}, + {id: 3, name: 'Ensino Fundamental - anos iniciais'}, + {id: 4, name: 'Ensino Fundamental - anos finais'}, + {id: 5, name: 'Ensino Médio'}, + {id: 6, name: 'EJA'}, + {id: 7, name: 'EE exclusiva'} + ]; + next(); +}, response('education_level_short')); + +rqfCount.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValueToField({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'turma' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'turma' + } +}, 'dims').addValueToField({ + name: 'city', + table: 'municipio', + tableField: 'nome', + resultField: 'city_name', + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'turma' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'turma' + } +}, 'filter').addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'turma' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'turma' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'turma' + } +}).addValue({ + name: 'min_year', + table: 'turma', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'turma', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name:'adm_dependency', + table: 'turma', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}).addValue({ + name: 'location', + table: 'turma', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'diff_location', + table: 'turma', + tableField: 'localizacao_diferenciada_par', + resultField: 'diff_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_diferenciada_par' + } +}).addValue({ + name: 'rural_location', + table: 'turma', + tableField: 'localidade_area_rural', + resultField: 'rural_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localidade_area_rural' + } +}).addValue({ + name:'education_level_mod', + table: 'turma', + tableField: 'etapas_mod_ensino_segmento_id', + resultField: 'education_level_mod_id', + where: { + relation: '=', + type: 'integer', + field: 'etapas_mod_ensino_segmento_id' + } +}).addValue({ + name: 'education_level_short', + table: 'turma', + tableField: 'etapa_resumida', + resultField: 'education_level_short_id', + where: { + relation: '=', + type: 'integer', + field: 'etapa_resumida' + } +}).addValue({ + name: 'adm_dependency_detailed', + table: 'turma', + tableField: 'dependencia_adm_priv', + resultField: 'adm_dependency_detailed_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_priv' + } +}).addValue({ + name:'period', + table: 'turma', + tableField: 'turma_turno_id', + resultField: 'period_id', + where: { + relation: '=', + type: 'integer', + field: 'turma_turno_id' + } +}).addValue({ + name:'integral_time', + table: 'turma', + tableField: 'tempo_integral', + resultField: 'integral_time_id', + where: { + relation: '=', + type: 'integer', + field: 'tempo_integral' + } +}).addValueToField({ + name: 'school', + table: 'escola_agregada', + tableField: ['nome_escola', 'id'], + resultField: ['school_name', 'school_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id', 'ano_censo'], + foreign: ['escola_id', 'ano_censo'], + foreignTable: 'turma' + } +}, 'dims').addValueToField({ + name: 'school', + table: 'escola_agregada', + tableField: 'nome_escola', + resultField: 'school_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id', 'ano_censo'], + foreign: ['escola_id', 'ano_censo'], + foreignTable: 'turma' + } +}, 'filter').addValueToField({ + name: 'period_not', + table: 'turma', + tableField: 'turma_turno_id', + resultField: 'period_id', + where: { + relation: '<>', + type: 'integer', + field: 'turma_turno_id' + } +}, 'filter'); + + +classApp.get('/', rqfCount.parse(), (req, res, next) => { + req.sql.field('COUNT(turma.id)', 'total') + .field("'Brasil'", 'name') + .field('turma.ano_censo', 'year') + .from('turma') + .group('turma.ano_censo') + .order('turma.ano_censo') + .where('(turma.tipo_turma_id >= 0 AND turma.tipo_turma_id <= 3 AND turma.tipo_atendimento_id is NULL) \ + OR ((turma.tipo_atendimento_id = 1 OR turma.tipo_atendimento_id = 2) AND turma.tipo_turma_id is NULL) '); + next(); +}, rqfCount.build(), query, addMissing(rqfCount), id2str.transform(), response('class')); + +module.exports = classApp; diff --git a/src/libs/routes_v2/classCount.js b/src/libs/routes_v2/classCount.js new file mode 100644 index 0000000000000000000000000000000000000000..7771632838dc5a09cb47f3400ddf5e055b15db23 --- /dev/null +++ b/src/libs/routes_v2/classCount.js @@ -0,0 +1,455 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const classCountApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValueToField({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'turma' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'turma' + } +}, 'dims').addValueToField({ + name: 'city', + table: 'municipio', + tableField: 'nome', + resultField: 'city_name', + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'turma' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'turma' + } +}, 'filter') +.addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'turma' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'turma' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'turma' + } +}).addValue({ + name: 'min_year', + table: 'turma', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'turma', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name:'adm_dependency', + table: 'turma', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}).addValue({ + name: 'location', + table: 'turma', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'rural_location', + table: 'turma', + tableField: 'localidade_area_rural', + resultField: 'rural_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localidade_area_rural' + } +}).addValue({ + name:'education_level_mod', + table: 'turma', + tableField: 'etapas_mod_ensino_segmento_id', + resultField: 'education_level_mod_id', + where: { + relation: '=', + type: 'integer', + field: 'etapas_mod_ensino_segmento_id' + } +}).addValue({ + name:'education_level_short', + table: 'turma', + tableField: 'etapa_resumida', + resultField: 'education_level_short_id', + where: { + relation: '=', + type: 'integer', + field: 'etapa_resumida' + } +}).addValue({ + name: 'adm_dependency_detailed', + table: 'turma', + tableField: 'dependencia_adm_priv', + resultField: 'adm_dependency_detailed_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_priv' + } +}).addValueToField({ + name: 'school', + table: 'escola_agregada', + tableField: ['nome_escola', 'id'], + resultField: ['school_name', 'school_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id', 'ano_censo'], + foreign: ['escola_id', 'ano_censo'], + foreignTable: 'turma' + } +}, 'dims').addValueToField({ + name: 'school', + table: 'escola_agregada', + tableField: 'nome_escola', + resultField: 'school_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id', 'ano_censo'], + foreign: ['escola_id', 'ano_censo'], + foreignTable: 'turma' + } +}, 'filter'); + +classCountApp.get('/year_range', (req, res, next) => { + req.sql.from('escola_agregada') + .field('MIN(escola_agregada.ano_censo)', 'start_year') + .field('MAX(escola_agregada.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +classCountApp.get('/years', (req, res, next) => { + req.sql.from('escola_agregada') + .field('DISTINCT escola_agregada.ano_censo', 'year'); + next(); +}, query, response('years')); + +classCountApp.get('/adm_dependency', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.admDependency(i) + }); + }; + next(); +}, response('adm_dependency')); + +classCountApp.get('/adm_dependency_detailed', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 6; ++i) { + req.result.push({ + id: i, + name: id2str.admDependencyPriv(i) + }); + }; + next(); +}, response('adm_dependency_detailed')); + +classCountApp.get('/location', (req, res, next) => { + req.result = [ + {id: 1, name: 'Urbana'}, + {id: 2, name: 'Rural'} + ]; + next(); +}, response('location')); + +classCountApp.get('/rural_location', (req, res, next) => { + req.result = [ + {id: 1, name: "Urbana"}, + {id: 2, name: "Rural"}, + {id: 3, name: "Rural - Área de assentamento"}, + {id: 4, name: "Rural - Terra indígena"}, + {id: 5, name: "Rural - Área remanescente de quilombos"}, + {id: 6, name: "Rural - Unidade de uso sustentável"} + ]; + next(); +}, response('rural_location')); + +classCountApp.get('/education_level_mod', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 10; ++i) { + req.result.push({ + id: i, + name: id2str.educationLevelMod(i) + }); + } + req.result.push({ + id: 99, + name: id2str.educationLevelMod(99) + }); + next(); +}, response('education_level_mod')); + +classCountApp.get('/education_level_short', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 7; ++i) { + req.result.push({ + id: i, + name: id2str.educationLevelShort(i) + }); + } + req.result.push({ + id: 99, + name: id2str.educationLevelShort(99) + }); + next(); +}, response('education_level_short')); + +classCountApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'turma\''); + next(); +}, query, response('source')); + +// Se a dimensão obrigatória do LDE (etapa de ensino) possui alguma etapa sem nenhum valor, então é criado um objeto +// com média 0.0 e é inserido no resultado. Usada para não quebrar a sequência de etapas na tabela do LDE. +function addNullFields(result) { + const firstYear = result[0].year; + var obj = result.filter(res => res.year == firstYear); + var prevFirstDimId = obj[0]; + obj.forEach((d) => { + if((d["education_level_mod_id"] > prevFirstDimId["education_level_mod_id"]) && (prevFirstDimId["education_level_mod_id"] != 10) && + (d["education_level_mod_id"] != prevFirstDimId["education_level_mod_id"] + 1)) { + let newObj = {}; + Object.keys(prevFirstDimId).forEach((key) => { + newObj[key] = prevFirstDimId[key]; + }); + newObj.education_level_mod_id = d["education_level_mod_id"] - 1; + newObj.education_level_mod_name = id2str.educationLevelMod(d["education_level_mod_id"] - 1); + newObj.average = 0.0; + result.splice(result.indexOf(prevFirstDimId) + 1, 0, newObj); + } + prevFirstDimId = d; + }); +} + +function addZeroFields(result) { + let i; + for (i=0; i < result.length; i++) { + let hasTotal = result[i].hasOwnProperty("total"); + if (hasTotal == true) { + result[i].average = 0.0; + result[i].median = 0.0; + result[i].stddev = 0.0; + result[i].first_qt = 0.0; + result[i].third_qt = 0.0; + } + } + return result; +} + +// SimCAQ +classCountApp.get('/count', rqf.parse(), (req, res, next) => { + req.sql.field("'Brasil'", 'name') + .field('turma.ano_censo', 'year') + .field('AVG(turma.num_matricula)', 'average') + .field('MEDIAN(turma.num_matricula)', 'median') + .field('STDDEV_POP(turma.num_matricula)', 'stddev') + .field('QUANTILE(turma.num_matricula, 0.25)', 'first_qt') + .field('QUANTILE(turma.num_matricula, 0.75)', 'third_qt') + .from('turma') + .group('turma.ano_censo') + .order('turma.ano_censo') + .where('turma.local_turma = 0 AND turma.dependencia_adm_id <= 3 AND ((turma.etapa_resumida >= 1 AND turma.etapa_resumida <= 7) OR turma.etapa_resumida = 99) AND turma.turma_turno_id <> 99') + next(); +}, rqf.build(), query, addMissing(rqf), id2str.transform(), response('class_count')); + +// LDE +// Essa rota não esta sendo usada. +// Ela está com defeito e quando é chamada cai o banco. +/* +classCountApp.get('/', rqf.parse(), (req, res, next) => { + // Faz a consulta do número de alunos pelas dimensões + if(("education_level_mod" in req.dims) || ("education_level_mod" in req.filter) || ("education_level_short" in req.dims)) { + req.sql.field("'Brasil'", 'name') + .field('turma.ano_censo', 'year') + .field('AVG(turma.num_matricula)', 'average') + .field('MEDIAN(turma.num_matricula)', 'median') + .field('STDDEV_POP(turma.num_matricula)', 'stddev') + .field('QUANTILE(turma.num_matricula, 0.25)', 'first_qt') + .field('QUANTILE(turma.num_matricula, 0.75)', 'third_qt') + .from('turma') + .group('turma.ano_censo') + .order('turma.ano_censo') + .where('turma.tipo_turma_id = 0 AND turma.etapas_mod_ensino_segmento_id >= 1 AND turma.etapas_mod_ensino_segmento_id <= 10'); + next(); + } else { + res.status(400); + next({ + status: 400, + message: 'Wrong/No filter specified' + }); + } +}, rqf.build(), query, id2str.transform(), (req, res, next) => { + req.partial = []; + + // Caso tenha apenas uma dimensão, o indicador possuirá uma linha de total + if((req.dims) && (req.dims.size == 1)) { + req.partial = req.result; + + // A linha de total deverá conter o valor total do ano que está no banco de dados, então usa o mesmo filtro de anos da consulta anterior + let yearFilter = {}; + if("min_year" in req.filter) + yearFilter.min_year = req.filter.min_year; + if("max_year" in req.filter) + yearFilter.max_year = req.filter.max_year; + + // Faz a consulta sem dimensões, do total do(s) ano(s) escolhido(s) + req.resetSql(); + req.dims = {}; + req.filter = yearFilter; + req.sql.field("'Brasil'", 'name') + .field('turma.ano_censo', 'year') + .field('AVG(turma.num_matricula)', 'average') + .field('MEDIAN(turma.num_matricula)', 'median') + .field('STDDEV_POP(turma.num_matricula)', 'stddev') + .field('QUANTILE(turma.num_matricula, 0.25)', 'first_qt') + .field('QUANTILE(turma.num_matricula, 0.75)', 'third_qt') + .from('turma') + .group('turma.ano_censo') + .order('turma.ano_censo') + .where('turma.tipo_turma_id = 0 AND turma.etapas_mod_ensino_segmento_id >= 1 AND turma.etapas_mod_ensino_segmento_id <= 10'); + } + next(); +}, rqf.build(), query, addMissing(rqf), id2str.transform(), (req, res, next) => { + // Se tem apenas uma dimensão + if(req.partial.length > 0) { + const yearClassCount = req.result; + req.result = req.partial; + + // Como a linha de total deve aparecer em um caso específico, ela é adicionada junto com a dimensão obrigatória + yearClassCount.forEach((result) => { + let obj = {}; + obj = result; + obj.education_level_mod_name = "Total"; + req.result.push(obj); + }) + } + // Caso tenha mais de uma dimensão, retorna a consulta só pelas dimensões, sem linha de total + else { + addNullFields(req.result); + req.result = addZeroFields(req.result); + } + + next(); +}, response('class_count')); +*/ + +module.exports = classCountApp; diff --git a/src/libs/routes_v2/classroom.js b/src/libs/routes_v2/classroom.js new file mode 100644 index 0000000000000000000000000000000000000000..a3d6ec7fef99fc0188086ac6cbd208746b7c4717 --- /dev/null +++ b/src/libs/routes_v2/classroom.js @@ -0,0 +1,277 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const classroomApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +let rqfCount = new ReqQueryFields(); + +//classroomApp.use(cache('15 day')); + + +// Complete range of the enrollments dataset. +// Returns a tuple of start and ending years of the complete enrollments dataset. +classroomApp.get('/year_range', (req, res, next) => { + req.sql.from('escola_agregada') + .field('MIN(escola_agregada.ano_censo)', 'start_year') + .field('MAX(escola_agregada.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +classroomApp.get('/years', (req, res, next) => { + req.sql.from('escola_agregada') + .field('DISTINCT escola_agregada.ano_censo', 'year'); + next(); +}, query, response('years')); + +classroomApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'escola_agregada\''); + next(); +}, query, response('source')); + +classroomApp.get('/adm_dependency', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.admDependency(i) + }); + }; + next(); +}, response('adm_dependency')); + +classroomApp.get('/adm_dependency_detailed', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 6; ++i) { + req.result.push({ + id: i, + name: id2str.admDependencyPriv(i) + }); + }; + next(); +}, response('adm_dependency_detailed')); + +classroomApp.get('/location', (req, res, next) => { + req.result = [ + {id: 1, name: 'Urbana'}, + {id: 2, name: 'Rural'} + ]; + next(); +}, response('location')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValueToField({ + name: 'school', + table: 'escola_agregada', + tableField: ['nome_escola', 'id'], + resultField: ['school_name', 'school_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + } +}, 'dims').addValueToField({ + name: 'school', + table: 'escola_agregada', + tableField: 'nome_escola', + resultField: 'school_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + } +}, 'filter').addValueToField({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'escola_agregada' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'escola_agregada' + } +}, 'dims').addValueToField({ + name: 'city', + table: 'municipio', + tableField: 'nome', + resultField: 'city_name', + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'escola_agregada' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'escola_agregada' + } +}, 'filter').addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'escola_agregada' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'escola_agregada' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'escola_agregada' + } +}).addValue({ + name: 'min_year', + table: 'escola_agregada', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'escola_agregada', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'adm_dependency', + table: 'escola_agregada', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}).addValue({ + name: 'adm_dependency_detailed', + table: 'escola_agregada', + tableField: 'dependencia_adm_priv', + resultField: 'adm_dependency_detailed_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_priv' + } +}).addValue({ + name: 'location', + table: 'escola_agregada', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}); + +classroomApp.get('/', cache('15 day'), rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('escola_agregada') + .field('SUM(escola_agregada.qtde_salas_utilizadas_dentro)', 'total') + .field("'Brasil'", 'name') + .field('escola_agregada.ano_censo', 'year') + .group('escola_agregada.ano_censo') + .order('escola_agregada.ano_censo') + .where('escola_agregada.situacao_funcionamento_pareada = 1 AND escola_agregada.local_func_predio_escolar = 1') + .where('escola_agregada.ensino_regular = 1 OR escola_agregada.ensino_eja = 1 OR escola_agregada.educacao_profissional = 1'); + next(); +}, query, addMissing(rqf), id2str.transform(), (req, res, next) => { + if (req.dims.location && req.result.length < 2) { // Garantimos que conterá as duas localizações no resultado para o simCAQ + let result = []; + for (let i = 1; i <= 2; i++) { + if (i !== req.result[0].location_id) { + let newObj = Object.assign({}, req.result[0]); + newObj.location_id = i; + newObj.total = 0; + newObj.location_name = (i == 1) ? "Urbana" : "Rural"; + result.push(newObj); + } + else { + result.push(req.result[0]); + } + } + + req.result = result; + } + + next(); +}, response('classroom')); + +module.exports = classroomApp; diff --git a/src/libs/routes/classroomCount.js b/src/libs/routes_v2/classroomCount.js similarity index 94% rename from src/libs/routes/classroomCount.js rename to src/libs/routes_v2/classroomCount.js index 038c6e4563f20b8348ff4244385eb202c9197f55..ea649bbfdf6a88c9ffbf58aafd062bd619467c31 100644 --- a/src/libs/routes/classroomCount.js +++ b/src/libs/routes_v2/classroomCount.js @@ -43,8 +43,6 @@ const cache = require('apicache').options({ debug: config.debug, statusCodes: {i let rqf = new ReqQueryFields(); -const fs = require('fs') - rqf.addField({ name: 'filter', field: false, @@ -54,22 +52,6 @@ rqf.addField({ field: true, where: false }).addValueToField({ - name: 'city', - table: 'municipio', - tableField: 'nome', - resultField: 'city_name', - where: { - relation: '=', - type: 'integer', - field: 'municipio_id', - table: '@' - }, - join: { - primary: 'id', - foreign: 'municipio_id', - foreignTable: '@' - } -}, 'filter').addValueToField({ name: 'city', table: 'municipio', tableField: ['nome', 'id'], @@ -85,22 +67,6 @@ rqf.addField({ foreignTable: '@' } }, 'dims').addValueToField({ - name: 'state', - table: 'estado', - tableField: 'nome', - resultField: 'state_name', - where: { - relation: '=', - type: 'integer', - field: 'estado_id', - table: '@' - }, - join: { - primary: 'id', - foreign: 'estado_id', - foreignTable: '@' - } -}, 'filter').addValueToField({ name: 'state', table: 'estado', tableField: ['nome', 'id'], @@ -117,7 +83,7 @@ rqf.addField({ } }, 'dims').addValueToField({ name: 'school', - table: 'escola', + table: 'escola_agregada', tableField: ['nome_escola', 'id'], resultField: ['school_name', 'school_id'], where: { @@ -165,39 +131,9 @@ rqf.addField({ type: 'integer', field: 'ano_censo' } -}).addValue({ - name: 'school_year', - table: '@', - tableField: 'serie_ano_id', - resultField: 'school_year_id', - where: { - relation: '=', - type: 'integer', - field: 'serie_ano_id' - } -}).addValue({ - name: 'location', - table: '@', - tableField: 'localizacao_id', - resultField: 'location_id', - where: { - relation: '=', - type: 'integer', - field: 'localizacao_id' - } -}).addValue({ - name: 'period', - table: '@', - tableField: 'turma_turno_id', - resultField: 'period_id', - where: { - relation: '=', - type: 'integer', - field: 'turma_turno_id' - } }).addValue({ name: 'school_building', - table: 'escola', + table: '@', tableField: 'local_func_predio_escolar', resultField: 'school_building', where: { @@ -207,7 +143,7 @@ rqf.addField({ } }).addValue({ name: 'night_time', - table: 'matricula', + table: '@', tableField: 'periodo_noturno', resultField: 'night_time', where: { @@ -217,7 +153,7 @@ rqf.addField({ } }).addValue({ name: 'formation_level', - table: 'docente_por_formacao', + table: '@', tableField: 'tipo_formacao', resultField: 'formation_level', where: { @@ -237,7 +173,7 @@ rqf.addField({ } }, 'filter') .addValue({ name: 'integral_time', - table: 'matricula', + table: '@', tableField: 'tempo_integral', resultField: 'integral_time_id', where: { @@ -247,7 +183,7 @@ rqf.addField({ } }).addValue({ name: 'education_level_short', - table: 'matricula', + table: '@', tableField: 'etapa_resumida', resultField: 'education_level_short_id', where: { @@ -255,6 +191,26 @@ rqf.addField({ type: 'integer', field: 'etapa_resumida' } +}).addValue({ + name: 'location', + table: '@', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'school_year', + table: '@', + tableField: 'ano_censo', + resultField: 'school_year', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo' + } }); classroomCountApp.post('/', rqf.parse(), (req, res, next) => { @@ -275,14 +231,18 @@ classroomCountApp.post('/', rqf.parse(), (req, res, next) => { req.dims.school_year = true; req.dims.location = true; + + req.sql.field('sum(dia_total)', 'total_day') .field('sum(noite_total)', 'total_night') .field("'Brasil'", 'name') - .field('matricula_por_localizacao.ano_censo', 'year') - .from('matricula_por_localizacao') - .where('matricula_por_localizacao.serie_ano_id < 15') - .group('matricula_por_localizacao.ano_censo') - .order('matricula_por_localizacao.ano_censo') + .field('simcaq_matricula_por_localizacao.ano_censo', 'year') + .field('simcaq_matricula_por_localizacao.serie_ano_id', 'school_year_id') + .from('simcaq_matricula_por_localizacao') + .where('simcaq_matricula_por_localizacao.serie_ano_id < 15') + .group('simcaq_matricula_por_localizacao.ano_censo') + .group('simcaq_matricula_por_localizacao.serie_ano_id') + .order('simcaq_matricula_por_localizacao.ano_censo') next(); }, rqf.build(), query, id2str.transform(), (req, res, next) => { @@ -312,27 +272,50 @@ classroomCountApp.post('/', rqf.parse(), (req, res, next) => { }; } } - + delete req.dims; delete req.filter; req.resetSql(); next(); }, rqf.parse(), (req, res, next) => { + /* + select + sum(escola_agregada.num_salas_utilizadas) as soma, + 'Brasil' as name, + ano_censo, + estado_id, + municipio_id, + localizacao_id, + local_func_predio_escolar + from escola_agregada + where + situacao_de_funcionamento = 1 and + dependencia_adm_id IN (2, 3) and + escola_agregada.ensino_regular = 1 OR escola_agregada.ensino_eja = 1 OR escola_agregada.educacao_profissional = 1 + group by + name, + ano_censo, + estado_id, + municipio_id, + localizacao_id, + local_func_predio_escolar + */ + req.dims.state = true; req.dims.city = true; req.dims.location = true; req.dims.school_building = true; - - req.sql.field('SUM(escola.qtde_salas_utilizadas_dentro)', 'total') + + req.sql.field('SUM(escola_agregada.num_salas_utilizadas)', 'total') .field("'Brasil'", 'name') - .field('escola.ano_censo', 'year') - .from('escola') - .group('escola.ano_censo') - .order('escola.ano_censo') - .where('escola.situacao_de_funcionamento = 1') - .where('escola.dependencia_adm_id < 4') - .where('escola.ensino_regular = 1 OR escola.ensino_eja = 1 OR escola.educacao_profissional = 1'); + .field('escola_agregada.ano_censo', 'year') + .from('escola_agregada') + .group('escola_agregada.ano_censo') + .order('escola_agregada.ano_censo') + .where('escola_agregada.situacao_de_funcionamento = 1') + .where('escola_agregada.dependencia_adm_id IN (2,3)') + .where('escola_agregada.ensino_regular = 1 OR escola_agregada.ensino_eja = 1 OR escola_agregada.educacao_profissional = 1'); next(); }, rqf.build(), query, id2str.transform(), (req, res, next) => { @@ -381,15 +364,23 @@ classroomCountApp.post('/', rqf.parse(), (req, res, next) => { req.teacherCalc = true; } - req.dims.state = true; + /* + select sum(num_docentes), + 'Brasil' as name, + ano_censo, + estado_id, + municipio_id + from simcaq_docente_agregada + */ + req.dims.city = true; - req.dims.formation_level = true; - req.sql.field('count(distinct docente_por_formacao.id_docente)', 'total') + req.dims.state = true; + req.sql.field('SUM(simcaq_docente_agregada.num_docentes)', 'total') .field("'Brasil'", 'name') - .field('docente_por_formacao.ano_censo', 'year') - .from('docente_por_formacao') - .group('docente_por_formacao.ano_censo') - .order('docente_por_formacao.ano_censo'); + .field('simcaq_docente_agregada.ano_censo', 'year') + .from('simcaq_docente_agregada') + .group('simcaq_docente_agregada.ano_censo') + .order('simcaq_docente_agregada.ano_censo'); next(); }, rqf.build(), query, id2str.transform(), (req, res, next) => { @@ -400,16 +391,31 @@ classroomCountApp.post('/', rqf.parse(), (req, res, next) => { req.resetSql(); next(); }, rqf.parse(), (req, res, next) => { + /* + select + SUM(num_matriculas) as num_matriculas, + ano_censo, + estado_id, + municipio_id, + etapa_resumida, + tempo_integral + from simcaq_matricula_agregada + group by + ano_censo, + estado_id, + municipio_id, + etapa_resumida, + tempo_integral + */ req.dims.state = true; req.dims.city = true; req.dims.education_level_short = true; req.dims.integral_time = true; - req.sql.field('COUNT(*)', 'total') - .field('matricula.ano_censo', 'year') - .from('matricula') - .group('matricula.ano_censo') - .order('matricula.ano_censo') - .where('((matricula.tipo<=3 OR matricula.tipo IS NULL) AND (matricula.tipo_atendimento_turma IS NULL OR matricula.tipo_atendimento_turma <= 2) AND matricula.turma_turno_id <> 99)'); + req.sql.field('SUM(num_matriculas)', 'total') + .field('simcaq_matricula_agregada.ano_censo', 'year') + .from('simcaq_matricula_agregada') + .group('simcaq_matricula_agregada.ano_censo') + .order('simcaq_matricula_agregada.ano_censo'); next(); }, rqf.build() ,query, id2str.transform(), (req, res, next) => { // constrói objeto de tempo integral e calcula diagnósticos @@ -434,6 +440,8 @@ classroomCountApp.post('/', rqf.parse(), (req, res, next) => { if (req.dims.school){ obj.school_id = integral_time.school_id obj.school_name = integral_time.school_name + obj.adm_dependency_id = integral_time.adm_dependency_id + obj.adm_dependency_name = integral_time.adm_dependency_name } req.integral_time[code] = obj currentCodeObj = obj; @@ -519,7 +527,9 @@ classroomCountApp.post('/', rqf.parse(), (req, res, next) => { }; if (req.dims.school){ obj.school_id = classroom.school_id, - obj.school_name = classroom.school_name + obj.school_name = classroom.school_name, + obj.adm_dependency_id = classroom.adm_dependency_id, + obj.adm_dependency_name = classroom.adm_dependency_name } if (req.teacherCalc) obj.percentage_teacher_career = []; diff --git a/src/libs/routes_v2/courseCount.js b/src/libs/routes_v2/courseCount.js new file mode 100644 index 0000000000000000000000000000000000000000..404ed2eb09b56efe5b6bd1caaa643ca1e225d3a8 --- /dev/null +++ b/src/libs/routes_v2/courseCount.js @@ -0,0 +1,814 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); +const { join } = require('lodash'); + +const courseCountApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const config = require(`${libs}/config`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +let rqf = new ReqQueryFields(); + +let rqfMapfor = new ReqQueryFields(); + +courseCountApp.get('/upper_adm_dependency', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 7; ++i) { + req.result.push({ + id: i, + name: id2str.upperAdmDependency(i) + }); + }; + next(); +}, response('upper_adm_dependency')); + +courseCountApp.get('/years', (req, res, next) => { + req.sql.from('curso_ens_superior') + .field('DISTINCT curso_ens_superior.ano_censo', 'year') + .where('curso_ens_superior.ano_censo > 2010'); + next(); +}, query, response('years')); + +courseCountApp.get('/year_range', (req, res, next) => { + req.sql.from('curso_ens_superior') + .field('MIN(curso_ens_superior.ano_censo)', 'start_year') + .field('MAX(curso_ens_superior.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +courseCountApp.get('/academic_organization', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 5; ++i) { + req.result.push({ + id: i, + name: id2str.academicOrganization(i) + }); + }; + next(); +}, response('academic_organization')); + +courseCountApp.get('/ocde_geral', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 8; ++i) { + req.result.push({ + id: i, + name: id2str.ocdeGeral(i) + }); + }; + next(); +}, response('ocde_geral')); + +courseCountApp.get('/ocde_specific', (req, res, next) => { + req.result = []; + const defaultCase = null; + for(let i = 1; i <= 86; ++i) { + let obj = { + id: i, + name: id2str.ocdeSpecific(i) + }; + if (obj.name !== id2str.ocdeSpecific(defaultCase)){ + req.result.push(obj); + } + }; + req.result.push({ + id: defaultCase, + name: id2str.ocdeSpecific(defaultCase) + }); + next(); +}, response('ocde_specific')); + +courseCountApp.get('/ocde_detailed', (req, res, next) => { + req.result = []; + const defaultCase = null; + for(let i = 142; i <= 863; ++i) { + let obj = { + id: i, + name: id2str.ocdeDetailed(i) + }; + if (obj.name !== id2str.ocdeDetailed(defaultCase)){ + req.result.push(obj); + } + }; + req.result.push({ + id: defaultCase, + name: id2str.ocdeDetailed(defaultCase) + }); + next(); +}, response('ocde_detailed')); + +courseCountApp.get('/cine_geral', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 10; ++i) { + req.result.push({ + id: i, + name: id2str.cineGeral(i) + }); + }; + next(); +}, response('cine_geral')); + +courseCountApp.get('/cine_specific', (req, res, next) => { + req.result = []; + const defaultCase = null; + for(let i = 1; i <= 104; ++i) { + let obj = { + id: i, + name: id2str.cineSpecific(i) + }; + if (obj.name !== id2str.cineSpecific(defaultCase)){ + req.result.push(obj); + } + }; + req.result.push({ + id: defaultCase, + name: id2str.cineSpecific(defaultCase) + }); + next(); +}, response('cine_specific')); + +courseCountApp.get('/cine_detailed', (req, res, next) => { + req.result = []; + const defaultCase = null; + for(let i = 11; i <= 1041; ++i) { + let obj = { + id: i, + name: id2str.cineDetailed(i) + }; + if (obj.name !== id2str.cineDetailed(defaultCase)){ + req.result.push(obj); + } + }; + req.result.push({ + id: defaultCase, + name: id2str.cineDetailed(defaultCase) + }); + next(); +}, response('cine_detailed')); + +courseCountApp.get('/academic_level', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.academicLevel(i) + }); + }; + next(); +}, response('academic_level')); + +courseCountApp.get('/upper_education_mod', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 2; ++i) { + req.result.push({ + id: i, + name: id2str.upperEducationMod(i) + }); + }; + next(); +}, response('upper_education_mod')); + +courseCountApp.get('/is_free', (req, res, next) => { + req.result = [ + {id: null, name: 'Não Classificado'}, + {id: 0, name: 'Não'}, + {id: 1, name: 'Sim'} + ]; + next(); +}, response('is_free')); + +courseCountApp.get('/night_time', (req, res, next) => { + req.result = [{ + id: 9, + name: id2str.nightTime(9) + }]; + for(let i = 0; i <= 1; ++i) { + req.result.push({ + id: i, + name: id2str.nightTime(i) + }) + } + next(); +}, response('night_time')); + +courseCountApp.get('/university', (req, res, next) => { + req.sql.from('curso_ens_superior') + .field('DISTINCT curso_ens_superior.nome_ies', 'nome') + .field('curso_ens_superior.cod_ies', 'cod') + next(); +}, query, response('university')); + +courseCountApp.get('/localoffer', (req, res, next) => { + req.sql.from('localoferta_ens_superior', 'l') + .field('DISTINCT l.nome', 'localoffer_name') + .field('l.cod_local_oferta', 'localoffer_id'); + next(); +}, query, response('localoffer')); + + +rqfMapfor.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValueToField({ + name: 'state', + table: 'municipio', + tableField: 'estado_id', + resultField: 'state_id', + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'cod_municipio', + foreignTable: 'localoferta_ens_superior' + } +}, 'filter').addValue({ + name: 'mesoregion', + table: 'municipio', + tableField: ['nome_mesorregiao', 'mesorregiao_id'], + resultField: ['mesoregion_name', 'mesoregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'mesorregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'cod_municipio', + foreignTable: 'localoferta_ens_superior' + } +}).addValue({ + name: 'microregion', + table: 'municipio', + tableField: ['nome_microrregiao', 'microrregiao_id'], + resultField: ['microregion_name', 'microregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'microrregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'cod_municipio', + foreignTable: 'localoferta_ens_superior' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['id', 'nome'], + resultField: ['city_id', 'city_name'], + where: { + relation: '=', + type: 'integer', + field: 'id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'cod_municipio', + foreignTable: 'localoferta_ens_superior' + } +}).addValue({ + name:'academic_level', + table: 'curso_ens_superior', + tableField: 'cod_grau_academico', + resultField: 'academic_level_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_grau_academico' + } +}).addValue({ + name: 'min_year', + table: 'localoferta_ens_superior', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: 'localoferta_ens_superior', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'localoferta_ens_superior', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: 'localoferta_ens_superior', + field: 'ano_censo' + } +}).addValue({ + name:'course', + table: 'curso_ens_superior', + tableField: 'nome_curso', + resultField: 'course_name', + where: { + relation: 'LIKE', + type: 'string', + field: 'nome_curso' + } +}).addValueToField({ + name: 'campi', + table: 'localoferta_ens_superior', + tableField: ['cod_local_oferta', 'nome'], + resultField: ['campi_id', 'campi_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_local_oferta', + table: 'localoferta_ens_superior' + } +}, 'filter').addValue({ + name:'upper_adm_dependency', + table: 'curso_ens_superior', + tableField: 'par_categoria_administrativa', + resultField: 'upper_adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'par_categoria_administrativa' + } +}).addValue({ + name:'upper_education_mod', + table: 'curso_ens_superior', + tableField: 'cod_modalidade_ensino', + resultField: 'upper_education_mod_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_modalidade_ensino' + } +}).addValue({ + name:'academic_organization', + table: 'curso_ens_superior', + tableField: 'cod_organizacao_academica', + resultField: 'academic_organization_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_organizacao_academica' + } +}) + + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'region', + table: 'localoferta_ens_superior', + tableField: ['nome_regiao', 'cod_regiao'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'cod_regiao', + table: 'localoferta_ens_superior' + }, + join: { + primary: ['ano_censo', 'cod_curso'], + foreign: ['ano_censo', 'cod_curso'], + foreignTable: 'curso_ens_superior' + } +}).addValue({ + name: 'state', + table: 'localoferta_ens_superior', + tableField: ['sigla_uf_t', 'cod_uf_t'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'cod_uf', + table: 'localoferta_ens_superior' + }, + join: { + primary: ['ano_censo', 'cod_curso'], + foreign: ['ano_censo', 'cod_curso'], + foreignTable: 'curso_ens_superior' + } +}).addValue({ + name: 'mesoregion', + table: 'municipio', + tableField: ['nome_mesorregiao', 'mesorregiao_id'], + resultField: ['mesoregion_name', 'mesoregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'mesorregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'cod_municipio_curso', + foreignTable: 'curso_ens_superior' + } +}).addValue({ + name: 'microregion', + table: 'municipio', + tableField: ['nome_microrregiao', 'microrregiao_id'], + resultField: ['microregion_name', 'microregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'microrregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'cod_municipio_curso', + foreignTable: 'curso_ens_superior' + } +}).addValue({ + name: 'city', + table: 'localoferta_ens_superior', + tableField: ['cod_municipio_t', 'nome_municipio_t'], + resultField: ['city_id', 'city_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_municipio', + table: 'localoferta_ens_superior' + }, + join: { + primary: ['ano_censo', 'cod_curso'], + foreign: ['ano_censo', 'cod_curso'], + foreignTable: 'curso_ens_superior' + } +}).addValue({ + name: 'localoffer', + table: 'localoferta_ens_superior', + tableField: ['cod_local_oferta', 'nome'], + resultField: ['localoffer_id', 'localoffer_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_curso', + table: 'curso_ens_superior' + }, + join: { + primary: ['ano_censo', 'cod_curso'], + foreign: ['ano_censo', 'cod_curso'], + foreignTable: 'curso_ens_superior' + } +}).addValue({ + name: 'campi', + table: 'localoferta_ens_superior', + tableField: ['cod_local_oferta', 'nome'], + resultField: ['campi_id', 'campi_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_curso', + table: 'curso_ens_superior' + }, + join: { + primary: ['ano_censo', 'cod_curso'], + foreign: ['ano_censo', 'cod_curso'], + foreignTable: 'curso_ens_superior' + } +}).addValue({ + name: 'university', + table: 'curso_ens_superior', + tableField: ['cod_ies', 'nome_ies'], + resultField: ['university_id', 'university_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_ies' + } +}).addValue({ + name: 'universityLocalOffer', + table: 'curso_ens_superior', + tableField: ['cod_ies', 'nome_ies'], + resultField: ['university_id', 'university_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_ies' + } +}).addValue({ + name:'upper_adm_dependency', + table: 'curso_ens_superior', + tableField: 'par_categoria_administrativa', + resultField: 'upper_adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'par_categoria_administrativa' + } +}).addValue({ + name:'academic_organization', + table: 'curso_ens_superior', + tableField: 'cod_organizacao_academica', + resultField: 'academic_organization_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_organizacao_academica' + } +}).addValue({ + name:'course', + table: 'curso_ens_superior', + tableField: 'nome_curso', + resultField: 'course_name', + where: { + relation: 'LIKE', + type: 'string', + field: 'nome_curso' + } +}).addValue({ + name:'ocde_specific', + table: 'curso_ens_superior', + tableField: ['cod_ocde_area_especifica', 'nome_ocde_area_especifica'], + resultField: ['ocde_specific_id', 'ocde_specific_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_ocde_area_especifica' + } +}).addValue({ + name:'ocde_geral', + table: 'curso_ens_superior', + tableField: ['cod_ocde_area_geral', 'nome_ocde_area_geral'], + resultField: ['ocde_geral_id', 'ocde_geral_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_ocde_area_geral' + } +}).addValue({ + name:'ocde_detailed', + table: 'curso_ens_superior', + tableField: ['cod_ocde_area_detalhada', 'nome_ocde_area_detalhada'], + resultField: ['ocde_detailed_id', 'ocde_detailed_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_ocde_area_detalhada' + } +}).addValue({ + name:'cine_specific', + table: 'curso_ens_superior', + tableField: ['cod_cine_area_especifica', 'nome_cine_area_especifica'], + resultField: ['cine_specific_id', 'cine_specific_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_cine_area_especifica' + } +}).addValue({ + name:'cine_geral', + table: 'curso_ens_superior', + tableField: ['cod_cine_area_geral', 'nome_cine_area_geral'], + resultField: ['cine_geral_id', 'cine_geral_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_cine_area_geral' + } +}).addValue({ + name:'cine_detailed', + table: 'curso_ens_superior', + tableField: ['cod_cine_area_detalhada', 'nome_cine_area_detalhada'], + resultField: ['cine_detailed_id', 'cine_detailed_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_cine_area_detalhada' + } +}).addValue({ + name:'academic_level', + table: 'curso_ens_superior', + tableField: 'cod_grau_academico', + resultField: 'academic_level_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_grau_academico' + } +}).addValue({ + name:'upper_education_mod', + table: 'curso_ens_superior', + tableField: 'cod_modalidade_ensino', + resultField: 'upper_education_mod_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_modalidade_ensino' + } +}).addValue({ + name:'is_free', + table: 'curso_ens_superior', + tableField: 'gratuito', + resultField: 'is_free_id', + where: { + relation: '=', + type: 'boolean', + field: 'gratuito' + } +}).addValue({ + name:'night_time', + table: 'curso_ens_superior', + tableField: 'noturno_curso_t', + resultField: 'night_time_id', + where: { + relation: '=', + type: 'integer', + field: 'noturno_curso_t' + } +}).addValue({ + name:'situation', + table: 'curso_ens_superior', + tableField: 'cod_situacao_curso', + resultField: 'situacao_curso_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_situacao_curso' + } +}).addValue({ + name:'year', + table: 'curso_ens_superior', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'min_year', + table: 'curso_ens_superior', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: 'curso_ens_superior', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'curso_ens_superior', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: 'curso_ens_superior', + field: 'ano_censo' + } +}) + +courseCountApp.get('/count_by_name', rqfMapfor.parse(), (req, res, next) => { + req.sql.from('localoferta_ens_superior') + .field('COUNT(DISTINCT localoferta_ens_superior.cod_curso)', 'total') + .field('localoferta_ens_superior.ano_censo', 'year') + .join ('curso_ens_superior ON (localoferta_ens_superior.cod_curso = curso_ens_superior.cod_curso) AND (localoferta_ens_superior.ano_censo = curso_ens_superior.ano_censo)') + .where('curso_ens_superior.cod_nivel_academico = 1') + .where('curso_ens_superior.tipo_atributo_ingresso <> 1 OR curso_ens_superior.tipo_atributo_ingresso is NULL') + .group('localoferta_ens_superior.ano_censo') + .order('localoferta_ens_superior.ano_censo') + + next(); +}, rqfMapfor.build(), query, (req, res, next) =>{ + if ('course' in req.dims){ + var total_course = req.result.reduce((total, cur) => {return total += cur.total}, 0) + for (var course of req.result){ + course.percentage = Number((( course.total / total_course ) * 100).toFixed(2)) + } + } + next(); +}, id2str.transform(), response('count_by_name')); + +courseCountApp.get('/', rqf.parse(), (req, res, next) => { + if ("localoffer" in req.dims || "campi" in req.dims) { + if ("university" in req.dims || "universityLocalOffer" in req.dims) { + req.sql.from('curso_ens_superior') + .field('curso_ens_superior.ano_censo', 'year') + .field('COUNT(localoferta_ens_superior.cod_local_oferta)', 'total') + .where('curso_ens_superior.tipo_atributo_ingresso <> 1 OR curso_ens_superior.tipo_atributo_ingresso is NULL') + .where('curso_ens_superior.cod_nivel_academico = 1') + .group('curso_ens_superior.ano_censo') + .order('curso_ens_superior.ano_censo') + .order('localoferta_ens_superior.cod_local_oferta'); + } else { + req.sql.from('curso_ens_superior') + .field('curso_ens_superior.ano_censo', 'year') + .field('COUNT(localoferta_ens_superior.cod_local_oferta)', 'total') + .field('localoferta_ens_superior.cod_ies', 'university_id') + .field('curso_ens_superior.nome_ies', 'university_name') + .where('curso_ens_superior.tipo_atributo_ingresso <> 1 OR curso_ens_superior.tipo_atributo_ingresso is NULL') + .where('curso_ens_superior.cod_nivel_academico = 1') + .group('curso_ens_superior.ano_censo') + .group('localoferta_ens_superior.cod_ies') + .group('curso_ens_superior.nome_ies') + .order('curso_ens_superior.ano_censo') + .order('localoferta_ens_superior.cod_local_oferta'); + } + } else if (("state" in req.dims) || ("city" in req.dims) || ("microregion" in req.dims) || ("mesoregion" in req.dims) || ("region" in req.dims) || + ("state" in req.filter) || ("city" in req.filter) || ("microregion" in req.filter) || ("mesoregion" in req.filter) || ("region" in req.filter) ) { + if ("course" in req.dims){ + req.sql.from('curso_ens_superior') + .field('COUNT(*)', 'total') + .field("'Brasil'", 'name') + .field('curso_ens_superior.ano_censo', 'year') + .group('curso_ens_superior.ano_censo') + .order('curso_ens_superior.ano_censo') + .where('curso_ens_superior.cod_nivel_academico = 1') + } + else{ + req.sql.from('curso_ens_superior') + .field('COUNT(DISTINCT curso_ens_superior.cod_curso)', 'total') + .field("'Brasil'", 'name') + .field('curso_ens_superior.ano_censo', 'year') + .group('curso_ens_superior.ano_censo') + .order('curso_ens_superior.ano_censo') + .where('curso_ens_superior.tipo_atributo_ingresso <> 1 OR curso_ens_superior.tipo_atributo_ingresso is NULL') + .where('curso_ens_superior.cod_nivel_academico = 1'); + } + + } else if ("university" in req.dims || "universityLocalOffer" in req.dims) { + req.sql.from('curso_ens_superior') + .field('COUNT(curso_ens_superior.cod_curso)', 'total') + .field("'Brasil'", 'name') + .field('curso_ens_superior.ano_censo', 'year') + .group('curso_ens_superior.cod_ies') + .group('curso_ens_superior.ano_censo') + .order('curso_ens_superior.cod_ies') + .order('curso_ens_superior.ano_censo') + .where('curso_ens_superior.tipo_atributo_ingresso <> 1 OR curso_ens_superior.tipo_atributo_ingresso is NULL') + .where('curso_ens_superior.cod_nivel_academico = 1'); + } else { + req.sql.from('curso_ens_superior') + .field('COUNT(curso_ens_superior.cod_curso)', 'total') + .field("'Brasil'", 'name') + .field('curso_ens_superior.ano_censo', 'year') + .group('curso_ens_superior.ano_censo') + .order('curso_ens_superior.ano_censo') + .where('curso_ens_superior.tipo_atributo_ingresso <> 1 OR curso_ens_superior.tipo_atributo_ingresso is NULL') + .where('curso_ens_superior.cod_nivel_academico = 1'); + } + next(); +}, rqf.build(), query, (req, res, next) =>{ + if ('course' in req.dims){ + var total_course = req.result.reduce((total, cur) => {return total += cur.total}, 0) + for (var course of req.result){ + course.percentage = Number((( course.total / total_course ) * 100).toFixed(2)) + } + } + next(); +}, id2str.transform(), addMissing(rqf), response('course_count')); + +module.exports = courseCountApp; diff --git a/src/libs/routes_v2/courseStudents.js b/src/libs/routes_v2/courseStudents.js new file mode 100644 index 0000000000000000000000000000000000000000..77180cb2b23489df7f2ebf74c57cc0471fddbc3e --- /dev/null +++ b/src/libs/routes_v2/courseStudents.js @@ -0,0 +1,201 @@ +const express = require('express'); + +const courseStudentsApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const response = require(`${libs}/middlewares/response`); + +const id2str = require(`${libs}/middlewares/id2str`); + +let rqf = new ReqQueryFields(); + +courseStudentsApp.get('/enrolled_vacancies_freshmen', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 3; ++i) { + req.result.push({ + id: i, + name: id2str.enrolledVacanciesFreshmen(i) + }); + }; + next(); +}, response('enrolled_vacancies_freshmen')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}) +.addValueToField({ + name: 'state', + table: 'ies_ens_superior', + tableField: 'cod_uf_ies', + resultField: 'state_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_uf_ies', + table: 'ies_ens_superior' + } +}, 'filter') +.addValueToField({ + name: 'min_year', + table: 'curso_ens_superior', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo', + table: 'curso_ens_superior' + } +}, 'filter') +.addValueToField({ + name: 'max_year', + table: 'curso_ens_superior', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo', + table: 'ies_ens_superior' + } +}, 'filter') +.addValue({ + name: 'upper_adm_dependency', + table: 'curso_ens_superior', + tableField: 'par_categoria_administrativa', + resultField: 'upper_adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'par_categoria_administrativa', //cod_categoria_administrativa + table: 'curso_ens_superior' + } +}) +.addValue({ + name: 'course', + table: 'curso_ens_superior', + tableField: 'nome_curso', + resultField: 'course_name', + where: { + relation: '=', + type: 'string', + field: 'nome_curso', + table: 'curso_ens_superior' + } +}) +.addValue({ + name: 'upper_education_mod', + table: 'curso_ens_superior', + tableField: 'cod_modalidade_ensino', + resultField: 'upper_education_mod_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_modalidade_ensino', + table: 'curso_ens_superior' + } +}) +.addValue({ + name: 'academic_organization', + table: 'curso_ens_superior', + tableField: 'cod_organizacao_academica', + resultField: 'academic_organization_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_organizacao_academica', + table: 'curso_ens_superior' + } +}) +.addValue({ + name: 'mesoregion', + table: 'municipio', + tableField: ['nome_mesorregiao', 'mesorregiao_id'], + resultField: ['mesoregion_name', 'mesoregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'mesorregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'cod_municipio_ies', + foreignTable: 'ies_ens_superior' + } +}) +.addValue({ + name: 'microregion', + table: 'municipio', + tableField: ['nome_microrregiao', 'microrregiao_id'], + resultField: ['microregion_name', 'microregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'microrregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'cod_municipio_ies', + foreignTable: 'ies_ens_superior' + } +}) +.addValue({ + name: 'city', + table: 'municipio', + tableField: ['id', 'nome'], + resultField: ['city_id', 'city_name'], + where: { + relation: '=', + type: 'integer', + field: 'id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'cod_municipio_ies', + foreignTable: 'ies_ens_superior' + } +}) + + + +courseStudentsApp.get('/', rqf.parse(), (req, res, next) => { + req.sql.field("curso_ens_superior.ano_censo", "year") + .field("SUM(curso_ens_superior.quantidade_inscritos_total)", "inscritos_total") + .field("SUM(curso_ens_superior.quantidade_vagas_totais)", "vagas_totais") + .field("SUM(curso_ens_superior.quantidade_ingresso_curso)", "ingresso_curso") + .from("curso_ens_superior") + .join("ies_ens_superior ON curso_ens_superior.ano_censo = ies_ens_superior.ano_censo AND curso_ens_superior.cod_ies = ies_ens_superior.cod_ies") + .where("curso_ens_superior.cod_nivel_academico = 1") + .where("curso_ens_superior.cod_grau_academico = 2 OR curso_ens_superior.cod_grau_academico = 4") + .group("curso_ens_superior.ano_censo") + .order("curso_ens_superior.ano_censo") + next(); + +}, rqf.build(), query, (req, res, next) => { + for (var res of req.result){ + res.inscritos_total = Number(res.inscritos_total); + res.vagas_totais = Number(res.vagas_totais); + res.ingresso_curso = Number(res.ingresso_curso); + res.total = null; + } + + next(); +}, id2str.transform(), response('course_students')) + +module.exports = courseStudentsApp; diff --git a/src/libs/routes_v2/cub.js b/src/libs/routes_v2/cub.js new file mode 100644 index 0000000000000000000000000000000000000000..cfc2848a19ef2f831c6562a89d5fd5ea7f938b22 --- /dev/null +++ b/src/libs/routes_v2/cub.js @@ -0,0 +1,227 @@ +const express = require('express'); + +const cubApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const request = require(`request`); + +const config = require(`${libs}/config`); + +const passport = require('passport'); + +const download = require(`${libs}/middlewares/downloadDatabase`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); +let rqfCount = new ReqQueryFields(); + +cubApp.get('/year_range', (req, res, next) => { + req.sql.from('cub') + .field('MIN(cub.ano_censo)', 'start_year') + .field('MAX(cub.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +cubApp.get('/years', (req, res, next) => { + req.sql.from('cub') + .field('DISTINCT cub.ano_censo', 'year'); + next(); +}, query, response('years')); + +cubApp.get('/months', (req, res, next) => { + req.sql.from('cub') + .field('DISTINCT cub.mes_censo', 'month'); + next(); +}, query, response('months')); + +cubApp.get('/years_months', (req, res, next) => { + req.sql.from('cub') + .field('DISTINCT cub.ano_censo AS "year", cub.mes_censo AS "month"'); + next(); +}, query, response('years_months')); + +cubApp.get('/price_type', (req, res, next) => { + req.sql.from('cub') + .field('DISTINCT cub.tipo_preco', 'price_type'); + next(); +}, query, response('price_type')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['sigla', 'id'], + resultField: ['sigla_uf', 'cod_uf'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'cub' + }, + // join: { + // primary: 'id', + // foreign: 'estado_id', + // foreignTable: 'cub' + // } +}).addValue({ + name: 'min_year', + table: 'cub', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: 'cub', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'cub', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: 'cub', + field: 'ano_censo' + } +}).addValue({ + name: 'min_month', + table: 'cub', + tableField: 'mes_censo', + resultField: 'month', + where: { + relation: '>=', + type: 'integer', + table: 'cub', + field: 'mes_censo' + } +}).addValue({ + name: 'max_month', + table: 'cub', + tableField: 'mes_censo', + resultField: 'month', + where: { + relation: '<=', + type: 'integer', + table: 'cub', + field: 'mes_censo' + } +}); + +cubApp.get('/last_state_values', rqf.parse(), rqf.build(), (req, res, next) => { + + var price_by_id = squel.select().from('cub') + .field('estado_id') + .field('MAX(ano_censo*100 + mes_censo)', 'ano_censo') + .group('estado_id') + + if (req.filter.size || req.dims.size){ + if ('state' in req.filter || 'state' in req.dims){ + //req.sql = states + req.sql.from('cub') + .field('cub.ano_censo', 'ano') + .field('cub.mes_censo', 'mes') + .field('cub.tipo_preco', 'tipo_preco') + .field('cub.preco', 'preco') + .join( + price_by_id, + 'sub', + 'cub.estado_id = sub.estado_id AND cub.ano_censo = (sub.ano_censo/100)' + ) + .join('estado', null, 'cub.estado_id = estado.id') + .group('cub.ano_censo') + .group('cub.mes_censo') + .group('cub.tipo_preco') + .group('cub.preco') + } + else{ + req.sql.from("cub") + } + } + else{ + //req.sql = average + req.sql.from( + squel.select().from('cub') + .field('cub.tipo_preco', 'tipo_preco') + .field('cub.preco', 'preco') + .join(price_by_id, 'sub', + 'cub.estado_id = sub.estado_id AND cub.ano_censo = (sub.ano_censo/100)' + ) + .join('estado', null, 'cub.estado_id = estado.id') + , "states") + .field('AVG(states.preco)', 'preco') + .field("'BR'", 'sigla_uf') + .field('states.tipo_preco') + .group('states.tipo_preco') + } + next(); +}, query, id2str.transform(), response('last_state_values')) + +cubApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + if (req.filter.size || req.filter.dims) { + if ('state' in req.filter || 'state' in req.dims) { + req.sql.from('cub') + .field('cub.estado_id', 'cod_uf') + .field('estado.sigla', 'sigla_uf') + .field('cub.tipo_preco', 'tipo_preco') + .field('cub.preco', 'preco') + .join('estado', null, 'cub.estado_id=estado.id') + .group('cub.ano_censo') + .group('cub.mes_censo') + .group('cub.estado_id') + .group('estado.sigla') + .group('cub.tipo_preco') + .group('cub.preco') + } else { + req.sql.from('cub') + .field("'BR'", 'sigla_uf') + .field("cub.tipo_preco", 'tipo_preco') + .field('AVG(cub.preco)', 'preco') + .join('estado', null, 'cub.estado_id=estado.id') + .group('cub.ano_censo') + .group('cub.mes_censo') + .group('cub.tipo_preco') + } + } else { + req.sql.from('cub') + .field('cub.estado_id', 'cod_uf') + .field('estado.sigla', 'sigla_uf') + .field('cub.tipo_preco', 'tipo_preco') + .field('cub.preco', 'preco') + .join('estado', null, 'cub.estado_id=estado.id') + .group('cub.ano_censo') + .group('cub.mes_censo') + .group('cub.estado_id') + .group('estado.sigla') + .group('cub.tipo_preco') + .group('cub.preco') + } + + next(); +}, query, id2str.transform(), response('cub')); + +module.exports = cubApp; diff --git a/src/libs/routes_v2/dailyChargeAmount.js b/src/libs/routes_v2/dailyChargeAmount.js new file mode 100644 index 0000000000000000000000000000000000000000..78115e48c9de29559b2f2a717c90fac24b4f4ca4 --- /dev/null +++ b/src/libs/routes_v2/dailyChargeAmount.js @@ -0,0 +1,467 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const dailyChargeAmountApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const request = require(`request`); + +const config = require(`${libs}/config`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: { include: [200] } }).middleware; + +let rqf = new ReqQueryFields(); + +let rqfCount = new ReqQueryFields(); + +//dailyChargeAmountApp.use(cache('15 day')); + +dailyChargeAmountApp.get('/year_range', (req, res, next) => { + req.sql.from('turma') + .field('MIN(turma.ano_censo)', 'start_year') + .field('MAX(turma.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +dailyChargeAmountApp.get('/years', (req, res, next) => { + req.sql.from('turma') + .field('DISTINCT turma.ano_censo', 'year'); + next(); +}, query, response('years')); + +dailyChargeAmountApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'turma\''); + next(); +}, query, response('source')); + +dailyChargeAmountApp.get('/adm_dependency', (req, res, next) => { + req.result = []; + for (let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.admDependency(i) + }); + }; + next(); +}, response('adm_dependency')); + +dailyChargeAmountApp.get('/adm_dependency_detailed', cache('15 day'), (req, res, next) => { + req.result = []; + for (let i = 1; i <= 6; ++i) { + req.result.push({ + id: i, + name: id2str.admDependencyPriv(i) + }); + }; + next(); +}, response('adm_dependency_detailed')); + +dailyChargeAmountApp.get('/location', cache('15 day'), (req, res, next) => { + req.result = [ + { id: 1, name: 'Urbana' }, + { id: 2, name: 'Rural' } + ]; + next(); +}, response('location')); + +dailyChargeAmountApp.get('/rural_location', (req, res, next) => { + req.result = [ + { id: 1, name: "Urbana" }, + { id: 2, name: "Rural" }, + { id: 3, name: "Rural - Área de assentamento" }, + { id: 4, name: "Rural - Terra indígena" }, + { id: 5, name: "Rural - Área remanescente de quilombos" }, + { id: 6, name: "Rural - Unidade de uso sustentável" } + ]; + next(); +}, response('rural_location')); + +dailyChargeAmountApp.get('/education_level_short', (req, res, next) => { + req.result = [ + { id: null, name: 'Não classificada' }, + { id: 1, name: 'Creche' }, + { id: 2, name: 'Pré-Escola' }, + { id: 3, name: 'Ensino Fundamental - anos iniciais' }, + { id: 4, name: 'Ensino Fundamental - anos finais' }, + { id: 5, name: 'Ensino Médio' }, + { id: 6, name: 'EJA' }, + { id: 7, name: 'EE exclusiva' } + ]; + next(); +}, response('education_level_short')); + +dailyChargeAmountApp.get('/average/education_level_mod', (req, res, next) => { + req.result = [ + { id: null, name: 'Não classificada' }, + { id: 1, name: 'Creche' }, + { id: 2, name: 'Pré-Escola' }, + { id: 3, name: 'Educação Infantil Unificada' }, + { id: 4, name: 'Ensino Fundamental - anos iniciais' }, + { id: 5, name: 'Ensino Fundamental - anos finais' }, + { id: 6, name: 'Ensino Médio' }, + { id: 7, name: 'Turma Multisseriadas e Multietapas' }, + { id: 8, name: 'EJA - Ensino Fundamental' }, + { id: 9, name: 'EJA - Ensino Médio' }, + { id: 10, name: 'Educação Profissional' } + ]; + next(); +}, response('education_level_mod')); + +dailyChargeAmountApp.get('/period', (req, res, next) => { + req.result = []; + for (let i = 1; i <= 3; ++i) { + req.result.push({ + id: i, + name: id2str.period(i) + }); + }; + req.result.push({ + id: 99, + name: id2str.period(99) + }); + next(); +}, response('period')); + +dailyChargeAmountApp.get('/integral_time', (req, res, next) => { + req.result = [ + { id: null, name: 'Não Disponível' }, + { id: 0, name: 'Não' }, + { id: 1, name: 'Sim' } + ]; + next(); +}, response('integral_time')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'turma' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'turma' + } +}).addValue({ + name: 'school', + table: 'escola_agregada', + tableField: ['nome_escola', 'id'], + resultField: ['school_name', 'school_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_id', + foreignTable: 'turma' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'turma' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'turma' + } +}).addValue({ + name: 'min_year', + table: 'turma', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: 'turma', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'turma', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: 'turma', + field: 'ano_censo' + } +}).addValue({ + name: 'location', + table: 'turma', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'adm_dependency', + table: 'turma', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}).addValue({ + name: 'adm_dependency_detailed', + table: 'turma', + tableField: 'dependencia_adm_priv', + resultField: 'adm_dependency_detailed_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_priv' + } +}).addValue({ + name: 'rural_location', + table: 'turma', + tableField: 'localidade_area_rural', + resultField: 'rural_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localidade_area_rural' + } +}).addValue({ + name: 'education_level_mod', + table: 'turma', + tableField: 'etapas_mod_ensino_segmento_id', + resultField: 'education_level_mod_id', + dontGroup: true, + where: { + relation: '=', + type: 'integer', + field: 'etapas_mod_ensino_segmento_id' + } +}).addValue({ + name: 'period', + table: 'turma', + tableField: 'turma_turno_id', + resultField: 'period_id', + where: { + relation: '=', + type: 'integer', + field: 'turma_turno_id' + } +}).addValue({ + name: 'integral_time', + table: 'turma', + tableField: 'tempo_integral', + resultField: 'integral_time_id', + where: { + relation: '=', + type: 'boolean', + field: 'tempo_integral' + } +}).addValue({ + name: 'education_level_short', + table: 'turma', + tableField: 'etapa_resumida', + resultField: 'education_level_short_id', + where: { + relation: '=', + type: 'integer', + field: 'etapa_resumida' + } +}); + +dailyChargeAmountApp.get('/', rqf.parse(), (req, res, next) => { + var status = 0; + if ('period' in req.filter) { + if (req.filter['period'].length == 1 && (req.filter['period'][0] == '3' || req.filter['period'][0] === '4')) { + status = 1; + } else if (req.filter['period'].length <= 2 && (req.filter['period'].includes('1') || req.filter['period'].includes('2')) && (!req.filter['period'].includes('3'))) { + status = 1; + } + } else if (req.filter['integral_time'] == '1') { + status = 1; + } + + if (status) { + req.sql.from('turma') + .field('turma.ano_censo', 'year') + .field('turma.etapa_resumida', 'education_level_short_id') + .field('AVG(turma.duracao_turma)/60.0', 'average_class_duration') + .field('MEDIAN(turma.duracao_turma)/60.0', 'median_class_duration') + .field('STDDEV_SAMP(turma.duracao_turma)/60.0', 'std_class_duration') + .field('QUANTILE(turma.duracao_turma, 0.25)/60.0', 'fstqt_class_duration') + .field('QUANTILE(turma.duracao_turma, 0.75)/60.0', 'thdqt_class_duration') + .group('turma.ano_censo') + .group('turma.etapa_resumida') + .order('turma.ano_censo') + .order('turma.etapa_resumida') + .where('((turma.tipo_turma_id <= 3 AND turma.tipo_atendimento_id is NULL) OR (turma.tipo_atendimento_id <= 2 AND turma.tipo_turma_id is NULL)) and turma.dependencia_adm_id <= 3') + } else { + res.status(400); + next({ + status: 400, + message: 'Wrong/No filter specified' + }); + } + + next(); + +}, rqf.build(), query, addMissing(rqf), (req, res, next) => { + + function sliced(object) { + return object['education_level_short_id'] > 3; + } + + if ('period' in req.filter || 'period' in req.dims) { + req.filter['period'].forEach((element) => { + if (element == '3') + req.result = req.result.filter(sliced); + }); + } + + next(); +}, id2str.transform(), response('turma')); + +dailyChargeAmountApp.get('/average', rqf.parse(), rqf.build(), (req, res, next) => { + var status = 0; + if (('education_level_mod' in req.filter || 'education_level_mod' in req.dims) + && ('integral_time' in req.filter)) { + if (req.filter['integral_time'] == '0' + && ('period' in req.filter)) { + if (req.filter['period'].length == 1 + && req.filter['period'][0] == '3') { + status = 1; + } else if (req.filter['period'].length <= 2 + && (req.filter['period'].includes('1') + || req.filter['period'].includes('2')) + && (!req.filter['period'].includes('3'))) { + status = 1; + } + } else if (req.filter['integral_time'] == '1') { + status = 1; + } + } + + if (status) { + let baseQ = req.sql.clone(); + + let tableR = baseQ.clone(); + tableR.from('turma') + .field('duracao_turma') + .field('etapas_mod_ensino_segmento_id') + .field('ROW_NUMBER() OVER(PARTITION BY etapas_mod_ensino_segmento_id ORDER BY duracao_turma)', 'rowno') + .where('((turma.tipo_turma_id <= 3 AND turma.tipo_atendimento_id is NULL) OR (turma.tipo_atendimento_id <= 2 AND turma.tipo_turma_id is NULL))') + + let tableG = baseQ.clone(); + tableG.from('turma') + .field('1+COUNT(*)', 'counter') + .field('etapas_mod_ensino_segmento_id') + .where('((turma.tipo_turma_id <= 3 AND turma.tipo_atendimento_id is NULL) OR (turma.tipo_atendimento_id <= 2 AND turma.tipo_turma_id is NULL))') + .group('etapas_mod_ensino_segmento_id') + + let joinRG = squel.select(); + joinRG.from(tableR, 'R') + .field('R.etapas_mod_ensino_segmento_id') + .field('AVG(1.0*R.duracao_turma)/60', 'median_value') + .join(tableG, 'G', 'R.etapas_mod_ensino_segmento_id = G.etapas_mod_ensino_segmento_id AND R.rowNo BETWEEN G.counter/2 AND G.counter/2+G.counter%2') + .group('R.etapas_mod_ensino_segmento_id') + + req.sql + .from('turma') + .from(joinRG, 'm') + .field('turma.ano_censo', 'year') + .field('turma.etapas_mod_ensino_segmento_id', 'education_level_mod_id') + .field('AVG(turma.duracao_turma)/60.0', 'average_class_duration') + .field('AVG(m.median_value)', 'median_class_duration') + .field('STDDEV_SAMP(turma.duracao_turma)/60.0', 'std_class_duration') + .field('QUANTILE(turma.duracao_turma, 0.25)/60.0', 'fstqt_class_duration') + .field('QUANTILE(turma.duracao_turma, 0.75)/60.0', 'thdqt_class_duration') + .group('turma.ano_censo') + .group('turma.etapas_mod_ensino_segmento_id') + .order('turma.ano_censo') + .order('turma.etapas_mod_ensino_segmento_id') + .where('((turma.tipo_turma_id <= 3 AND turma.tipo_atendimento_id is NULL) OR (turma.tipo_atendimento_id <= 2 AND turma.tipo_turma_id is NULL)) \ + and m.etapas_mod_ensino_segmento_id = turma.etapas_mod_ensino_segmento_id') + } else { + res.status(400); + next({ + status: 400, + message: 'Wrong/No filter specified' + }); + } + + next(); +}, query, addMissing(rqf), id2str.transform(), response('turma')); + +module.exports = dailyChargeAmountApp; diff --git a/src/libs/routes_v2/disciplines.js b/src/libs/routes_v2/disciplines.js new file mode 100644 index 0000000000000000000000000000000000000000..63b05f327152d7deaa4122d05fbbc0f80355a5a4 --- /dev/null +++ b/src/libs/routes_v2/disciplines.js @@ -0,0 +1,682 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const disciplinesApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const config = require(`${libs}/config`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: { include: [200] } }).middleware; + +let rqf = new ReqQueryFields(); + +disciplinesApp.use(cache('15 day')); + +// Returns a tuple of start and ending years of the complete enrollments dataset. +disciplinesApp.get('/year_range', (req, res, next) => { + req.sql.from('docente') + .field('MIN(docente.ano_censo)', 'start_year') + .field('MAX(docente.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +disciplinesApp.get('/years', (req, res, next) => { + req.sql.from('docente'). + field('DISTINCT docente.ano_censo', 'year'); + next(); +}, query, response('years')); + +disciplinesApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'docente\''); + next(); +}, query, response('source')); + +disciplinesApp.get('/adm_dependency_detailed', (req, res, next) => { + req.result = []; + for (let i = 1; i <= 8; ++i) { + req.result.push({ + id: i, + name: id2str.admDependencyPriv(i) + }); + }; + next(); +}, response('adm_dependency_detailed')); + +disciplinesApp.get('/adm_dependency', (req, res, next) => { + req.result = []; + for (let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.admDependency(i) + }); + }; + next(); +}, response('adm_dependency')); + +disciplinesApp.get('/education_level_mod', (req, res, next) => { + req.result = []; + for (let i = 1; i <= 12; ++i) { + req.result.push({ + id: i, + name: id2str.educationLevelMod(i) + }); + } + req.result.push({ + id: 99, + name: id2str.educationLevelMod(99) + }); + next(); +}, response('education_level_mod')); + +disciplinesApp.get('/education_level_short', (req, res, next) => { + req.result = [ + { id: null, name: 'Não classificada' }, + { id: 1, name: 'Creche' }, + { id: 2, name: 'Pré-Escola' }, + { id: 3, name: 'Ensino Fundamental - anos iniciais' }, + { id: 4, name: 'Ensino Fundamental - anos finais' }, + { id: 5, name: 'Ensino Médio' }, + { id: 6, name: 'EJA' }, + { id: 7, name: 'EE exclusiva' } + ]; + next(); +}, response('education_level_short')); + +disciplinesApp.get('/location', (req, res, next) => { + req.result = []; + for (let i = 1; i <= 2; ++i) { + req.result.push({ + id: i, + name: id2str.location(i) + }); + }; + next(); +}, response('location')); + +disciplinesApp.get('/rural_location', (req, res, next) => { + req.result = []; + for (let i = 1; i <= 8; i++) { + req.result.push({ + id: i, + name: id2str.ruralLocation(i) + }); + }; + next(); +}, response('rural_location')); + +disciplinesApp.get('/education_type', (req, res, next) => { + req.sql.from('docente') + .field('DISTINCT nivel_tipo_formacao', 'id') + .order('id'); + next(); +}, query, (req, res, next) => { + req.result.forEach((result) => { + result.name = id2str.educationType(result.id); + }); + next(); +}, response('education_type')); + +disciplinesApp.get('/gender', (req, res, next) => { + req.result = [ + { id: 1, name: 'Masculino' }, + { id: 2, name: 'Feminino' } + ]; + next(); +}, response('gender')); + + +disciplinesApp.get('/contract_type', (req, res, next) => { + req.result = [{ + id: "null", + name: id2str.contractType("null") + }]; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.contractType(i) + }); + } + next(); +}, response('contract_type')); + +disciplinesApp.get('/ethnic_group', (req, res, next) => { + req.result = []; + for (let i = 0; i <= 5; ++i) { + req.result.push({ + id: i, + name: id2str.ethnicGroup(i) + }); + } + next(); +}, response('ethnic_group')); + +disciplinesApp.get('/discipline', (req, res, next) => { + req.result = []; + for (let i = 1; i <= 19; i++) { + req.result.push({ + id: i, + name: id2str.discipline(i) + }) + } + next(); +}, response('discipline')) + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'adm_dependency', + table: 'docente', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}).addValue({ + name: 'adm_dependency_detailed', + table: 'docente', + tableField: 'dependencia_adm_priv', + resultField: 'adm_dependency_detailed_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_priv' + } +}).addValue({ + name: 'contract_type', + table: 'docente', + tableField: 'tipo_contratacao', + resultField: 'contract_type_id', + where: { + relation: '=', + type: 'integer', + field: 'tipo_contratacao' + } +}).addValue({ + name: 'education_level_mod', + table: 'docente', + tableField: 'etapas_mod_ensino_segmento_id', + resultField: 'education_level_mod_id', + where: { + relation: '=', + type: 'integer', + field: 'etapas_mod_ensino_segmento_id' + } +}).addValue({ + name: 'education_level_short', + table: 'docente', + tableField: 'etapa_resumida', + resultField: 'education_level_short_id', + where: { + relation: '=', + type: 'integer', + field: 'etapa_resumida' + } +}).addValue({ + name: 'education_type', + table: 'docente', + tableField: 'nivel_tipo_formacao', + resultField: 'education_type_id', + where: { + relation: '=', + type: 'integer', + field: 'nivel_tipo_formacao' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_regiao_id', + foreignTable: 'docente' + } +}).addValue({ + name: 'mesoregion', + table: 'municipio', + tableField: ['nome_mesorregiao', 'mesorregiao_id'], + resultField: ['mesoregion_name', 'mesoregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'mesorregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'escola_municipio_id', + foreignTable: 'docente' + } +}).addValue({ + name: 'microregion', + table: 'municipio', + tableField: ['nome_microrregiao', 'microrregiao_id'], + resultField: ['microregion_name', 'microregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'microrregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'escola_municipio_id', + foreignTable: 'docente' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_estado_id', + foreignTable: 'docente' + } +}).addValueToField({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_municipio_id', + foreignTable: 'docente' + } +}, 'dims').addValueToField({ + name: 'city', + table: 'municipio', + tableField: 'nome', + resultField: 'city_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_municipio_id', + foreignTable: 'docente' + } +}, 'filter').addValueToField({ + name: 'school', + table: 'escola', + tableField: ['nome_escola', 'id'], + resultField: ['school_name', 'school_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id', 'ano_censo'], + foreign: ['escola_id', 'ano_censo'], + foreignTable: 'docente' + } +}, 'dims').addValueToField({ + name: 'school', + table: 'escola', + tableField: 'nome_escola', + resultField: 'school_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id', 'ano_censo'], + foreign: ['escola_id', 'ano_censo'], + foreignTable: 'docente' + } +}, 'filter').addValue({ + name: 'location', + table: 'docente', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'rural_location', + table: 'docente', + tableField: 'localidade_area_rural', + resultField: 'rural_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localidade_area_rural' + } +}).addValue({ + name: 'min_year', + table: 'docente', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'docente', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'gender', + table: 'docente', + tableField: 'sexo', + resultField: 'gender_id', + where: { + relation: '=', + type: 'integer', + field: 'sexo' + } +}).addValue({ + name: 'ethnic_group', + table: 'docente', + tableField: 'cor_raca', + resultField: 'ethnic_group_id', + where: { + relation: '=', + type: 'integer', + field: 'cor_raca' + } +}).addValue({ + name: 'discipline', + table: 'docente', + tableField: '', + resultField: '', + where: { + relation: '=', + type: 'integer', + field: '' + } +}); + +disciplinesApp.get('/', rqf.parse(), (req, res, next) => { + if ('discipline' in req.dims) { + // delete req.filter.discipline; + delete req.dims.discipline; + req.tmp_discipline = true; + + req.sql.field('SUM(n_disc)', 'total') + .field('SUM(n_disc_adequada)', 'total_suitable') + + .field('SUM(quimica_not_null)', 'total_quimica') + .field('SUM(adequacao_quimica)', 'total_suitable_quimica') + + .field('SUM(fisica_not_null)', 'total_fisica') + .field('SUM(adequacao_fisica)', 'total_suitable_fisica') + + .field('SUM(matematica_not_null)', 'total_matematica') + .field('SUM(adequacao_matematica)', 'total_suitable_matematica') + + .field('SUM(biologia_not_null)', 'total_biologia') + .field('SUM(adequacao_biologia)', 'total_suitable_biologia') + + .field('SUM(ciencias_not_null)', 'total_ciencias') + .field('SUM(adequacao_ciencias)', 'total_suitable_ciencias') + + .field('SUM(lingua_portuguesa_not_null)', 'total_lingua_portuguesa') + .field('SUM(adequacao_lingua_portuguesa)', 'total_suitable_lingua_portuguesa') + + .field('SUM(lingua_inglesa_not_null)', 'total_lingua_inglesa') + .field('SUM(adequacao_lingua_inglesa)', 'total_suitable_lingua_inglesa') + + .field('SUM(lingua_espanhola_not_null)', 'total_lingua_espanhola') + .field('SUM(adequacao_lingua_espanhola)', 'total_suitable_lingua_espanhola') + + .field('SUM(lingua_francesa_not_null)', 'total_lingua_francesa') + .field('SUM(adequacao_lingua_francesa)', 'total_suitable_lingua_francesa') + + .field('SUM(lingua_outra_not_null)', 'total_lingua_outra') + .field('SUM(adequacao_lingua_outra)', 'total_suitable_lingua_outra') + + .field('SUM(lingua_indigena_not_null)', 'total_lingua_indigena') + .field('SUM(adequacao_lingua_indigena)', 'total_suitable_lingua_indigena') + + .field('SUM(artes_not_null)', 'total_artes') + .field('SUM(adequacao_artes)', 'total_suitable_artes') + + .field('SUM(educacao_fisica_not_null)', 'total_educacao_fisica') + .field('SUM(adequacao_educacao_fisica)', 'total_suitable_educacao_fisica') + + .field('SUM(historia_not_null)', 'total_historia') + .field('SUM(adequacao_historia)', 'total_suitable_historia') + + .field('SUM(geografia_not_null)', 'total_geografia') + .field('SUM(adequacao_geografia)', 'total_suitable_geografia') + + .field('SUM(filosofia_not_null)', 'total_filosofia') + .field('SUM(adequacao_filosofia)', 'total_suitable_filosofia') + + .field('SUM(ensino_religioso_not_null)', 'total_ensino_religioso') + .field('SUM(adequacao_ensino_religioso)', 'total_suitable_ensino_religioso') + + .field('SUM(estudos_sociais_not_null)', 'total_estudos_sociais') + .field('SUM(adequacao_estudos_sociais)', 'total_suitable_estudos_sociais') + + .field('SUM(sociologia_not_null)', 'total_sociologia') + .field('SUM(adequacao_sociologia)', 'total_suitable_sociologia') + + .field("'Brasil'", 'name') + .field('docente.ano_censo', 'year') + .from('docente') + .group('docente.ano_censo') + .order('docente.ano_censo') + .where('(docente.tipo_docente = 1 OR docente.tipo_docente = 5) AND \ + ((docente.tipo_turma_id >= 0 AND docente.tipo_turma_id <= 3 AND docente.tipo_turma_atendimento_id is NULL) \ + OR ((docente.tipo_turma_atendimento_id = 1 OR docente.tipo_turma_atendimento_id = 2) AND docente.tipo_turma_id is NULL)) AND \ + docente.etapas_mod_ensino_segmento_id <> 6 AND docente.etapas_mod_ensino_segmento_id <> 12'); + } + else if ('discipline' in req.filter) { + const disciplines = ['quimica', 'fisica', 'matematica', 'biologia', 'ciencias', 'lingua_portuguesa', 'lingua_inglesa', 'lingua_espanhola', 'lingua_francesa', 'lingua_outra', 'lingua_indigena', 'artes', 'educacao_fisica', 'historia', 'geografia', 'filosofia', 'ensino_religioso', 'estudos_sociais', 'sociologia'] + + let totalQuery = 'SUM(' + let totalSuitableQuery = 'SUM(' + + if (!(req.filter.discipline instanceof Array)) req.filter.discipline = [req.filter.discipline] + + req.filter.discipline.forEach(d => { + totalQuery += disciplines[d - 1] + '_not_null + ' + totalSuitableQuery += 'adequacao_' + disciplines[d - 1] + ' + ' + }) + totalQuery = totalQuery.slice(0, -2) + ')' + totalSuitableQuery = totalSuitableQuery.slice(0, -2) + ')' + + delete req.filter.discipline; + + req.sql.field(totalQuery, 'total') + .field(totalSuitableQuery, 'total_suitable') + .field("'Brasil'", 'name') + .field('docente.ano_censo', 'year') + .from('docente') + // .join('turma', null, 'docente.turma_id=turma.id AND docente.ano_censo=turma.ano_censo') + .group('docente.ano_censo') + .order('docente.ano_censo') + .where('(docente.tipo_docente = 1 OR docente.tipo_docente = 5) AND \ + ((docente.tipo_turma_id >= 0 AND docente.tipo_turma_id <= 3 AND docente.tipo_turma_atendimento_id is NULL) \ + OR ((docente.tipo_turma_atendimento_id = 1 OR docente.tipo_turma_atendimento_id = 2) AND docente.tipo_turma_id is NULL)) AND \ + docente.etapas_mod_ensino_segmento_id <> 6 AND docente.etapas_mod_ensino_segmento_id <> 12'); + } + else { + req.sql.field('SUM(n_disc)', 'total') + .field('SUM(n_disc_adequada)', 'total_suitable') + .field("'Brasil'", 'name') + .field('docente.ano_censo', 'year') + .from('docente') + // .join('turma', null, 'docente.turma_id=turma.id AND docente.ano_censo=turma.ano_censo') + .group('docente.ano_censo') + .order('docente.ano_censo') + .where('(docente.tipo_docente = 1 OR docente.tipo_docente = 5) AND \ + ((docente.tipo_turma_id >= 0 AND docente.tipo_turma_id <= 3 AND docente.tipo_turma_atendimento_id is NULL) \ + OR ((docente.tipo_turma_atendimento_id = 1 OR docente.tipo_turma_atendimento_id = 2) AND docente.tipo_turma_id is NULL)) AND \ + docente.etapas_mod_ensino_segmento_id <> 6 AND docente.etapas_mod_ensino_segmento_id <> 12'); + } + + next(); +}, rqf.build(), query, id2str.transform(), (req, res, next) => { + let filters = Object.keys(req.filter) + + // if(filters.includes("state")) { + // const disciplinesDB = ['quimica', 'fisica', 'matematica', 'biologia', 'ciencias', 'lingua_portuguesa', 'lingua_inglesa', 'lingua_espanhola', + // 'lingua_francesa', 'lingua_outra', 'lingua_indigena', 'artes', 'educacao_fisica', 'historia', 'geografia', 'filosofia', 'ensino_religioso', + // 'estudos_sociais', 'sociologia'] + // const disciplinesAPI = ["Química", "Física", "Matemática", "Biologia", "Ciências", "Língua Portuguesa", "Língua Estrangeira – Inglês", + // "Língua Estrangeira - Espanhol","Língua Estrangeira - Francês", "Língua Estrangeira - Outras", "Língua Indígena", "Arte", "Educação Física", "História", + // "Geografia", "Filosofia", "Ensino religioso", "Estudos Sociais", "Sociologia"] + + // let jsonKeys = [] + // let results = [] + // req.result.forEach((r) => { + // jsonKeys = Object.keys(r) + + // let i + // let size = jsonKeys.length - 2 // Last two infos are "name" and "year" + // for(i = 0; i < size; i++) { + // let total_name = jsonKeys[i] + // let suitable_name = jsonKeys[i + 1] + + // // Calculates percentage + // let percentage = r[suitable_name] / r[total_name] + // percentage = percentage * 100 + // percentage = percentage.toFixed(1) // Rounds to 1 digit after comma, returns string + // percentage = percentage.replace(".", ",") + "%" + + // // Parses name + // total_name = total_name.replace("total_", "") + // let discipline_index = disciplinesDB.indexOf(total_name) + // let discipline_name = disciplinesAPI[discipline_index] + + // let obj = { + // total: percentage, + // name: r["name"], + // year: r["year"], + // discipline_id: discipline_index + 1, // Convert function starts at 1, not at 0 + // discipline_name: discipline_name + // } + // results.push(obj) + + // i++; // Ignore next, it's a suitable already used + // } + // }) + + // req.result = results; + // } + // else { + let disciplinesNotSuitable = []; + let disciplinesSuitable = []; + + req.result.forEach((r) => { + + let obj = { + sum_total: 0, + sum_suitable: 0 + } + + Object.keys(r).forEach(k => { + if (k !== 'total' && k !== 'total_suitable') + obj[k] = r[k]; + }) + + if (req.tmp_discipline){ + Object.keys(r).forEach(k => { + if (/^total_suitable_/.test(k)) // if k starts with total_suitable + obj.sum_suitable += parseInt(r[k]); + else if (/^total_(?!suitable)/.test(k)) + obj.sum_total += parseInt(r[k]); + }) + } else { + delete obj.sum_total; + delete obj.sum_suitable; + } + + let objNotSuitable = Object.assign({}, { + total: parseInt(r.total) - parseInt(r.total_suitable), + suitable: 0, + discipline_name: 'Formação não adequada', + }, obj) + + let objSuitable = Object.assign({}, { + total: parseInt(r.total_suitable), + suitable: 1, + discipline_name: 'Formação adequada', + }, obj) + + disciplinesNotSuitable.push(objNotSuitable) + disciplinesSuitable.push(objSuitable) + }) + + req.result = disciplinesNotSuitable.concat(disciplinesSuitable); + next(); +}, response('disciplines')); + +module.exports = disciplinesApp; + + diff --git a/src/libs/routes_v2/distributionFactor.js b/src/libs/routes_v2/distributionFactor.js new file mode 100644 index 0000000000000000000000000000000000000000..8a7b0e28b8bd3f1678cf9721e4e54c67edfe029c --- /dev/null +++ b/src/libs/routes_v2/distributionFactor.js @@ -0,0 +1,210 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const distributionApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const multiQuery = require(`${libs}/middlewares/multiQuery`); + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +distributionApp.use(cache('15 day')); + +rqf.addField({ + name: 'dims', + field: true, + where: false +}).addField({ + name: 'filter', + field: false, + where: true +}).addValueToField({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'fatores_matricula' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'fatores_matricula' + } +}, 'dims').addValueToField({ + name: 'city', + table: 'municipio', + tableField: 'nome', + resultField: 'city_name', + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'fatores_matricula' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'fatores_matricula' + } +}, 'filter').addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'fatores_matricula' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'fatores_matricula' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'fatores_matricula' + } +}) + +// Return all cities +distributionApp.get('/', rqf.parse(), (req, res, next) => { + req.querySet = []; + req.queryIndex = {}; + + let relation = req.sql.clone(); + relation.from('relacao_fatores_matricula').field('*'); + req.queryIndex.relation = req.querySet.push(relation) - 1; + + req.sql.from('fatores_matricula') + .field('fatores_matricula.municipio_id', 'municipio_id') + .field('fatores_matricula."mais_CRE_0"') + .field('fatores_matricula."mais_CRE_1"') + .field('fatores_matricula."mais_CRE_2"') + .field('fatores_matricula."mais_CRE_3"') + .field('fatores_matricula."mais_PRE"') + .field('fatores_matricula."mais_EFAI"') + .field('fatores_matricula."mais_EFAF"') + .field('fatores_matricula."mais_EM"') + .field('fatores_matricula."mais_EJA"') + .field('fatores_matricula."menos_CRE_0"') + .field('fatores_matricula."menos_CRE_1"') + .field('fatores_matricula."menos_CRE_2"') + .field('fatores_matricula."menos_CRE_3"') + .field('fatores_matricula."menos_PRE"') + .field('fatores_matricula."menos_EFAI"') + .field('fatores_matricula."menos_EFAF"') + .field('fatores_matricula."menos_EM"') + .field('fatores_matricula."menos_EJA"') + .group('fatores_matricula.municipio_id') + .group('fatores_matricula."mais_CRE_0"') + .group('fatores_matricula."mais_CRE_1"') + .group('fatores_matricula."mais_CRE_2"') + .group('fatores_matricula."mais_CRE_3"') + .group('fatores_matricula."mais_PRE"') + .group('fatores_matricula."mais_EFAI"') + .group('fatores_matricula."mais_EFAF"') + .group('fatores_matricula."mais_EM"') + .group('fatores_matricula."mais_EJA"') + .group('fatores_matricula."menos_CRE_0"') + .group('fatores_matricula."menos_CRE_1"') + .group('fatores_matricula."menos_CRE_2"') + .group('fatores_matricula."menos_CRE_3"') + .group('fatores_matricula."menos_PRE"') + .group('fatores_matricula."menos_EFAI"') + .group('fatores_matricula."menos_EFAF"') + .group('fatores_matricula."menos_EM"') + .group('fatores_matricula."menos_EJA"'); + + if(typeof req.dims.state !== 'undefined' || typeof req.filter.state !== 'undefined') { + req.sql.where('fatores_matricula.nivel = \'UF\''); + } else { + req.sql.where('fatores_matricula.nivel = \'BR\''); + } + + next(); +}, rqf.build(), query, (req, res, next) => { + req.enrollmentFactor = req.result; + next(); +}, multiQuery, (req, res, next) => { + let relation = req.result[req.queryIndex.relation]; + let result = []; + let first = true; + req.enrollmentFactor.forEach((city) => { + // if(first) console.log(city); + let obj = { + level: city.nivel, + region_id: city.regiao_id, + region_name: city.region_name, + state_id: city.state_id, + state_name: city.state_name, + city_id: city.municipio_id, + city_name: city.city_name, + series: [] + }; + // if(first) console.log(obj); + first = false; + relation.forEach((serie) => { + obj.series.push({ + serie_id: serie.id, + distribution_factor_addition: city[serie.fator_adicao], + distribution_factor_reduction: city[serie.fator_reducao] + }); + }); + result.push(obj); + }); + req.result = result; + next(); +}, response('ditributionFactor')); + +module.exports = distributionApp; diff --git a/src/libs/routes/downloads.js b/src/libs/routes_v2/downloads.js similarity index 100% rename from src/libs/routes/downloads.js rename to src/libs/routes_v2/downloads.js diff --git a/src/libs/routes_v2/educationYears.js b/src/libs/routes_v2/educationYears.js new file mode 100644 index 0000000000000000000000000000000000000000..0d103883f53fc53dbd8770fa983dc5fe568564dd --- /dev/null +++ b/src/libs/routes_v2/educationYears.js @@ -0,0 +1,46 @@ +const express = require('express'); + +const educationYearsApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const response = require(`${libs}/middlewares/response`); + +const config = require(`${libs}/config`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +educationYearsApp.use(cache('15 day')); + +educationYearsApp.get('/', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 7; ++i) { + let edLvlShort = { + id: i, + name: id2str.educationLevelShort(i), + schoolYears: [] + }; + + for(let j = i*10; j <= (i*10 + 9); ++j) { + + let schoolYear = { + id: j, + name: id2str.schoolYear(j) + }; + + if(schoolYear.name !== id2str.schoolYear(99)) { + edLvlShort.schoolYears.push(schoolYear); + } + } + if(edLvlShort.name !== id2str.schoolYear(99)) { + req.result.push(edLvlShort); + } + } + next(); +}, response('educationYears')); + +module.exports = educationYearsApp; diff --git a/src/libs/routes_v2/educationalBudget.js b/src/libs/routes_v2/educationalBudget.js new file mode 100644 index 0000000000000000000000000000000000000000..30f6afc16ce86fe0c981b58b905b87b77d51cec1 --- /dev/null +++ b/src/libs/routes_v2/educationalBudget.js @@ -0,0 +1,325 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + + +const libs = `${process.cwd()}/libs`; + +const conn = require(`${libs}/db/monet`); + +const express = require('express'); + +const educationalBudget = express.Router(); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +let rqfId = new ReqQueryFields(); + +const db = require(`${libs}/db/query_exec`); + +const log = require(`${libs}/log`)(module); + +rqfId.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'federative_entity', + table: 'orcamento_educacional', + tableField: 'entidade_federativa', + resultField: 'entidade_federativa_id', + where: { + relation: '=', + type: 'integer', + field: 'entidade_federativa' + } +}); + +//Insert route in orcamento_educacional table +educationalBudget.post('/insert', (req, res, next) => { + let id = req.body.id || null; + let entidade_federativa = req.body.entidade_federativa || null; + let csv = req.body.csv || null; + + //csv example + //"RO|7777777|jiarana|8043|41768845|43141895|66081767|8216|24312922|158,2%" + + req.id = id; + req.entidade_federativa = entidade_federativa; + req.csv = csv.toString(); + req.date = new Date(); + + //split o csv para adicionar separadamente nas colunas + csv = csv.split("|"); + req.uf = csv[0]; + req.municipio_id = csv[1]; + req.nome = csv[2]; + req.matriculas = csv[3]; + req.receitas_vinculadas = csv[4]; + req.despesas_realizadas = csv[5]; + req.despesas_correntes = csv[6]; + req.valor_aluno = csv[7]; + req.completacao = csv[8]; + req.completacao_porcentagem = csv[9]; + + let sqlQueryParams = []; + + //remove id duplicate + let deleteQuery = squel.delete() + .from("orcamento_educacional") + .where('id = ' + req.id) + .toString() + + //Exec delete sql + log.debug(`Executing SQL query '${deleteQuery}' with params '${[sqlQueryParams]}'`); + return new Promise((resolve, reject) => { + // Prepare statement + conn.prepare(deleteQuery, true).then((dbQuery) => { + // Execute query + dbQuery.exec(sqlQueryParams).then((dbResult) => { + // release resources allocated for the prepared statement + dbQuery.release(); + resolve(dbResult.data); + req.result = "Insertion Success" + next(); + }).catch((queryError) => { + log.error(`SQL query execution error: ${queryError.message}`); + req.result = "SQL query execution error:" + queryError.message; + log.error(`SQL query: ${deleteQuery} with params: ${sqlQueryParams}`); + // release resources allocated for the prepared statement + dbQuery.release(); + next(); + }); + }).catch((prepError) => { + log.error(`SQL prepared statement error: ${prepError.message}`); + req.result = "SQL query execution error:" + queryError.message; + log.error(`SQL query: ${deleteQuery} with params: ${sqlQueryParams}`); + next(); + }); + }); + +}, (req, res, next) => { + //build query + let insertQuery = squel.insert() + .into("orcamento_educacional") + .set("id", req.id) + .set("entidade_federativa", req.entidade_federativa) + .set("csv", req.csv) + .set("data", req.date.toString()) + .set("uf", req.uf) + .set("municipio_id", req.municipio_id) + .set("nome", req.nome) + .set("receitas_vinculadas", req.receitas_vinculadas) + .set("despesas_realizadas", req.despesas_realizadas) + .set("despesas_correntes", req.despesas_correntes) + .set("valor_aluno", req.valor_aluno) + .set("completacao", req.completacao) + .set("completacao_porcentagem", req.completacao_porcentagem) + .toString() + + let sqlQueryParams = []; + + //Exec insert sql + log.debug(`Executing SQL query '${insertQuery}' with params '${[sqlQueryParams]}'`); + return new Promise((resolve, reject) => { + // Prepare statement + conn.prepare(insertQuery, true).then((dbQuery) => { + // Execute query + dbQuery.exec(sqlQueryParams).then((dbResult) => { + // release resources allocated for the prepared statement + dbQuery.release(); + resolve(dbResult.data); + req.result = "Insertion Success" + next(); + }).catch((queryError) => { + log.error(`SQL query execution error: ${queryError.message}`); + req.result = "SQL query execution error:" + queryError.message; + log.error(`SQL query: ${insertQuery} with params: ${sqlQueryParams}`); + // release resources allocated for the prepared statement + dbQuery.release(); + next(); + }); + }).catch((prepError) => { + log.error(`SQL prepared statement error: ${prepError.message}`); + req.result = "SQL query execution error:" + queryError.message; + log.error(`SQL query: ${insertQuery} with params: ${sqlQueryParams}`); + next(); + }); + }); + + next(); +}, response('educationalBudget')); + +//Delete orcamento_educacional table +educationalBudget.get('/delete', (req, res, next) => { + + //build query + let insertQuery = squel.delete() + .from("orcamento_educacional") + .toString() + + let sqlQueryParams = []; + + //Exec sql in monet + log.debug(`Executing SQL query '${insertQuery}' with params '${[sqlQueryParams]}'`); + return new Promise((resolve, reject) => { + // Prepare statement + conn.prepare(insertQuery, true).then((dbQuery) => { + // Execute query + dbQuery.exec(sqlQueryParams).then((dbResult) => { + // release resources allocated for the prepared statement + dbQuery.release(); + resolve(dbResult.data); + req.result = "Delete Table Success" + next(); + }).catch((queryError) => { + log.error(`SQL query execution error: ${queryError.message}`); + req.result = "SQL query execution error:" + queryError.message; + log.error(`SQL query: ${insertQuery} with params: ${sqlQueryParams}`); + // release resources allocated for the prepared statement + dbQuery.release(); + next(); + }); + }).catch((prepError) => { + log.error(`SQL prepared statement error: ${prepError.message}`); + req.result = "SQL query execution error:" + queryError.message; + log.error(`SQL query: ${insertQuery} with params: ${sqlQueryParams}`); + next(); + }); + }); + + next(); +}, response('educationalBudget')); + +//Return all id's in table +educationalBudget.get('/id', rqfId.parse(), rqfId.build(), (req, res, next) => { + req.sql.from('orcamento_educacional') + .field('orcamento_educacional.municipio_id') + next(); +}, query, response('educationalBudget')); + +//Return count id grouop by entidade_federativa +educationalBudget.get('/finish', rqf.parse(), (req, res, next) => { + req.sql.field('COUNT(*)', 'total') + .field('orcamento_educacional.entidade_federativa', 'entidade_federativa') + .from('orcamento_educacional') + .group('orcamento_educacional.entidade_federativa') + .order('orcamento_educacional.entidade_federativa') + next(); +}, query, response('educationalBudget')); + +//return all data +educationalBudget.get('/', rqf.parse(), (req, res, next) => { + req.sql.from('orcamento_educacional') + .field('orcamento_educacional.id') + .field('orcamento_educacional.entidade_federativa', 'entidade_federativa') + .field('orcamento_educacional.data', 'data_insercao') + .field('orcamento_educacional.uf', 'uf') + .field('orcamento_educacional.municipio_id', 'municipio_id') + .field('orcamento_educacional.nome', 'nome') + .field('orcamento_educacional.receitas_vinculadas', 'receitas_vinculadas') + .field('orcamento_educacional.despesas_realizadas', 'despesas_realizadas') + .field('orcamento_educacional.despesas_correntes', 'despesas_correntes') + .field('orcamento_educacional.valor_aluno', 'valor_aluno') + .field('orcamento_educacional.completacao', 'completacao') + .field('orcamento_educacional.completacao_porcentagem', 'completacao_porcentagem') + .field('orcamento_educacional.csv', 'csv') + next(); +}, query, response('educationalBudget')); + +//Insert route in orcamento_educacional table +educationalBudget.post('/insert_pqr', (req, res, next) => { + let id = JSON.parse(req.body.id) || null; + let pqr = JSON.parse(req.body.pqr) || null; + + req.id = id; + req.pqr = pqr; + req.date = new Date(); + + //build query + let insertQuery = squel.insert() + .into("orcamento_educacional_pqr") + .set("id", req.id.toString()) + .set("pqr", req.pqr.toString()) + .set("data", req.date.toString()) + .toString() + + let sqlQueryParams = []; + + //Exec sql + log.debug(`Executing SQL query '${insertQuery}' with params '${[sqlQueryParams]}'`); + return new Promise((resolve, reject) => { + // Prepare statement + conn.prepare(insertQuery, true).then((dbQuery) => { + // Execute query + dbQuery.exec(sqlQueryParams).then((dbResult) => { + // release resources allocated for the prepared statement + dbQuery.release(); + resolve(dbResult.data); + req.result = "Insertion Success" + next(); + }).catch((queryError) => { + log.error(`SQL query execution error: ${queryError.message}`); + req.result = "SQL query execution error:" + queryError.message; + log.error(`SQL query: ${insertQuery} with params: ${sqlQueryParams}`); + // release resources allocated for the prepared statement + dbQuery.release(); + next(); + }); + }).catch((prepError) => { + log.error(`SQL prepared statement error: ${prepError.message}`); + req.result = "SQL query execution error:" + queryError.message; + log.error(`SQL query: ${insertQuery} with params: ${sqlQueryParams}`); + next(); + }); + }); + + next(); +}, response('educationalBudget')); + +educationalBudget.get('/get_pqr', (req, res, next) => { + req.sql.from('orcamento_educacional_pqr') + .field('orcamento_educacional_pqr.id', 'id') + .field('orcamento_educacional_pqr.pqr', 'pqr') + .field('orcamento_educacional_pqr.data', 'data') + next(); +}, query, response('educationalBudget')); + +module.exports = educationalBudget; + diff --git a/src/libs/routes_v2/employees.js b/src/libs/routes_v2/employees.js new file mode 100644 index 0000000000000000000000000000000000000000..1ef4e7fd0a3b29ae0b2725b1cbdc3cd1b318f7e4 --- /dev/null +++ b/src/libs/routes_v2/employees.js @@ -0,0 +1,656 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const employeesApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const config = require(`${libs}/config`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqfTeacher = new ReqQueryFields(); + +let rqfSchool = new ReqQueryFields(); + + +employeesApp.use(cache('15 day')); + +// Returns a tuple of start and ending years of the complete enrollments dataset. +employeesApp.get('/year_range', (req, res, next) => { + req.sql.from('escola') + .field('MIN(escola.ano_censo)', 'start_year') + .field('MAX(escola.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +employeesApp.get('/years', (req, res, next) => { + req.sql.from('escola'). + field('DISTINCT escola.ano_censo', 'year'); + next(); +}, query, response('years')); + +employeesApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'docente\''); + next(); +}, query, response('source')); + +employeesApp.get('/location', (req, res, next) => { + req.result = [ + {id: 1, name: 'Urbana'}, + {id: 2, name: 'Rural'} + ]; + next(); +}, response('location')); + +employeesApp.get('/diff_location', (req, res, next) => { + req.result = [ + {id: 0, name: "A escola não está em localidade diferenciada"}, + {id: 1, name: "Área de assentamento"}, + {id: 2, name: "Terra indígena"}, + {id: 3, name: "Terra remanescente de quilombos"}, + ]; + next(); +}, response('diff_location')); + +employeesApp.get('/adm_dependency_detailed', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 6; ++i) { + req.result.push({ + id: i, + name: id2str.admDependencyPriv(i) + }); + }; + next(); +}, response('adm_dependency_detailed')); + +employeesApp.get('/adm_dependency', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.admDependency(i) + }); + }; + next(); +}, response('adm_dependency')); + +employeesApp.get('/function', (req, res, next) => { + req.result = [ + {id: 0, name: "Administrativos"}, + {id: 1, name: "Serviços Gerais"}, + {id: 2, name: "Bibliotecário"}, + {id: 3, name: "Saúde"}, + {id: 4, name: "Coordenador"}, + {id: 5, name: "Fonoaudiólogo"}, + {id: 6, name: "Nutricionista"}, + {id: 7, name: "Psicólogo"}, + {id: 8, name: "Alimentação"}, + {id: 9, name: "Pedagogia"}, + {id: 10, name: "Secretário"}, + {id: 11, name: "Segurança"}, + {id: 12, name: "Monitores"}, + {id: 99, name: "Não Classificado"} + ]; + next(); +}, response('function')); + +rqfSchool.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'adm_dependency', + table: '@', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}).addValue({ + name: 'adm_dependency_detailed', + table: '@', + tableField: 'dependencia_adm_priv', + resultField: 'adm_dependency_detailed_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_priv' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: '@' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: '@' + } +}).addValueToField({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: '@' + } +}, 'dims').addValueToField({ + name: 'city', + table: 'municipio', + tableField: 'nome', + resultField: 'city_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: '@' + } +}, 'filter').addValueToField({ + name: 'school', + table: '@', + tableField: ['nome_escola', 'id'], + resultField: ['school_name', 'school_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, +}, 'dims').addValueToField({ + name: 'school', + table: '@', + tableField: 'escola_nome', + resultField: 'school_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, +}, 'filter').addValue({ + name: 'location', + table: '@', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'diff_location', + table: '@', + tableField: 'localizacao_diferenciada_par', + resultField: 'diff_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_diferenciada_par' + } +}).addValue({ + name: 'rural_location', + table: '@', + tableField: 'localidade_area_rural', + resultField: 'rural_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localidade_area_rural' + } +}).addValue({ + name: 'function', + table: '@', + tableField: 'a', + resultField: 'function_id', + where: { + relation: '=', + type: 'integer', + field: 'a' + } +}).addValue({ + name: 'min_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}); + +rqfTeacher.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'adm_dependency', + table: '@', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}).addValue({ + name: 'adm_dependency_detailed', + table: '@', + tableField: 'dependencia_adm_priv', + resultField: 'adm_dependency_detailed_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_priv' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: '@' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: '@' + } +}).addValueToField({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: '@' + } +}, 'dims').addValueToField({ + name: 'city', + table: 'municipio', + tableField: 'nome', + resultField: 'city_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: '@' + } +}, 'filter').addValueToField({ + name: 'school', + table: 'escola', + tableField: ['nome_escola', 'id'], + resultField: ['school_name', 'school_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id','ano_censo'], + foreign: ['escola_id','ano_censo'], + foreignTable: '@' + } +}, 'dims').addValueToField({ + name: 'school', + table: 'escola', + tableField: 'nome_escola', + resultField: 'school_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id','ano_censo'], + foreign: ['escola_id','ano_censo'], + foreignTable: '@' + } +}, 'filter').addValue({ + name: 'location', + table: '@', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'diff_location', + table: '@', + tableField: 'localizacao_diferenciada_par', + resultField: 'diff_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_diferenciada_par' + } +}).addValue({ + name: 'rural_location', + table: '@', + tableField: 'localidade_area_rural', + resultField: 'rural_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localidade_area_rural' + } +}).addValue({ + name: 'min_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}); + + +function formatFunction(queryOriginal,reqDims) { + delete reqDims.size; + delete reqDims.function; + let dims = Object.keys(reqDims); //se for = 0, apenas lidamos com a dimensao function. Se for = 1, lidamos com function mais a dimensao q esta nesse array. + let name = { + qtde_admin: "Administrativos", + qtde_servicos_gerais: "Serviços Gerais", + qtde_bibliotecario: "Bibliotecário", + qtde_saude: "Saúde", + qtde_coordenador: "Coordenador", + qtde_fono: "Fonoaudiólogo", + qtde_nutricionista: "Nutricionista", + qtde_psicologo: "Psicólogo", + qtde_alimentacao: "Alimentação", + qtde_pedagogia: "Pedagogia", + qtde_secretario: "Secretário", + qtde_seguranca: "Segurança", + qtde_monitores: "Monitores", + qtde_null: "Não Classificado" + } + let resultObj = [] + //Nesse caso apenas precisamos acertar as dimensoes que o banco retorna, ou seja, criando um objeto para cada funcao de funcionario + if (dims.length == 0) { + queryOriginal.forEach((result) => { + Object.keys(result).forEach(function(key,index) { + if (key.includes("qtde")) { + let newObj = { + year: result["year"], + function_id: index, + function_name: name[key], + total: result[key] + } + resultObj.push(newObj); + } + }) + }) + } + //Nesse caso precisamos copiar o id e name da variavel que está na dimensão junto com funcionarios por função + else { + queryOriginal.forEach((result) => { + Object.keys(result).forEach(function(key,index) { + if (key.includes("qtde")) { + let newObj = { + year: result["year"], + function_id: index, + function_name: name[key], + total: result[key] + } + newObj[dims[0] + "_id"] = result[dims[0] + "_id"]; + newObj[dims[0] + "_name"] = result[dims[0] + "_name"]; + resultObj.push(newObj); + } + }) + }) + } + + return resultObj; + +} + +function matchQueries(queryTotal, queryPartial) { + let match = []; + queryTotal.forEach((result) => { + let newObj = {}; + let keys = Object.keys(result); + keys.forEach((key) => { + newObj[key] = result[key]; + }); + let index = keys.indexOf('total'); + if(index > -1) keys.splice(index, 1); + let objMatch = null; + + for(let i = 0; i < queryPartial.length; ++i) { + let partial = queryPartial[i]; + let foundMatch = true; + for(let j = 0; j < keys.length; ++j) { + let key = keys[j]; + if(partial[key] !== result[key]) { + foundMatch = false; + break; + } + } + if(foundMatch) { + objMatch = partial; + break; + } + } + + if(objMatch) { + newObj.total = result.total - objMatch.total; + if (newObj.total > 0) { + newObj.total_employees = result.total; + newObj.total_teachers = objMatch.total + match.push(newObj); + } + } + }); + + return match; +} + +employeesApp.get('/', rqfSchool.parse(), (req, res, next) => { + req.allTeacher = {} + req.schoolTable = {} + + if ("function" in req.dims) { + delete req.dims.function; + req.sql.field('SUM(funcionarios_por_escola.total)', 'qtde_null') + .field('funcionarios_por_escola.ano_censo', 'year') + .from('funcionarios_por_escola') + .group('funcionarios_por_escola.ano_censo') + .order('funcionarios_por_escola.ano_censo') + .where('funcionarios_por_escola.ano_censo <> 2009 or funcionarios_por_escola.estado_id <> 42') + } else { + delete req.dims.function; + req.sql.field('SUM(funcionarios_por_escola.total)', 'total') + .field('funcionarios_por_escola.ano_censo', 'year') + .from('funcionarios_por_escola') + .group('funcionarios_por_escola.ano_censo') + .order('funcionarios_por_escola.ano_censo') + .where('funcionarios_por_escola.ano_censo <> 2009 or funcionarios_por_escola.estado_id <> 42') + } + next(); + +}, rqfSchool.build(), query, rqfSchool.parse(), id2str.transform(), (req, res, next) => { + + req.allTeacher = req.result; + req.resetSql(); + if ("function" in req.dims) { + req.sql.field('SUM(CASE WHEN escola.qt_prof_admin = 88888 THEN 0 ELSE escola.qt_prof_admin END)', 'qtde_admin') + .field('SUM(CASE WHEN escola.qtde_prof_servicos_gerais = 88888 THEN 0 ELSE escola.qtde_prof_servicos_gerais END) AS qtde_servicos_gerais') + .field('SUM(CASE WHEN escola.qtde_prof_bibliotecario = 88888 THEN 0 ELSE escola.qtde_prof_bibliotecario END)', 'qtde_bibliotecario') + .field('SUM(CASE WHEN escola.qtde_prof_saude = 88888 THEN 0 ELSE escola.qtde_prof_saude END)','qtde_saude') + .field('SUM(CASE WHEN escola.qtde_prof_coordenador = 88888 THEN 0 ELSE escola.qtde_prof_coordenador END)','qtde_coordenador') + .field('SUM(CASE WHEN escola.qtde_prof_fono = 88888 THEN 0 ELSE escola.qtde_prof_fono END)','qtde_fono') + .field('SUM(CASE WHEN escola.qtde_prof_nutricionista = 88888 THEN 0 ELSE escola.qtde_prof_nutricionista END)', 'qtde_nutricionista') + .field('SUM(CASE WHEN escola.qtde_prof_psicologo = 88888 THEN 0 ELSE escola.qtde_prof_psicologo END)', 'qtde_psicologo') + .field('SUM(CASE WHEN escola.qtde_prof_alimentacao = 88888 THEN 0 ELSE escola.qtde_prof_alimentacao END)','qtde_alimentacao') + .field('SUM(CASE WHEN escola.qtde_prof_pedagogia = 88888 THEN 0 ELSE escola.qtde_prof_pedagogia END)', 'qtde_pedagogia') + .field('SUM(CASE WHEN escola.qtde_prof_secretario = 88888 THEN 0 ELSE escola.qtde_prof_secretario END)','qtde_secretario') + .field('SUM(CASE WHEN escola.qtde_prof_seguranca = 88888 THEN 0 ELSE escola.qtde_prof_seguranca END)','qtde_seguranca') + .field('SUM(CASE WHEN escola.qtde_prof_monitores = 88888 THEN 0 ELSE escola.qtde_prof_monitores END)', 'qtde_monitores') + .field("'Brasil'", 'name') + .field('escola.ano_censo', 'year') + .from('escola') + .group('escola.ano_censo') + .order('escola.ano_censo') + .where('(escola.situacao_funcionamento_pareada = 1) AND (escola.ensino_regular = 1 OR escola.ensino_eja = 1 OR escola.educacao_profissional = 1) AND (escola.dependencia_adm_id = 2 OR escola.dependencia_adm_id = 3 OR escola.dependencia_adm_id = 4) and ano_censo >= 2019'); + delete req.dims.function; + } else { + req.sql.field('SUM(CASE WHEN escola.qt_prof_admin = 88888 THEN 0 ELSE escola.qt_prof_admin END) + SUM(CASE WHEN escola.qtde_prof_servicos_gerais = 88888 THEN 0 ELSE escola.qtde_prof_servicos_gerais END) + SUM(CASE WHEN escola.qtde_prof_bibliotecario = 88888 THEN 0 ELSE escola.qtde_prof_bibliotecario END) + SUM(CASE WHEN escola.qtde_prof_saude = 88888 THEN 0 ELSE escola.qtde_prof_saude END) + SUM(CASE WHEN escola.qtde_prof_coordenador = 88888 THEN 0 ELSE escola.qtde_prof_coordenador END) + SUM(CASE WHEN escola.qtde_prof_fono = 88888 THEN 0 ELSE escola.qtde_prof_fono END) + SUM(CASE WHEN escola.qtde_prof_nutricionista = 88888 THEN 0 ELSE escola.qtde_prof_nutricionista END) + SUM(CASE WHEN escola.qtde_prof_psicologo = 88888 THEN 0 ELSE escola.qtde_prof_psicologo END) + SUM(CASE WHEN escola.qtde_prof_alimentacao = 88888 THEN 0 ELSE escola.qtde_prof_alimentacao END) + SUM(CASE WHEN escola.qtde_prof_pedagogia = 88888 THEN 0 ELSE escola.qtde_prof_pedagogia END) + SUM(CASE WHEN escola.qtde_prof_secretario = 88888 THEN 0 ELSE escola.qtde_prof_secretario END) + SUM(CASE WHEN escola.qtde_prof_seguranca = 88888 THEN 0 ELSE escola.qtde_prof_seguranca END) + SUM(CASE WHEN escola.qtde_prof_monitores = 88888 THEN 0 ELSE escola.qtde_prof_monitores END)', 'total') + .field("'Brasil'", 'name') + .field('escola.ano_censo', 'year') + .from('escola') + .group('escola.ano_censo') + .order('escola.ano_censo') + .where('(escola.situacao_funcionamento_pareada = 1) AND (escola.ensino_regular = 1 OR escola.ensino_eja = 1 OR escola.educacao_profissional = 1) AND (escola.dependencia_adm_id = 2 OR escola.dependencia_adm_id = 3 OR escola.dependencia_adm_id = 4) and ano_censo >= 2019'); + } + next(); + +}, rqfSchool.build(), query, rqfSchool.parse(), id2str.transform(), addMissing(rqfSchool), (req, res, next) => { + + if ("function" in req.dims) { + let aux_employes = formatFunction(req.result, req.dims); + req.allTeacher = formatFunction(req.allTeacher, req.dims); + req.schoolTable = aux_employes; + } else { + req.schoolTable = req.result + } + + if (req.filter.min_year <= 2018 && req.filter.max_year <= 2018) { + let aux_employees = req.allTeacher; + req.result = aux_employees; + } else if (req.filter.min_year >= 2019 && req.filter.max_year >= 2019) { + req.result = req.schoolTable; + } else if (req.filter.min_year <= 2018 && req.filter.max_year >= 2019) { + let aux_employees = req.allTeacher; + req.result = aux_employees.concat(req.schoolTable); + } + next(); +}, response('employees')); + +module.exports = employeesApp; diff --git a/src/libs/routes_v2/enrollment.js b/src/libs/routes_v2/enrollment.js new file mode 100644 index 0000000000000000000000000000000000000000..872593852ad783b18d3491405184d63132558872 --- /dev/null +++ b/src/libs/routes_v2/enrollment.js @@ -0,0 +1,1204 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); +const { result } = require('lodash'); + +const enrollmentApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const config = require(`${libs}/config`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +enrollmentApp.use(cache('15 day')); + +let rqf = new ReqQueryFields(); + +// Complete range of the enrollments dataset. +// Returns a tuple of start and ending years of the complete enrollments dataset. +enrollmentApp.get('/year_range', (req, res, next) => { + req.sql.from('matricula') + .field('MIN(matricula.ano_censo)', 'start_year') + .field('MAX(matricula.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +enrollmentApp.get('/years', (req, res, next) => { + req.sql.from('matricula') + .field('DISTINCT matricula.ano_censo', 'year'); + next(); +}, query, response('years')); + +enrollmentApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'matricula\''); + next(); +}, query, response('source')); + +enrollmentApp.get('/location', (req, res, next) => { + req.result = [ + {id: 1, name: 'Urbana'}, + {id: 2, name: 'Rural'} + ]; + next(); +}, response('location')); + +enrollmentApp.get('/diff_location', (req, res, next) => { + req.result = [ + {id: 0, name: "A escola não está em localidade diferenciada"}, + {id: 1, name: "Área de assentamento"}, + {id: 2, name: "Terra indígena"}, + {id: 3, name: "Terra remanescente de quilombos"}, + ]; + next(); +}, response('diff_location')); + +// Returns all school years available +enrollmentApp.get('/school_year', (req, res, next) => { + req.result = []; + for(let i = 11; i <= 71; ++i) { + let obj = { + id: i, + name: id2str.schoolYear(i) + }; + + if(obj.name !== id2str.schoolYear(99)) { + req.result.push(obj); + } + } + req.result.push({ + id: 99, + name: id2str.schoolYear(99) + }); + next(); +}, response('school_year')); + +// Returns all school years available +enrollmentApp.get('/education_level', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 74; ++i) { + let obj = { + id: i, + name: id2str.educationLevel(i) + }; + + if(obj.name !== id2str.educationLevel(99)) { + req.result.push(obj); + } + } + req.result.push({ + id: 99, + name: id2str.educationLevel(99) + }); + next(); +}, response('education_level')); + +// Returns all school years available +enrollmentApp.get('/education_level_mod', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 12; ++i) { + if (i == 3 || i == 6) + continue; + + req.result.push({ + id: i, + name: id2str.educationLevelMod(i) + }); + } + req.result.push({ + id: 99, + name: id2str.educationLevelMod(99) + }); + next(); +}, response('education_level_mod')); + +enrollmentApp.get('/education_level_short', (req, res, next) => { + req.result = [ + {id: null, name: 'Não classificada'}, + {id: 1, name: 'Creche'}, + {id: 2, name: 'Pré-Escola'}, + {id: 3, name: 'Ensino Fundamental - anos iniciais'}, + {id: 4, name: 'Ensino Fundamental - anos finais'}, + {id: 5, name: 'Ensino Médio'}, + {id: 6, name: 'EJA'}, + {id: 7, name: 'EE exclusiva'} + ]; + next(); +}, response('education_level_short')); + +// Returns all adm dependencies +enrollmentApp.get('/adm_dependency', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.admDependency(i) + }); + }; + next(); +}, response('adm_dependency')); + +enrollmentApp.get('/adm_dependency_detailed', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 8; ++i) { + req.result.push({ + id: i, + name: id2str.admDependencyPriv(i) + }); + }; + next(); +}, response('adm_dependency_detailed')); + +// Return genders +enrollmentApp.get('/gender', (req, res, next) => { + req.result = [ + {id: 1, name: 'Masculino'}, + {id: 2, name: 'Feminino'} + ]; + next(); +}, response('gender')); + +// Return ethnic group +enrollmentApp.get('/ethnic_group', (req, res, next) => { + req.result = []; + for(let i = 0; i <=5; ++i) { + req.result.push({ + id: i, + name: id2str.ethnicGroup(i) + }); + } + next(); +}, response('ethnic_group')); + +enrollmentApp.get('/period', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.period(i) + }); + } + req.result.push({ + id: 99, + name: id2str.period(99) + }); + next(); +}, response('period')); + +// Returns integral-time avaible +enrollmentApp.get('/integral_time', (req, res, next) => { + req.result = []; + for(let i = 0; i <= 2; ++i) { + req.result.push({ + id: i, + name: id2str.integralTime(i) + }); + } + next(); +}, response('integral_time')); + +enrollmentApp.get('/special_class', (req, res, next) => { + req.result = [ + {id: null, name: 'Não Declarado'}, + {id: 0, name: 'Não'}, + {id: 1, name: 'Sim'} + ]; + next(); +}, response('special_class')); + +enrollmentApp.get('/pee', (req, res, next) => { + req.result = [ + {id: true, name: id2str.booleanVariable(true)}, + {id: false, name: id2str.booleanVariable(false)} + ]; + next(); +}, response('pee')) + +enrollmentApp.get('/pee_por_categoria', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 14; ++i) { + req.result.push({ + id: i, + name: id2str.peePorCategoria(i) + }); + } + next(); +}, response('pee_por_categoria')); + +enrollmentApp.get('/age_range_all', (req, res, next) => { + req.result = [ + {id: 1, name: '0 a 3 anos'}, + {id: 2, name: '4 a 5 anos'}, + {id: 3, name: '6 a 10 anos'}, + {id: 4, name: '11 a 14 anos'}, + {id: 5, name: '15 a 17 anos'}, + {id: 6, name: '18 a 24 anos'}, + {id: 7, name: '25 a 29 anos'}, + {id: 8, name: '30 a 40 anos'}, + {id: 9, name: '41 a 50 anos'}, + {id: 10, name: '51 a 64 anos'}, + {id: 11, name: 'Mais que 64 anos'} + ]; + next(); +}, response('age_range_all')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'adm_dependency', + table: 'matricula', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}).addValue({ + name: 'adm_dependency_detailed', + table: 'matricula', + tableField: 'dependencia_adm_priv', + resultField: 'adm_dependency_detailed_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_priv' + } +}).addValue({ + name: 'school_year', + table: 'matricula', + tableField: 'serie_ano_id', + resultField: 'school_year_id', + where: { + relation: '=', + type: 'integer', + field: 'serie_ano_id' + } +}).addValue({ + name: 'education_level', + table: 'matricula', + tableField: 'etapa_ensino_id', + resultField: 'education_level_id', + where: { + relation: '=', + type: 'integer', + field: 'etapa_ensino_id' + } +}).addValue({ + name: 'education_level_mod', + table: 'matricula', + tableField: 'etapas_mod_ensino_segmento_id', + resultField: 'education_level_mod_id', + where: { + relation: '=', + type: 'integer', + field: 'etapas_mod_ensino_segmento_id' + } +}).addValue({ + name: 'education_level_short', + table: 'matricula', + tableField: 'etapa_resumida', + resultField: 'education_level_short_id', + where: { + relation: '=', + type: 'integer', + field: 'etapa_resumida' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'matricula' + } +}).addValue({ + name: 'mesoregion', + table: 'municipio', + tableField: ['nome_mesorregiao', 'mesorregiao_id'], + resultField: ['mesoregion_name', 'mesoregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'mesorregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'matricula' + } +}).addValue({ + name: 'microregion', + table: 'municipio', + tableField: ['nome_microrregiao', 'microrregiao_id'], + resultField: ['microregion_name', 'microregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'microrregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'matricula' + } +}).addValueToField({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'matricula' + } +}, 'dims').addValueToField({ + name: 'state', + table: 'estado', + tableField: 'nome', + resultField: 'state_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'matricula' + } +}, 'filter').addValueToField({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'matricula' + } +}, 'dims').addValueToField({ + name: 'city', + table: 'municipio', + tableField: 'nome', + resultField: 'city_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'matricula' + } +}, 'filter').addValueToField({ + name: 'school', + table: 'escola', + tableField: ['nome_escola', 'id'], + resultField: ['school_name', 'school_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id', 'ano_censo'], + foreign: ['escola_id', 'ano_censo'], + foreignTable: 'matricula' + } +}, 'dims').addValueToField({ + name: 'locale_id', + table: 'matricula', + tableField: 'localizacao_id', + resultField: 'locale_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}, 'dims').addValueToField({ + name: 'school_id', + table: 'escola', + tableField: 'id', + resultField: 'school_id', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id', 'ano_censo'], + foreign: ['escola_id', 'ano_censo'], + foreignTable: 'matricula' + } +}, 'dims').addValueToField({ + name: 'school', + table: 'escola', + tableField: 'nome_escola', + resultField: 'school_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id', 'ano_censo'], + foreign: ['escola_id', 'ano_censo'], + foreignTable: 'matricula' + } +}, 'filter').addValue({ + name: 'location', + table: 'matricula', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'diff_location', + table: 'matricula', + tableField: 'localizacao_diferenciada_par', + resultField: 'diff_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_diferenciada_par' + } +}).addValue({ + name: 'rural_location', + table: 'matricula', + tableField: 'localidade_area_rural', + resultField: 'rural_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localidade_area_rural' + } +}).addValue({ + name: 'min_year', + table: 'matricula', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'matricula', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'gender', + table: 'matricula', + tableField: 'sexo', + resultField: 'gender_id', + where: { + relation: '=', + type: 'integer', + field: 'sexo' + } +}).addValue({ + name: 'ethnic_group', + table: 'matricula', + tableField: 'cor_raca_id', + resultField: 'ethnic_group_id', + where: { + relation: '=', + type: 'integer', + field: 'cor_raca_id' + } +}).addValue({ + name: 'period', + table: 'matricula', + tableField: 'turma_turno_id', + resultField: 'period_id', + where: { + relation: '=', + type: 'integer', + field: 'turma_turno_id' + } +}).addValue({ + name:'integral_time', + table: 'matricula', + tableField: 'tempo_integral', + resultField: 'integral_time_id', + where: { + relation: '=', + type: 'integer', + field: 'tempo_integral' + } +}).addValue({ + name:'age_range_all', + table: 'matricula', + tableField: 'faixa_etaria_31_03', + resultField: 'age_range_all_id', + where: { + relation: '=', + type: 'integer', + field: 'faixa_etaria_31_03' + } +}).addValue({ + name:'special_class', + table: 'matricula', + tableField: 'exclusiva_especial', + resultField: 'special_class_id', + where: { + relation: '=', + type: 'boolean', + field: 'exclusiva_especial' + } +}).addValueToField({ + name: 'period_not', + table: 'matricula', + tableField: 'turma_turno_id', + resultField: 'period_id', + where: { + relation: '<>', + type: 'integer', + field: 'turma_turno_id' + } +}, 'filter') +.addValue({ + name: 'low_vision', + table: 'matricula', + tableField: 'baixa_visao', + resultField: 'low_vision', + where: { + relation: '=', + type: 'boolean', + field: 'baixa_visao' + } +}).addValue({ + name: 'blindness', + table: 'matricula', + tableField: 'cegueira', + resultField: 'blindness', + where: { + relation: '=', + type: 'boolean', + field: 'cegueira' + } +}).addValue({ + name: 'deafness', + table: 'matricula', + tableField: 'surdez', + resultField: 'deafness', + where: { + relation: '=', + type: 'boolean', + field: 'surdez' + } +}).addValue({ + name: 'hearing_deficiency', + table: 'matricula', + tableField: 'deficiencia_auditiva', + resultField: 'hearing_deficiency', + where: { + relation: '=', + type: 'boolean', + field: 'deficiencia_auditiva' + } +}).addValue({ + name: 'deafblindness', + table: 'matricula', + tableField: 'surdo_cegueira', + resultField: 'deafblindness', + where: { + relation: '=', + type: 'boolean', + field: 'surdo_cegueira' + } +}).addValue({ + name: 'physical_disability', + table: 'matricula', + tableField: 'deficiencia_fisica', + resultField: 'physical_disability', + where: { + relation: '=', + type: 'boolean', + field: 'deficiencia_fisica' + } +}).addValue({ + name: 'intellectual_disability', + table: 'matricula', + tableField: 'deficiencia_intelectual', + resultField: 'intellectual_disability', + where: { + relation: '=', + type: 'boolean', + field: 'deficiencia_intelectual' + } +}).addValue({ + name: 'multiple_disabilities', + table: 'matricula', + tableField: 'deficiencia_multiplas', + resultField: 'multiple_disabilities', + where: { + relation: '=', + type: 'boolean', + field: 'deficiencia_multiplas' + } +}).addValue({ + name: 'autism', + table: 'matricula', + tableField: 'autismo', + resultField: 'autism', + where: { + relation: '=', + type: 'boolean', + field: 'autismo' + } +}).addValue({ + name: 'autism_spectrum_disorder', + table: 'matricula', + tableField: 'transtorno_espectro_autista', + resultField: 'autism_spectrum_disorder', + where: { + relation: '=', + type: 'boolean', + field: 'transtorno_espectro_autista' + } +}).addValue({ + name: 'asperger_syndrom', + table: 'matricula', + tableField: 'sindrome_asperger', + resultField: 'asperger_syndrom', + where: { + relation: '=', + type: 'boolean', + field: 'sindrome_asperger' + } +}).addValue({ + name: 'rett_syndrom', + table: 'matricula', + tableField: 'sindrome_rett', + resultField: 'rett_syndrom', + where: { + relation: '=', + type: 'boolean', + field: 'sindrome_rett' + } +}).addValue({ + name: 'childhood_desintegrative_disorder', + table: 'matricula', + tableField: 'transtorno_desintegrativo_da_infancia', + resultField: 'childhood_desintegrative_disorder', + where: { + relation: '=', + type: 'boolean', + field: 'transtorno_desintegrativo_da_infancia' + } +}).addValue({ + name: 'supergifted', + table: 'matricula', + tableField: 'superdotado', + resultField: 'supergifted', + where: { + relation: '=', + type: 'boolean', + field: 'superdotado' + } +}).addValue({ + name: 'pee', + table: 'matricula', + tableField: 'possui_necessidade_especial', + resultField: 'pee_id', + where: { + relation: '=', + type: 'boolean', + field: 'possui_necessidade_especial' + } +}).addValue({ + name: 'pee_por_categoria', + table: 'matricula', + tableField: 'possui_necessidade_especial', + resultField: 'pee_por_categoria', + where: { + relation: '=', + type: 'boolean', + field: 'possui_necessidade_especial' + } +}); + +enrollmentApp.get('/', rqf.parse(), (req, res, next) => { + if('pee_por_categoria' in req.dims){ + delete req.dims.pee_por_categoria + req.pee_por_categoria = true + req.sql.field('SUM(CASE WHEN cegueira = true THEN 1 ELSE 0 END)', 'Cegueira') + .field('SUM(CASE WHEN baixa_visao = true THEN 1 ELSE 0 END)', 'Baixa visão') + .field('SUM(CASE WHEN surdez = true THEN 1 ELSE 0 END)', 'Surdez') + .field('SUM(CASE WHEN deficiencia_auditiva = true THEN 1 ELSE 0 END)', 'Deficiência auditiva') + .field('SUM(CASE WHEN surdo_cegueira = true THEN 1 ELSE 0 END)', 'Surdocegueira') + .field('SUM(CASE WHEN deficiencia_fisica = true THEN 1 ELSE 0 END)', 'Deficiência física') + .field('SUM(CASE WHEN deficiencia_intelectual = true THEN 1 ELSE 0 END)', 'Deficiência intelectual') + .field('SUM(CASE WHEN deficiencia_multiplas = true THEN 1 ELSE 0 END)', 'Deficiências múltiplas') + .field('SUM(CASE WHEN autismo = true THEN 1 ELSE 0 END)', 'Autismo') + .field('SUM(CASE WHEN transtorno_espectro_autista = true THEN 1 ELSE 0 END)', 'Transtorno do Espectro Autista (TEA)') + .field('SUM(CASE WHEN sindrome_asperger = true THEN 1 ELSE 0 END)', 'Síndrome de Asperger') + .field('SUM(CASE WHEN sindrome_rett = true THEN 1 ELSE 0 END)', 'Síndrome de Rett') + .field('SUM(CASE WHEN transtorno_desintegrativo_da_infancia = true THEN 1 ELSE 0 END)', 'Transtorno desintegrativo da infância') + .field('SUM(CASE WHEN superdotado = true THEN 1 ELSE 0 END)', 'Altas habilidades / Superdotação') + .field('matricula.ano_censo', 'year') + .from('matricula') + .group('matricula.ano_censo') + .order('matricula.ano_censo') + .where('((matricula.tipo<=3 OR matricula.tipo IS NULL) AND (matricula.tipo_atendimento_turma IS NULL OR matricula.tipo_atendimento_turma <= 2))'); + } + else{ + req.sql.field('COUNT(*)', 'total') + .field('matricula.ano_censo', 'year') + .from('matricula') + .group('matricula.ano_censo') + .order('matricula.ano_censo') + .where('((matricula.tipo<=3 OR matricula.tipo IS NULL) AND (matricula.tipo_atendimento_turma IS NULL OR matricula.tipo_atendimento_turma <= 2))'); + } + next(); +}, rqf.build(), query, id2str.transform(false), (req, res, next) => { + if(req.pee_por_categoria === true){ + let result = req.result; + let result_total = []; + for (var j = 0;j < result.length;j++){ + let result_parcial = result[j]; + for (var i in result_parcial){ + if(i !== 'year'){ + let obj = {}; + obj.total = result_parcial[i]; + i = i.replace(/"/g, ''); + obj.pee_por_categoria_name = i; + obj.year = result_parcial.year; + result_total.push(obj); + } + } + } + req.result= result_total; + } + next(); +}, response('enrollment')); + +enrollmentApp.get('/diagnosis', rqf.parse(), (req, res, next) => { + req.dims = {}; + req.dims.state = true; + req.dims.city = true; + req.dims.school_year = true; + req.dims.location = true; + req.dims.adm_dependency_detailed = true; + + req.sql.field('COUNT(*)', 'total') + .field("'Brasil'", 'name') + .field('matricula.ano_censo', 'year') + .from('matricula') + .group('matricula.ano_censo') + .order('matricula.ano_censo') + .where('matricula.tipo<=3'); + + next(); +}, rqf.build(), query, id2str.transform(), (req, res, next) => { + let enrollments = req.result; + + // Gera a relação etapa de ensino X ano escolar + let educationSchoolYear = {}; + for(let i = 10; i < 80; ++i) { + if(id2str.schoolYear(i) !== id2str.schoolYear(99)) { + let educationLevelId = Math.floor(i/10); + educationSchoolYear[i] = { + id: educationLevelId, + name: id2str.educationLevelShort(educationLevelId), + }; + } + } + + let result = []; + let educationLevelSet = new Set(); + let schoolYearSet = new Set(); + let i = 0; + while(i < enrollments.length) { + let enrollment = enrollments[i]; + if(!educationSchoolYear[enrollment.school_year_id]) { + ++i; + continue; + } + let educationLevelHash = '' + enrollment.year + educationSchoolYear[enrollment.school_year_id].id + enrollment.city_id; + let schoolYearHash = '' + enrollment.year + enrollment.school_year_id + enrollment.city_id; + + let currentEducation = null; + // Busca ou cria a etapa de ensino adequada + if(educationLevelSet.has(educationLevelHash)) { + let j = 0; + let edu = result[j]; + while(j < result.length && (edu.year != enrollment.year || edu.education_level_school_year_id != educationSchoolYear[enrollment.school_year_id].id)) { + ++j; + edu = result[j]; + } + if(j >= result.length) --j; + edu = result[j]; + + currentEducation = edu; + } else { + educationLevelSet.add(educationLevelHash); + let obj = { + year: enrollment.year, + name: enrollment.name, + state_id: enrollment.state_id, + state_name: enrollment.state_name, + city_id: enrollment.city_id, + city_name: enrollment.city_name, + education_level_school_year_id: educationSchoolYear[enrollment.school_year_id].id, + education_level_school_year_name: educationSchoolYear[enrollment.school_year_id].name, + total: 0, + adm_dependencies: [ + { + adm_dependency_detailed_id: enrollment.adm_dependency_detailed_id, + adm_dependency_detailed_name: enrollment.adm_dependency_detailed_name, + total: 0 + } + ], + locations: [ + { + location_id: enrollment.location_id, + location_name: enrollment.location_name, + total: 0 + } + ] + }; + + result.push(obj); + currentEducation = obj; + } + + let currentSchoolYear = null; + // Busca ou cria a série adequada + if(schoolYearSet.has(schoolYearHash)) { + let j = 0; + let edu = result[j]; + while(j < result.length && (edu.year != enrollment.year || edu.education_level_school_year_id != enrollment.school_year_id)) { + ++j; + edu = result[j]; + } + if(j >= result.length) --j; + edu = result[j]; + + currentSchoolYear = edu; + } else { + schoolYearSet.add(schoolYearHash); + let obj = { + year: enrollment.year, + name: enrollment.name, + state_id: enrollment.state_id, + state_name: enrollment.state_name, + city_id: enrollment.city_id, + city_name: enrollment.city_name, + education_level_school_year_id: enrollment.school_year_id, + education_level_school_year_name: enrollment.school_year_name, + total: 0, + adm_dependencies: [ + { + adm_dependency_detailed_id: enrollment.adm_dependency_detailed_id, + adm_dependency_detailed_name: enrollment.adm_dependency_detailed_name, + total: 0 + } + ], + locations: [ + { + location_id: enrollment.location_id, + location_name: enrollment.location_name, + total: 0 + } + ] + }; + + result.push(obj); + currentSchoolYear = obj; + } + + // Adiciona ao total + currentEducation.total += enrollment.total; + currentSchoolYear.total += enrollment.total; + + // Adiciona ao total da dependência administrativa + let admDependencyIndex = 0; + let admDependency = currentEducation.adm_dependencies[admDependencyIndex]; + while (admDependencyIndex < currentEducation.adm_dependencies.length && enrollment.adm_dependency_detailed_id > admDependency.adm_dependency_detailed_id) { + ++admDependencyIndex; + admDependency = currentEducation.adm_dependencies[admDependencyIndex]; + } + if(admDependencyIndex >= currentEducation.adm_dependencies.length || admDependency.adm_dependency_detailed_id != enrollment.adm_dependency_detailed_id) { // não encontrou + let obj = { + adm_dependency_detailed_id: enrollment.adm_dependency_detailed_id, + adm_dependency_detailed_name: enrollment.adm_dependency_detailed_name, + total: 0 + } + currentEducation.adm_dependencies.splice(admDependencyIndex, 0, obj); + admDependency = obj; + } + admDependency.total += enrollment.total; + + admDependencyIndex = 0; + admDependency = currentSchoolYear.adm_dependencies[admDependencyIndex]; + while (admDependencyIndex < currentSchoolYear.adm_dependencies.length && enrollment.adm_dependency_detailed_id > admDependency.adm_dependency_detailed_id) { + ++admDependencyIndex; + admDependency = currentSchoolYear.adm_dependencies[admDependencyIndex]; + } + if(admDependencyIndex >= currentSchoolYear.adm_dependencies.length || admDependency.adm_dependency_detailed_id != enrollment.adm_dependency_detailed_id) { // não encontrou + let obj = { + adm_dependency_detailed_id: enrollment.adm_dependency_detailed_id, + adm_dependency_detailed_name: enrollment.adm_dependency_detailed_name, + total: 0 + } + currentSchoolYear.adm_dependencies.splice(admDependencyIndex, 0, obj); + admDependency = obj; + } + admDependency.total += enrollment.total; + + // Adiciona ao total da localidade + let locationIndex = 0; + let location = currentEducation.locations[locationIndex]; + while (locationIndex < currentEducation.locations.length && enrollment.location_id > location.location_id) { + ++locationIndex; + location = currentEducation.locations[locationIndex]; + } + if(locationIndex >= currentEducation.locations.length || location.location_id != enrollment.location_id) { + let obj = { + location_id: enrollment.location_id, + location_name: enrollment.location_name, + total: 0 + } + currentEducation.locations.splice(locationIndex, 0, obj); + location = obj; + } + location.total += enrollment.total; + + locationIndex = 0; + location = currentSchoolYear.locations[locationIndex]; + while (locationIndex < currentSchoolYear.locations.length && enrollment.location_id > location.location_id) { + ++locationIndex; + location = currentSchoolYear.locations[locationIndex]; + } + if(locationIndex >= currentSchoolYear.locations.length || location.location_id != enrollment.location_id) { + let obj = { + location_id: enrollment.location_id, + location_name: enrollment.location_name, + total: 0 + } + currentSchoolYear.locations.splice(locationIndex, 0, obj); + location = obj; + } + location.total += enrollment.total; + + ++i; + } + + req.result = result; + + next(); +}, response('enrollment_diagnosis')); + +enrollmentApp.get('/projection', rqf.parse(), (req, res, next) => { + req.dims = {}; + req.dims.state = true; + req.dims.city = true; + req.dims.location = true; + req.dims.school_year = true; + req.dims.adm_dependency = true; + req.dims.period = true; + req.filter.adm_dependency = [1,2,3]; + + req.sql.field('COUNT(*)', 'total') + .field("'Brasil'", 'name') + .field('matricula.ano_censo', 'year') + .from('matricula') + .group('matricula.ano_censo') + .order('matricula.ano_censo') + .where('matricula.tipo<=3'); + + next(); +}, rqf.build(), query, id2str.transform(), (req, res, next) => { + let enrollments = req.result; + + // Gera a relação etapa de ensino X ano escolar + let educationSchoolYear = {}; + for(let i = 10; i < 80; ++i) { + if(id2str.schoolYear(i) !== id2str.schoolYear(99)) { + let educationLevelId = Math.floor(i/10); + educationSchoolYear[i] = { + id: educationLevelId, + name: id2str.educationLevelShort(educationLevelId), + }; + } + } + + let result = []; + let educationLevelSet = new Set(); + let schoolYearSet = new Set(); + let i = 0; + while(i < enrollments.length) { + let enrollment = enrollments[i]; + if(!educationSchoolYear[enrollment.school_year_id]) { + ++i; + continue; + } + let educationLevelHash = '' + enrollment.year + educationSchoolYear[enrollment.school_year_id].id + enrollment.city_id; + let schoolYearHash = '' + enrollment.year + enrollment.school_year_id + enrollment.city_id; + + let currentEducation = null; + // Busca ou cria a etapa de ensino adequada + if(educationLevelSet.has(educationLevelHash)) { + let j = 0; + let edu = result[j]; + while(j < result.length && (edu.year != enrollment.year || edu.education_level_school_year_id != educationSchoolYear[enrollment.school_year_id].id)) { + ++j; + edu = result[j]; + } + if((j >= result.length)) --j; + edu = result[j]; + + currentEducation = edu; + } else { + educationLevelSet.add(educationLevelHash); + let obj = { + year: enrollment.year, + name: enrollment.name, + state_id: enrollment.state_id, + state_name: enrollment.state_name, + city_id: enrollment.city_id, + city_name: enrollment.city_name, + education_level_school_year_id: educationSchoolYear[enrollment.school_year_id].id, + education_level_school_year_name: educationSchoolYear[enrollment.school_year_id].name, + urban_day_total: 0, + urban_night_total: 0, + rural_day_total: 0, + rural_night_total: 0 + }; + result.push(obj); + currentEducation = obj; + } + + let currentSchoolYear = null; + // Busca ou cria a série adequada + if(schoolYearSet.has(schoolYearHash)) { + let j = 0; + let edu = result[j]; + while(j < result.length && (edu.year != enrollment.year || edu.education_level_school_year_id != enrollment.school_year_id)){ + ++j; + edu = result[j]; + } + if(j >= result.length) --j; + edu = result[j]; + + currentSchoolYear = edu; + } else { + schoolYearSet.add(schoolYearHash); + let obj = { + year: enrollment.year, + name: enrollment.name, + state_id: enrollment.state_id, + state_name: enrollment.state_name, + city_id: enrollment.city_id, + city_name: enrollment.city_name, + education_level_school_year_id: enrollment.school_year_id, + education_level_school_year_name: enrollment.school_year_name, + urban_day_total: 0, + urban_night_total: 0, + rural_day_total: 0, + rural_night_total: 0 + }; + + result.push(obj); + currentSchoolYear = obj; + } + + if(enrollment.location_id == 1) { + if(enrollment.period_id < 3) { + currentEducation.urban_day_total += enrollment.total; + currentSchoolYear.urban_day_total += enrollment.total; + } else { + currentEducation.urban_night_total += enrollment.total; + currentSchoolYear.urban_night_total += enrollment.total; + } + } else { + if(enrollment.period_id < 3) { + currentEducation.rural_day_total += enrollment.total; + currentSchoolYear.rural_day_total += enrollment.total; + } else { + currentEducation.rural_night_total += enrollment.total; + currentSchoolYear.rural_night_total += enrollment.total; + } + } + + ++i; + } + + req.result = result; + + next(); +}, response('enrollment_projection')); + +module.exports = enrollmentApp; diff --git a/src/libs/routes_v2/enrollmentProjection.js b/src/libs/routes_v2/enrollmentProjection.js new file mode 100644 index 0000000000000000000000000000000000000000..4dd92e5df7985a6bb34632dfc3b4a685c5873e64 --- /dev/null +++ b/src/libs/routes_v2/enrollmentProjection.js @@ -0,0 +1,239 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const enrollmentProjectionApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const config = require(`${libs}/config`); + +let rqf = new ReqQueryFields(); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValueToField({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'projecao_matricula_por_dependencia' + } +}, 'dims').addValueToField({ + name: 'state', + table: 'estado', + tableField: 'nome', + resultField: 'state_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'projecao_matricula_por_dependencia' + } +}, 'filter').addValueToField({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'projecao_matricula_por_dependencia' + } +}, 'dims').addValueToField({ + name: 'city', + table: 'municipio', + tableField: 'nome', + resultField: 'city_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'projecao_matricula_por_dependencia' + } +}, 'filter').addValue({ + name: 'min_year', + table: 'projecao_matricula_por_dependencia', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'projecao_matricula_por_dependencia', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'adm_dependency', + table: 'projecao_matricula_por_dependencia', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}); + +enrollmentProjectionApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.field("'Brasil'", 'name') + .field('SUM(projecao_matricula_por_dependencia.urbano_dia_total)', 'urban_day_total') + .field('SUM(projecao_matricula_por_dependencia.urbano_noite_total)', 'urban_night_total') + .field('SUM(projecao_matricula_por_dependencia.rural_dia_total)', 'rural_day_total') + .field('SUM(projecao_matricula_por_dependencia.rural_noite_total)', 'rural_night_total') + .field('projecao_matricula_por_dependencia.etapa_ensino_escola_ano_id', 'education_level_school_year_id') + .field('projecao_matricula_por_dependencia.ano_censo', 'year') + .from('projecao_matricula_por_dependencia') + .where('projecao_matricula_por_dependencia.etapa_ensino_escola_ano_id <> 7 AND projecao_matricula_por_dependencia.etapa_ensino_escola_ano_id < 71') + .group('projecao_matricula_por_dependencia.etapa_ensino_escola_ano_id') + .group('projecao_matricula_por_dependencia.ano_censo') + .order('projecao_matricula_por_dependencia.ano_censo') + .order('projecao_matricula_por_dependencia.etapa_ensino_escola_ano_id'); + + next(); +}, query, id2str.transform(), (req, res, next) => { + + let result = []; + let i = 0; + let j = 1; + let base_year = req.result[0].year; + + let hashSet = new Set(); + let atual_city_name; + let atual_city_id; + let atual_state_name; + let atual_state_id; + while (i < req.result.length || j <= 63) { // Adciona séries não existentes no banco com 0 nos totais. + let atual = req.result[i]; + if (j > 63) { // Caso j passou da última série existente, mudamos de dimensão. + j = 1; + + if (base_year !== atual.year) { + base_year = atual.year; + hashSet = new Set(); + } + } + if (id2str.educationLevelSchoolYear(j) === id2str.educationLevelSchoolYear(99) || j === 7) { + j++; + continue; + } + + if (j == 1) { + let hash = "" + if ('state' in req.dims) + hash += atual.state_id; + if ('city' in req.dims) + hash += atual.city_id; + + if (!hashSet.has(hash)) { + hashSet.add(hash); + atual_city_id = atual.city_id; + atual_city_name = atual.city_name; + atual_state_id = atual.state_id; + atual_state_name = atual.state_name; + } + } + + if (atual !== undefined && atual.education_level_school_year_id === j) { // Série existe. + atual.urban_day_total = parseInt(atual.urban_day_total, 10); + atual.urban_night_total = ((atual.education_level_school_year_id >= 3 && atual.education_level_school_year_id < 10) || (atual.education_level_school_year_id >= 30)) ? parseInt(atual.urban_night_total, 10) : 0; //Não conta matrículas noturnas da pré-escola e da creche + atual.rural_day_total = parseInt(atual.rural_day_total, 10); + atual.rural_night_total = ((atual.education_level_school_year_id >= 3 && atual.education_level_school_year_id < 10) || (atual.education_level_school_year_id >= 30)) ? parseInt(atual.rural_night_total, 10) : 0; + result.push(atual); + + i++; + } + else { // Série não existe, adcionamos 0 ao resultado. + let base_result = { + name: req.result[0].name, + urban_day_total: 0, + urban_night_total: 0, + rural_day_total: 0, + rural_night_total: 0, + education_level_school_year_id: j, + year: base_year, + education_level_school_year_name: id2str.educationLevelSchoolYear(j) + }; + + if ('city' in req.dims) { // adciona os campos de cidade e/ou estado + base_result.city_id = atual_city_id; + base_result.city_name = atual_city_name; + } + if ('state' in req.dims) { + base_result.state_id = atual_state_id; + base_result.state_name = atual_state_name; + } + + result.push(base_result) + } + j++; + } + + req.result = result; + next(); +}, response('enrollment_projection')); + +module.exports = enrollmentProjectionApp; diff --git a/src/libs/routes_v2/financial.js b/src/libs/routes_v2/financial.js new file mode 100644 index 0000000000000000000000000000000000000000..dab9dfe8f107ab4a16c94e8c2f7f3f2340baba21 --- /dev/null +++ b/src/libs/routes_v2/financial.js @@ -0,0 +1,186 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const financialApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +financialApp.get('/year_range', (req, res, next) => { + req.sql.from('indicadores_financeiros') + .field('MIN(indicadores_financeiros.ano_censo)', 'start_year') + .field('MAX(indicadores_financeiros.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +financialApp.get('/years', (req, res, next) => { + req.sql.from('indicadores_financeiros') + .field('DISTINCT indicadores_financeiros.ano_censo', 'year'); + next(); +}, query, response('years')); + +financialApp.get('/sphere_adm', (req, res, next) => { + req.result = [ + {id: 1, name: "1"}, + {id: 2, name: "2"} + ] + next(); +}, response('sphere_adm')); + +financialApp.get('/financial_data', (req, res, next) => { + req.sql.from('indicadores_financeiros') + .field('DISTINCT indicadores_financeiros.dados_financeiros', 'financial_data'); + next(); +}, query, response('financial_data')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['sigla', 'id'], + resultField: ['sigla_uf', 'cod_uf'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'indicadores_financeiros' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'indicadores_financeiros' + } +}).addValue({ + name: 'min_year', + table: 'indicadores_financeiros', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: 'indicadores_financeiros', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'indicadores_financeiros', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: 'indicadores_financeiros', + field: 'ano_censo' + } +}).addValue({ + name: 'sphere_adm', + table: 'indicadores_financeiros', + tableField: 'esfera_adm', + resultField: 'sphere_adm_id', + where: { + relation: '=', + type: 'integer', + field: 'esfera_adm' + } +}).addValue({ + name: 'city', + table: 'indicadores_financeiros', + tableField: 'municipio_id', + resultField: 'city_id', + where: { + relation: '=', + type: 'integer', + field: 'municipio_id' + } +}).addValue({ + name: 'financial_data', + table: 'indicadores_financeiros', + tableField: 'dados_financeiros', + resultField: 'financial_data_id', + where: { + relation: '=', + type: 'integer', + field: 'dados_financeiros' + } +}); + +financialApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + if ("state" in req.filter) { + req.sql.from('indicadores_financeiros') + .field('indicadores_financeiros.estado_id', 'state_id') + .field('indicadores_financeiros.ano_censo', 'year') + .field('estado.sigla', 'state_abbreviation') + .field('indicadores_financeiros.valor', 'valor') + .field('indicadores_financeiros.esfera_adm', 'sphere_adm_id') + .field('indicadores_financeiros.dados_financeiros', 'financial_data_id') + .group('indicadores_financeiros.ano_censo') + .group('indicadores_financeiros.estado_id') + .group('estado.sigla') + .group('indicadores_financeiros.valor') + .group('indicadores_financeiros.dados_financeiros') + .group('indicadores_financeiros.esfera_adm') + } else { + req.sql.from('indicadores_financeiros') + .field('indicadores_financeiros.estado_id', 'state_id') + .field('indicadores_financeiros.ano_censo', 'year') + .field('estado.sigla', 'state_abbreviation') + .field('indicadores_financeiros.valor', 'valor') + .field('indicadores_financeiros.esfera_adm', 'sphere_adm_id') + .field('indicadores_financeiros.dados_financeiros', 'financial_data_id') + .join('estado', null, 'indicadores_financeiros.estado_id=estado.id') + .group('indicadores_financeiros.ano_censo') + .group('indicadores_financeiros.estado_id') + .group('estado.sigla') + .group('indicadores_financeiros.valor') + .group('indicadores_financeiros.dados_financeiros') + .group('indicadores_financeiros.esfera_adm') + } + next(); +}, query, id2str.transform(), response('financial')); + +module.exports = financialApp; diff --git a/src/libs/routes_v2/glossEnrollmentRatio.js b/src/libs/routes_v2/glossEnrollmentRatio.js new file mode 100644 index 0000000000000000000000000000000000000000..ab57e325096c56fa71287d38b4185f29ddf5c1bf --- /dev/null +++ b/src/libs/routes_v2/glossEnrollmentRatio.js @@ -0,0 +1,390 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const glossEnrollmentRatioApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const multiQuery = require(`${libs}/middlewares/multiQuery`); + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +glossEnrollmentRatioApp.use(cache('15 day')); + +// Complete range of the enrollments dataset. +// Returns a tuple of start and ending years of the complete enrollments dataset. +glossEnrollmentRatioApp.get('/year_range', (req, res, next) => { + req.sql.from('pnad') + .field('DISTINCT pnad.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + req.oldResult = req.result; + + req.sql = squel.select(); + + req.sql.from('matricula') + .field('DISTINCT matricula.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + let distinct_years = []; + let new_result = []; + for (let i = 0; i < req.oldResult.length; i++) { + for (let j = 0; j < req.result.length; j++) { + if(req.oldResult[i].year == req.result[j].year) { + distinct_years.push(req.oldResult[i]); + } + } + } + new_result.push({start_year: distinct_years[distinct_years.length -1].year, end_year: distinct_years[0].year}); + req.result = new_result; + next(); +}, response('range')); + +glossEnrollmentRatioApp.get('/years', (req, res, next) => { + req.sql.from('pnad') + .field('DISTINCT pnad.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + req.oldResult = req.result; + + req.sql = squel.select(); + + req.sql.from('matricula') + .field('DISTINCT matricula.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + let new_result = [] + for (let i = 0; i < req.oldResult.length; i++) { + for (let j = 0; j < req.result.length; j++) { + if(req.oldResult[i].year == req.result[j].year) { + new_result.push(req.oldResult[i]); + } + } + } + req.result = new_result; + next(); +}, response('years')); + +glossEnrollmentRatioApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'pnad\''); + next(); +}, query, response('source')); + +glossEnrollmentRatioApp.get('/education_level_short', (req, res, next) => { + req.result = [ + {id: null, name: 'Não classificada'}, + {id: 1, name: 'Creche'}, + {id: 2, name: 'Pré-Escola'}, + {id: 3, name: 'Ensino Fundamental - anos iniciais'}, + {id: 4, name: 'Ensino Fundamental - anos finais'}, + {id: 5, name: 'Ensino Médio'} + ]; + next(); +}, response('education_level_short')); + +glossEnrollmentRatioApp.get('/gender', (req, res, next) => { + req.result = [ + {id: 1, name: 'Masculino'}, + {id: 2, name: 'Feminino'} + ]; + next(); +}, response('gender')); + +glossEnrollmentRatioApp.get('/ethnic_group', (req, res, next) => { + req.result = [ + {id: 0, name: 'Sem declaração'}, + {id: 1, name: 'Branca'}, + {id: 2, name: 'Preta'}, + {id: 3, name: 'Parda'}, + {id: 4, name: 'Amarela'}, + {id: 5, name: 'Indígena'} + ]; + next(); +}, response('ethnic_group')); + +glossEnrollmentRatioApp.get('/location', (req, res, next) => { + req.result = [ + {id: 1, name: 'Urbana'}, + {id: 2, name: 'Rural'} + ]; + next(); +}, response('location')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: '@' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: '@' + } +}).addValue({ + name: 'ethnic_group', + table: '@', + tableField: 'cor_raca_id', + resultField: 'ethnic_group_id', + where: { + relation: '=', + type: 'integer', + field: 'cor_raca_id' + } +}).addValue({ + name: 'min_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'gender', + table: '@', + tableField: 'sexo', + resultField: 'gender_id', + where: { + relation: '=', + type: 'integer', + field: 'sexo' + } +}).addValue({ + name: 'location', + table: '@', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'education_level_short', + table: 'matricula', + tableField: 'etapa_resumida', + resultField: 'education_level_short_id', + where: { + relation: '=', + type: 'integer', + field: 'etapa_resumida' + } +}); + +function matchQueries(queryTotal, queryPartial) { + let match = []; + queryPartial.forEach((result) => { + let newObj = {}; + let keys = Object.keys(result); + keys.forEach((key) => { + newObj[key] = result[key]; + }); + // console.log('NEW OBJ'); + // console.log(newObj); + // remove total + let index = keys.indexOf('total'); + if(index > -1) keys.splice(index, 1); + // remove education_level_short_id + index = keys.indexOf('education_level_short_id'); + if(index > -1) keys.splice(index, 1); + // remove education_level_short_name + index = keys.indexOf('education_level_short_name'); + if(index > -1) keys.splice(index, 1); + let objMatch = null; + + for(let i = 0; i < queryTotal.length; ++i) { + let total = queryTotal[i]; + let foundMatch = true; + for(let j = 0; j < keys.length; ++j) { + let key = keys[j]; + if(total[key] !== result[key]) { + foundMatch = false; + break; + } + } + if(foundMatch) { + objMatch = total; + break; + } + } + + if(objMatch) { + // console.log('MATCH!!!!'); + // console.log(objMatch); + newObj.total = (result.total / objMatch.total) * 100; + newObj.partial = result.total; + newObj.denominator = objMatch.total + match.push(newObj); + } + }); + // console.log('TAMANHOS'); + // console.log(queryTotal.length); + // console.log(queryPartial.length); + // console.log(match.length); + return match; +} + +glossEnrollmentRatioApp.get('/', rqf.parse(),(req, res, next) => { + req.numerator = {}; + req.denominator = {}; + let glossEnrollmentRatioApp = {}; + + req.sql.from('matricula') + .field('count(*)', 'total') + .field('matricula.ano_censo', 'year') + .group('matricula.ano_censo') + .order('matricula.ano_censo') + .where('matricula.tipo <= 3') + + if ( "education_level_short" in req.dims ) { + req.sql.field('matricula.etapa_resumida', 'age_range') + req.sql.where('matricula.etapa_resumida = 1 OR matricula.etapa_resumida = 2 OR matricula.etapa_resumida = 3 OR matricula.etapa_resumida = 4 OR matricula.etapa_resumida = 5') + req.sql.group('matricula.etapa_resumida', 'age_range'); + } + next(); +}, rqf.build(), query, id2str.transform(), (req, res, next) => { + req.numerator = req.result; + req.resetSql(); + req.sql.field('sum(peso)', 'total') + .field('pnad.ano_censo','year') + .from('pnad') + .group('pnad.ano_censo') + .order('pnad.ano_censo') + + function convert(result) { + if (result == 1) { + return 'pnad.faixa_etaria_31_03 = 1' + } else if (result == 2) { + return 'pnad.faixa_etaria_31_03 = 2' + } else if (result == 4) { + return 'pnad.faixa_etaria_31_03 = 3' + } else if (result == 5) { + return 'pnad.faixa_etaria_31_03 = 4' + } else if (result == 6) { + return 'pnad.faixa_etaria_31_03 = 5' + } + } + + //remove education_level_short how filter and add faixa_etaria_31_03 in filter + if ("education_level_short" in req.filter) { + if (Array.isArray(req.filter.education_level_short)) { + var string_query = ''; + for(let i = 0; i < req.filter.education_level_short.length - 1; i++) { + string_query = string_query + convert(req.filter.education_level_short[i]) + ' OR '; + } + string_query = string_query + convert(req.filter.education_level_short[req.filter.education_level_short.length - 1]); + req.sql.where(string_query); + req.sql.field('pnad.faixa_etaria_31_03','age_range') + req.sql.group('pnad.faixa_etaria_31_03', 'age_range') + } + } else if ( "education_level_short" in req.dims ) { + req.sql.field('pnad.faixa_etaria_31_03','age_range') + req.sql.where('pnad.faixa_etaria_31_03 = 1 OR pnad.faixa_etaria_31_03 = 2 OR pnad.faixa_etaria_31_03 = 3 OR pnad.faixa_etaria_31_03 = 4 OR pnad.faixa_etaria_31_03 = 5') + req.sql.group('pnad.faixa_etaria_31_03', 'age_range'); + } else { + res.status(400); + next({ + status: 400, + message: 'Wrong/No filter specified' + }); + } + + next(); +}, rqf.parse(), (req, res, next) => { + if ("education_level_short" in req.filter) { + delete req.filter.education_level_short; + } + if ("education_level_short" in req.dims) { + delete req.dims.education_level_short; + } + next(); +}, rqf.build(), query, id2str.transform(), (req, res, next) => { + req.denominator = req.result; + req.result = [] + let glossEnrollment = matchQueries(req.denominator, req.numerator); + req.result = glossEnrollment; + + next(); +}, response('glossEnrollmentRatio')); + +module.exports = glossEnrollmentRatioApp; diff --git a/src/libs/routes_v2/idhm.js b/src/libs/routes_v2/idhm.js new file mode 100644 index 0000000000000000000000000000000000000000..5b941793f366742ff6dd43278046f4c5717f6441 --- /dev/null +++ b/src/libs/routes_v2/idhm.js @@ -0,0 +1,212 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const idhmApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +idhmApp.use(cache('15 day')); + +idhmApp.get('/year_range', (req, res, next) => { + req.sql.from('adh_idh') + .field('MIN(adh_idh.ano_censo)', 'start_year') + .field('MAX(adh_idh.ano_censo)', 'end_year'); + next(); +}, query, (req, res, next) => { + req.sql.from('adh_idh_uf') + .field('MIN(adh_idh_uf.ano_censo)', 'start_year') + .field('MAX(adh_idh_uf.ano_censo)', 'end_year'); + req.old_result = req.result; + next(); +}, query, (req, res, next) => { + if (req.old_result[0].start_year < req.result[0].start_year) { + req.result[0].start_year = req.old_result[0].start_year; + } + if (req.old_result[0].end_year > req.result[0].end_year) { + req.result[0].end_year = req.old_result[0].old_result; + } + next(); +}, query, response('range')); + +idhmApp.get('/years', (req, res, next) => { + req.sql.from('adh_idh') + .field('DISTINCT adh_idh.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + req.oldResult = req.result; + + req.sql = squel.select(); + + req.sql.from('adh_idh_uf') + .field('DISTINCT adh_idh_uf.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + let result = Object.assign(req.oldResult, req.result); + req.result = result; + next(); +}, response('years')); + +idhmApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'adh_idh\''); + next(); +}, query, response('source')); + +idhmApp.get('/IDHM_level', (req, res, next) => { + req.result = [ + {id: null, name: 'Não classificada'}, + {id: 1, name: 'Muito Baixa'}, + {id: 2, name: 'Baixo'}, + {id: 3, name: 'Médio'}, + {id: 4, name: 'Alto'}, + {id: 5, name: 'Muito Alto'} + ]; + next(); +}, response('IDHM_level')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'adh_idh' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'adh_idh' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: '@' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: '@' + } +}).addValue({ + name: 'min_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'idhm_level', + table: '@', + tableField: 'idhm_nivel', + resultField: 'idhm_level_id', + where: { + relation: '=', + type: 'integer', + table: '@', + field: 'idhm_nivel' + } +}); + + +idhmApp.get('/', rqf.parse(), (req, res, next) => { + if (("city" in req.dims) || ("city" in req.filter)) { + req.sql.from('adh_idh') + .field('adh_idh.idhm', 'total') + .field('adh_idh.ano_censo', 'year') + .field('adh_idh.municipio_id', 'city_id') + .field('adh_idh.estado_id', 'state_id') + .group('adh_idh.idhm') + .group('adh_idh.ano_censo') + .group('adh_idh.municipio_id') + .group('adh_idh.estado_id') + } else if (("state" in req.filter) || ("state" in req.dims)) { + req.sql.from('adh_idh_uf') + .field('adh_idh_uf.idhm', 'total') + .field('adh_idh_uf.ano_censo', 'year') + .field('adh_idh_uf.estado_id', 'state_id') + .group('adh_idh_uf.idhm') + .group('adh_idh_uf.ano_censo') + .group('adh_idh_uf.estado_id') + } else { + res.status(400); + next({ + status: 400, + message: 'Wrong/No filter specified' + }); + } + next(); +}, rqf.build(), query, addMissing(rqf), id2str.transform(), response('idhm')); + +module.exports = idhmApp; diff --git a/src/libs/routes_v2/idhme.js b/src/libs/routes_v2/idhme.js new file mode 100644 index 0000000000000000000000000000000000000000..1b492c610de2c79ecf77b5b378d2e72616536fd6 --- /dev/null +++ b/src/libs/routes_v2/idhme.js @@ -0,0 +1,185 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const idhmeApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +idhmeApp.use(cache('15 day')); + +idhmeApp.get('/year_range', (req, res, next) => { + req.sql.from('adh_idh') + .field('MIN(adh_idh.ano_censo)', 'start_year') + .field('MAX(adh_idh.ano_censo)', 'end_year'); + next(); +}, query, (req, res, next) => { + req.sql.from('adh_idh_uf') + .field('MIN(adh_idh_uf.ano_censo)', 'start_year') + .field('MAX(adh_idh_uf.ano_censo)', 'end_year'); + req.old_result = req.result; + next(); +}, query, (req, res, next) => { + if (req.old_result[0].start_year < req.result[0].start_year) { + req.result[0].start_year = req.old_result[0].start_year; + } + if (req.old_result[0].end_year > req.result[0].end_year) { + req.result[0].end_year = req.old_result[0].old_result; + } + next(); +}, query, response('range')); + +idhmeApp.get('/years', (req, res, next) => { + req.sql.from('adh_idh') + .field('DISTINCT adh_idh.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + req.oldResult = req.result; + + req.sql = squel.select(); + + req.sql.from('adh_idh_uf') + .field('DISTINCT adh_idh_uf.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + let result = Object.assign(req.oldResult, req.result); + req.result = result; + next(); +}, response('years')); + +idhmeApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'adh_idh\''); + next(); +}, query, response('source')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'adh_idh' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'adh_idh' + } +}).addValue({ + name: 'min_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: '@' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: '@' + } +}); + +idhmeApp.get('/', rqf.parse(), (req, res, next) => { + + if (("city" in req.dims) || ("city" in req.filter)) { + req.sql.from('adh_idh') + .field('adh_idh.idhm_e', 'total') + .field('adh_idh.ano_censo', 'year') + .field('adh_idh.municipio_id', 'city_id') + .group('adh_idh.idhm_e') + .group('adh_idh.ano_censo') + .group('adh_idh.municipio_id'); + } else if (("state" in req.filter) || ("state" in req.dims)) { + req.sql.from('adh_idh_uf') + .field('adh_idh_uf.idhm_e', 'total') + .field('adh_idh_uf.ano_censo', 'year') + .field('adh_idh_uf.estado_id', 'state_id') + .group('adh_idh_uf.idhm_e') + .group('adh_idh_uf.ano_censo') + .group('adh_idh_uf.estado_id'); + } else { + res.status(400); + next({ + status: 400, + message: 'Wrong/No filter specified' + }); + } + next(); +}, rqf.build(), query, addMissing(rqf), id2str.transform(), response('idhme')); + +module.exports = idhmeApp; diff --git a/src/libs/routes_v2/idhml.js b/src/libs/routes_v2/idhml.js new file mode 100644 index 0000000000000000000000000000000000000000..eee89ddf8c0f918db089ab5f5f5e3249f15d05d0 --- /dev/null +++ b/src/libs/routes_v2/idhml.js @@ -0,0 +1,185 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const idhmlApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +idhmlApp.use(cache('15 day')); + +idhmlApp.get('/year_range', (req, res, next) => { + req.sql.from('adh_idh') + .field('MIN(adh_idh.ano_censo)', 'start_year') + .field('MAX(adh_idh.ano_censo)', 'end_year'); + next(); +}, query, (req, res, next) => { + req.sql.from('adh_idh_uf') + .field('MIN(adh_idh_uf.ano_censo)', 'start_year') + .field('MAX(adh_idh_uf.ano_censo)', 'end_year'); + req.old_result = req.result; + next(); +}, query, (req, res, next) => { + if (req.old_result[0].start_year < req.result[0].start_year) { + req.result[0].start_year = req.old_result[0].start_year; + } + if (req.old_result[0].end_year > req.result[0].end_year) { + req.result[0].end_year = req.old_result[0].old_result; + } + next(); +}, query, response('range')); + +idhmlApp.get('/years', (req, res, next) => { + req.sql.from('adh_idh') + .field('DISTINCT adh_idh.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + req.oldResult = req.result; + + req.sql = squel.select(); + + req.sql.from('adh_idh_uf') + .field('DISTINCT adh_idh_uf.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + let result = Object.assign(req.oldResult, req.result); + req.result = result; + next(); +}, response('years')); + +idhmlApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'adh_idh\''); + next(); +}, query, response('source')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'adh_idh' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'adh_idh' + } +}).addValue({ + name: 'min_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: '@' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: '@' + } +}); + +idhmlApp.get('/', rqf.parse(), (req, res, next) => { + + if (("city" in req.dims) || ("city" in req.filter)) { + req.sql.from('adh_idh') + .field('adh_idh.idhm_l', 'total') + .field('adh_idh.ano_censo', 'year') + .field('adh_idh.municipio_id', 'city_id') + .group('adh_idh.idhm_l') + .group('adh_idh.ano_censo') + .group('adh_idh.municipio_id'); + } else if (("state" in req.filter) || ("state" in req.dims)) { + req.sql.from('adh_idh_uf') + .field('adh_idh_uf.idhm_l', 'total') + .field('adh_idh_uf.ano_censo', 'year') + .field('adh_idh_uf.estado_id', 'state_id') + .group('adh_idh_uf.idhm_l') + .group('adh_idh_uf.ano_censo') + .group('adh_idh_uf.estado_id'); + } else { + res.status(400); + next({ + status: 400, + message: 'Wrong/No filter specified' + }); + } + next(); +}, rqf.build(), query, addMissing(rqf), id2str.transform(), response('idhme')); + +module.exports = idhmlApp; diff --git a/src/libs/routes_v2/idhmr.js b/src/libs/routes_v2/idhmr.js new file mode 100644 index 0000000000000000000000000000000000000000..a9117cb4180bf2b5ffc17084ddf65c7febcdbc47 --- /dev/null +++ b/src/libs/routes_v2/idhmr.js @@ -0,0 +1,188 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const idhmrApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +idhmrApp.use(cache('15 day')); + +idhmrApp.get('/year_range', (req, res, next) => { + req.sql.from('adh_idh') + .field('MIN(adh_idh.ano_censo)', 'start_year') + .field('MAX(adh_idh.ano_censo)', 'end_year'); + next(); +}, query, (req, res, next) => { + req.sql.from('adh_idh_uf') + .field('MIN(adh_idh_uf.ano_censo)', 'start_year') + .field('MAX(adh_idh_uf.ano_censo)', 'end_year'); + req.old_result = req.result; + next(); +}, query, (req, res, next) => { + if (req.old_result[0].start_year < req.result[0].start_year) { + req.result[0].start_year = req.old_result[0].start_year; + } + if (req.old_result[0].end_year > req.result[0].end_year) { + req.result[0].end_year = req.old_result[0].old_result; + } + next(); +}, query, response('range')); + +idhmrApp.get('/years', (req, res, next) => { + req.sql.from('adh_idh') + .field('DISTINCT adh_idh.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + req.oldResult = req.result; + + req.sql = squel.select(); + + req.sql.from('adh_idh_uf') + .field('DISTINCT adh_idh_uf.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + let result = Object.assign(req.oldResult, req.result); + req.result = result; + next(); +}, response('years')); + +idhmrApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'adh_idh\''); + next(); +}, query, response('source')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'adh_idh' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'adh_idh' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: '@' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: '@' + } +}).addValue({ + name: 'min_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}); + +idhmrApp.get('/', rqf.parse(), (req, res, next) => { + if (("city" in req.dims) || ("city" in req.filter)) { + req.sql.from('adh_idh') + .field('adh_idh.idhm_r', 'total') + .field('adh_idh.ano_censo', 'year') + .field('adh_idh.municipio_id', 'city_id') + .field('adh_idh.estado_id', 'state_id') + .group('adh_idh.idhm_r') + .group('adh_idh.ano_censo') + .group('adh_idh.municipio_id') + .group('adh_idh.estado_id') + } else if (("state" in req.filter) || ("state" in req.dims)) { + req.sql.from('adh_idh_uf') + .field('adh_idh_uf.idhm_r', 'total') + .field('adh_idh_uf.ano_censo', 'year') + .field('adh_idh_uf.estado_id', 'state_id') + .group('adh_idh_uf.idhm_r') + .group('adh_idh_uf.ano_censo') + .group('adh_idh_uf.estado_id') + } else { + res.status(400); + next({ + status: 400, + message: 'Wrong/No filter specified' + }); + } + next(); +}, rqf.build(), query, addMissing(rqf), id2str.transform(), response('idhmr')); + +module.exports = idhmrApp; diff --git a/src/libs/routes_v2/infrastructure.js b/src/libs/routes_v2/infrastructure.js new file mode 100644 index 0000000000000000000000000000000000000000..89d7e2787c53908876fd22822397ceb9c38694a1 --- /dev/null +++ b/src/libs/routes_v2/infrastructure.js @@ -0,0 +1,586 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const infrastructureApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const multiQuery = require(`${libs}/middlewares/multiQuery`); + +const response = require(`${libs}/middlewares/response`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +infrastructureApp.use(cache('15 day')); + +infrastructureApp.get('/year_range', (req, res, next) => { + req.sql.from('escola_agregada') + .field('MIN(escola_agregada.ano_censo)', 'start_year') + .field('MAX(escola_agregada.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +infrastructureApp.get('/years', (req, res, next) => { + req.sql.from('escola_agregada') + .field('DISTINCT escola_agregada.ano_censo', 'year'); + next(); +}, query, response('years')); + +infrastructureApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'escola_agregada\''); + next(); +}, query, response('source')); + +infrastructureApp.get('/location', (req, res, next) => { + req.result = [ + {id: 1, name: 'Urbana'}, + {id: 2, name: 'Rural'} + ]; + next(); +}, response('location')); + +infrastructureApp.get('/rural_location', (req, res, next) => { + req.result = [ + {id: 1, name: "Urbana"}, + {id: 2, name: "Rural"}, + {id: 3, name: "Rural - Área de assentamento"}, + {id: 4, name: "Rural - Terra indígena"}, + {id: 5, name: "Rural - Área remanescente de quilombos"}, + {id: 6, name: "Rural - Unidade de uso sustentável"} + ]; + next(); +}, response('rural_location')); + +infrastructureApp.get('/adm_dependency', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.admDependency(i) + }); + }; + next(); +}, response('adm_dependency')); + +infrastructureApp.get('/adm_dependency_detailed', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 6; ++i) { + req.result.push({ + id: i, + name: id2str.admDependencyPriv(i) + }); + }; + next(); +}, response('adm_dependency_detailed')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValueToField({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'escola_agregada' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'escola_agregada' + } +}, 'dims').addValueToField({ + name: 'city', + table: 'municipio', + tableField: 'id', + resultField: 'city_id', + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'escola_agregada' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'escola_agregada' + } +}, 'filter').addValueToField({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'escola_agregada' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'escola_agregada' + } +}, 'dims').addValueToField({ + name: 'state', + table: 'estado', + tableField: 'id', + resultField: 'state_id', + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'escola_agregada' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'escola_agregada' + } +}, 'filter').addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'escola_agregada' + } +}).addValue({ + name: 'location', + table: 'escola_agregada', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'rural_location', + table: 'escola_agregada', + tableField: 'localidade_area_rural', + resultField: 'rural_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localidade_area_rural' + } +}).addValue({ + name: 'adm_dependency', + table: 'escola_agregada', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}).addValue({ + name: 'adm_dependency_detailed', + table: 'escola_agregada', + tableField: 'dependencia_adm_priv', + resultField: 'adm_dependency_detailed_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_priv' + } +}).addValue({ + name: 'min_year', + table: 'escola_agregada', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'escola_agregada', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}); + +function matchQueries(queryTotal, queryPartial) { + let match = []; + queryTotal.forEach((result) => { + let newObj = {}; + let keys = Object.keys(result); + keys.forEach((key) => { + newObj[key] = result[key]; + }); + let index = keys.indexOf('total'); + if(index > -1) keys.splice(index, 1); + let objMatch = null; + + for(let i = 0; i < queryPartial.length; ++i) { + let partial = queryPartial[i]; + let foundMatch = true; + for(let j = 0; j < keys.length; ++j) { + let key = keys[j]; + if(partial[key] !== result[key]) { + foundMatch = false; + break; + } + } + if(foundMatch) { + objMatch = partial; + break; + } + } + + if(objMatch) { + newObj.percentage = (objMatch.total / result.total) * 100; + newObj.partial = objMatch.total; + newObj.total = result.total + match.push(newObj); + } + }); + + return match; +} + +infrastructureApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.querySet = []; + req.queryIndex = {}; + + // Local de funcionamento + let allSchools = req.sql.clone(); + allSchools.from('escola_agregada').field('COUNT(escola_agregada.id)', 'total') + .field("'Brasil'", 'name') + .field('escola_agregada.ano_censo', 'year') + .group('escola_agregada.ano_censo') + .where('escola_agregada.situacao_de_funcionamento = 1') + .order('escola_agregada.ano_censo'); + req.queryIndex.allSchools = req.querySet.push(allSchools) - 1; + + let schoolPlace = allSchools.clone(); + schoolPlace.where('escola_agregada.func_predio_escolar = 1 AND escola_agregada.func_salas_empresa = 0 AND escola_agregada.func_templo_igreja = 0 AND escola_agregada.func_casa_professor = 0 AND escola_agregada.func_galpao = 0 AND escola_agregada.biblioteca = 1'); + req.queryIndex.schoolPlace = req.querySet.push(schoolPlace) - 1; + + // Bibliotecas + let allLibraries = allSchools.clone(); + allLibraries.where('escola_agregada.func_predio_escolar = 1 AND escola_agregada.localizacao_id = 1'); + req.queryIndex.allLibraries = req.querySet.push(allLibraries) - 1; + + let haveLibraries = allLibraries.clone(); + haveLibraries.where('escola_agregada.biblioteca = 1'); + req.queryIndex.haveLibraries = req.querySet.push(haveLibraries) - 1; + + // Bibliotecas/Sala de leitura + let allLibrariesReadingRoom = allSchools.clone(); + allLibrariesReadingRoom.where('escola_agregada.func_predio_escolar = 1 AND escola_agregada.localizacao_id = 2'); + req.queryIndex.allLibrariesReadingRoom = req.querySet.push(allLibrariesReadingRoom) - 1; + + let haveLibrariesReadingRoom = allLibrariesReadingRoom.clone(); + haveLibrariesReadingRoom.where('escola_agregada.sala_leitura = 1'); + req.queryIndex.haveLibrariesReadingRoom = req.querySet.push(haveLibrariesReadingRoom) - 1; + + // Laboratório de informática + let allInfLab = allSchools.clone(); + allInfLab.where('escola_agregada.func_predio_escolar = 1') + .where('etapa_en_fundamental_anos_iniciais = 1 OR etapa_en_fundamental_anos_finais = 1 OR etapa_en_medio = 1'); + req.queryIndex.allInfLab = req.querySet.push(allInfLab) - 1; + + let haveInfLab = allInfLab.clone(); + haveInfLab.where('escola_agregada.lab_informatica = 1'); + req.queryIndex.haveInfLab = req.querySet.push(haveInfLab) - 1; + + // Laboratório de ciências + let allScienceLab = allInfLab.clone(); + req.queryIndex.allScienceLab = req.querySet.push(allScienceLab) - 1; + + let haveScienceLab = allScienceLab.clone(); + haveScienceLab.where('escola_agregada.lab_ciencias = 1 AND (etapa_en_fundamental_anos_finais = 1 OR etapa_en_medio = 1)'); + req.queryIndex.haveScienceLab = req.querySet.push(haveScienceLab) - 1; + + // Parque infantil + let allKidsPark = allSchools.clone(); + allKidsPark.where('escola_agregada.func_predio_escolar = 1') + .where('escola_agregada.etapa_ed_infantil_creche = 1 OR escola_agregada.etapa_en_fundamental_anos_iniciais = 1'); + req.queryIndex.allKidsPark = req.querySet.push(allKidsPark) - 1; + + let haveKidsPark = allKidsPark.clone(); + haveKidsPark.where('escola_agregada.parque_infantil = 1'); + req.queryIndex.haveKidsPark = req.querySet.push(haveKidsPark) - 1; + + // Berçário + let allCribs = allSchools.clone(); + allCribs.where('escola_agregada.func_predio_escolar = 1') + .where('escola_agregada.reg_infantil_creche = 1 OR escola_agregada.esp_infantil_creche = 1'); + req.queryIndex.allCribs = req.querySet.push(allCribs) - 1; + + let haveCribs = allCribs.clone(); + haveCribs.where('escola_agregada.bercario = 1'); + req.queryIndex.haveCribs = req.querySet.push(haveCribs) - 1; + + // Quadra + let allSportsCourt = allScienceLab.clone(); + allSportsCourt.where('escola_agregada.localizacao_id = 1 AND (etapa_en_fundamental_anos_iniciais = 1 OR etapa_en_fundamental_anos_finais = 1 OR etapa_en_medio = 1)'); + req.queryIndex.allSportsCourt = req.querySet.push(allSportsCourt) - 1; + + let haveSportsCourt = allSportsCourt.clone(); + haveSportsCourt.where('escola_agregada.quadra_esportes = 1 AND (etapa_en_fundamental_anos_iniciais = 1 OR etapa_en_fundamental_anos_finais = 1 OR etapa_en_medio = 1)'); + req.queryIndex.haveSportsCourt = req.querySet.push(haveSportsCourt) - 1; + + // Quadra coberta + req.queryIndex.allCoveredSportsCourt = req.queryIndex.allSportsCourt; + + let haveCoveredSportsCourt = allSportsCourt.clone(); + haveCoveredSportsCourt.where('escola_agregada.quadra_esportes_coberta = 1 AND (etapa_en_fundamental_anos_iniciais = 1 OR etapa_en_fundamental_anos_finais = 1 OR etapa_en_medio = 1)'); + req.queryIndex.haveCoveredSportsCourt = req.querySet.push(haveCoveredSportsCourt) - 1; + + // Quadra Descoberta + let allUncoveredSportsCourt = allSportsCourt.clone(); + allUncoveredSportsCourt.where('escola_agregada.quadra_esportes_coberta = 0 AND (etapa_en_fundamental_anos_iniciais = 1 OR etapa_en_fundamental_anos_finais = 1 OR etapa_en_medio = 1)'); + req.queryIndex.allUncoveredSportsCourt = req.querySet.push(allUncoveredSportsCourt) - 1; + + let haveUncoveredSportsCourt = allUncoveredSportsCourt.clone(); + haveUncoveredSportsCourt.where('escola_agregada.quadra_esportes_descoberta = 1 AND (etapa_en_fundamental_anos_iniciais = 1 OR etapa_en_fundamental_anos_finais = 1 OR etapa_en_medio = 1)'); + req.queryIndex.haveUncoveredSportsCourt = req.querySet.push(haveUncoveredSportsCourt) - 1; + + // Sala de direção + let allDirectorRoom = allSchools.clone(); + allDirectorRoom.where('escola_agregada.func_predio_escolar = 1 AND escola_agregada.localizacao_id = 1'); + req.queryIndex.allDirectorRoom = req.querySet.push(allDirectorRoom) - 1; + + let haveDirectorRoom = allDirectorRoom.clone(); + haveDirectorRoom.where('escola_agregada.sala_diretoria = 1'); + req.queryIndex.haveDirectorRoom = req.querySet.push(haveDirectorRoom) - 1; + + // Secretaria + let allSecretary = allSchools.clone(); + allSecretary.where('escola_agregada.func_predio_escolar = 1'); + req.queryIndex.allSecretary = req.querySet.push(allSecretary) - 1; + + let haveSecretary = allSecretary.clone(); + haveSecretary.where('escola_agregada.secretaria = 1'); + req.queryIndex.haveSecretary = req.querySet.push(haveSecretary) - 1; + + // Sala de professores + req.queryIndex.allTeacherRoom = req.queryIndex.allSecretary; + + let haveTeacherRoom = allSecretary.clone(); + haveTeacherRoom.where('escola_agregada.sala_professor = 1'); + req.queryIndex.haveTeacherRoom = req.querySet.push(haveTeacherRoom) - 1; + + // Cozinha + req.queryIndex.allKitchen = req.queryIndex.allSecretary; + + let haveKitchen = allSecretary.clone(); + haveKitchen.where('escola_agregada.cozinha = 1'); + req.queryIndex.haveKitchen = req.querySet.push(haveKitchen) - 1; + + // Despensa + req.queryIndex.allStoreroom = req.queryIndex.allSecretary; + + let haveStoreroom = allSecretary.clone(); + haveStoreroom.where('escola_agregada.despensa = 1'); + req.queryIndex.haveStoreroom = req.querySet.push(haveStoreroom) - 1; + + // Almoxarifado + req.queryIndex.allWarehouse = req.queryIndex.allSecretary; + + let haveWarehouse = allSecretary.clone(); + haveWarehouse.where('escola_agregada.almoxarifado = 1'); + req.queryIndex.haveWarehouse = req.querySet.push(haveWarehouse) - 1; + + // Internet + req.queryIndex.allInternet = req.queryIndex.allLibrariesReadingRoom; + + let haveInternet = allLibrariesReadingRoom.clone(); + haveInternet.where('escola_agregada.internet = 1 AND localizacao_id = 2'); + req.queryIndex.haveInternet = req.querySet.push(haveInternet) - 1; + + // Internet banda larga + req.queryIndex.allBroadbandInternet = req.queryIndex.allLibraries; + + let haveBroadbandInternet = allLibraries.clone(); + haveBroadbandInternet.where('escola_agregada.internet_banda_larga = 1 AND localizacao_id = 1'); + req.queryIndex.haveBroadbandInternet = req.querySet.push(haveBroadbandInternet) - 1; + + // Banheiro dentro do prédio + req.queryIndex.allInsideBathroom = req.queryIndex.allSecretary; + + let haveInsideBathroom = allSecretary.clone(); + haveInsideBathroom.where('escola_agregada.sanitario_dentro_predio = 1'); + req.queryIndex.haveInsideBathroom = req.querySet.push(haveInsideBathroom) - 1; + + // Banheiro adequado para educação infantil dentro do prédio + req.queryIndex.allInsideKidsBathroom = req.queryIndex.allKidsPark; + + let haveInsideKidsBathroom = allKidsPark.clone(); + haveInsideKidsBathroom.where('escola_agregada.sanitario_ei = 1 AND (escola_agregada.etapa_ed_infantil_creche = 1 OR escola_agregada.etapa_en_fundamental_anos_iniciais = 1) AND localizacao_id IN (1, 2)'); + req.queryIndex.haveInsideKidsBathroom = req.querySet.push(haveInsideKidsBathroom) - 1; + + // Fornecimento de energia + req.queryIndex.allEletricEnergy = req.queryIndex.allSecretary; + + let haveEletricEnergy = allSecretary.clone(); + haveEletricEnergy.where('escola_agregada.fornecimento_energia = 1'); + req.queryIndex.haveEletricEnergy = req.querySet.push(haveEletricEnergy) - 1; + + // Abastecimento de água + req.queryIndex.allWaterSupply = req.queryIndex.allSecretary; + + let haveWaterSupply = allSecretary.clone(); + haveWaterSupply.where('escola_agregada.fornecimento_agua = 1'); + req.queryIndex.haveWaterSupply = req.querySet.push(haveWaterSupply) - 1; + + // Água filtrada + req.queryIndex.allFilteredWater = req.queryIndex.allSecretary; + + let haveFilteredWater = allSecretary.clone(); + haveFilteredWater.where('escola_agregada.agua_filtrada = 1'); + req.queryIndex.haveFilteredWater = req.querySet.push(haveFilteredWater) - 1; + + // Coleta de esgoto + req.queryIndex.allSewage = req.queryIndex.allSecretary; + + let haveSewage = allSecretary.clone(); + haveSewage.where('escola_agregada.esgoto_sanitario = 1'); + req.queryIndex.haveSewage = req.querySet.push(haveSewage) - 1; + + // Sala de recursos multifuncionais para Atendimento Educacional Especializado + req.queryIndex.allMultifunctionRoom = req.queryIndex.allSecretary; + + let haveMultifunctionRoom = allSecretary.clone(); + haveMultifunctionRoom.where('escola_agregada.sala_atendimento_especial = 1'); + req.queryIndex.haveMultifunctionRoom = req.querySet.push(haveMultifunctionRoom) - 1; + + // Banheiros adaptados para pessoas com deficiências + req.queryIndex.allSpecialBathroom = req.queryIndex.allSecretary; + + let haveSpecialBathroom = allSecretary.clone(); + haveSpecialBathroom.where('escola_agregada.sanitario_pne = 1'); + req.queryIndex.haveSpecialBathroom = req.querySet.push(haveSpecialBathroom) - 1; + + // Dependências adaptada para pessoas com deficiências + req.queryIndex.allAdaptedBuilding = req.queryIndex.allSecretary; + + let haveAdaptedBuilding = allSecretary.clone(); + haveAdaptedBuilding.where('escola_agregada.dependencias_pne = 1'); + req.queryIndex.haveAdaptedBuilding = req.querySet.push(haveAdaptedBuilding) - 1; + + + next(); +}, multiQuery, (req, res, next) => { + // Faz o matching entre os resultados + let school_place = matchQueries(req.result[req.queryIndex.allSchools], req.result[req.queryIndex.schoolPlace]); + let libraries = matchQueries(req.result[req.queryIndex.allLibraries], req.result[req.queryIndex.haveLibraries]); + let libraries_reading_room = matchQueries(req.result[req.queryIndex.allLibrariesReadingRoom], req.result[req.queryIndex.haveLibrariesReadingRoom]); + let computer_lab = matchQueries(req.result[req.queryIndex.allInfLab], req.result[req.queryIndex.haveInfLab]); + let science_lab = matchQueries(req.result[req.queryIndex.allScienceLab], req.result[req.queryIndex.haveScienceLab]); + let kids_park = matchQueries(req.result[req.queryIndex.allKidsPark], req.result[req.queryIndex.haveKidsPark]); + let nursery = matchQueries(req.result[req.queryIndex.allCribs], req.result[req.queryIndex.haveCribs]); + let sports_court = matchQueries(req.result[req.queryIndex.allSportsCourt], req.result[req.queryIndex.haveSportsCourt]); + let covered_sports_court = matchQueries(req.result[req.queryIndex.allCoveredSportsCourt], req.result[req.queryIndex.haveCoveredSportsCourt]); + let uncovered_sports_court = matchQueries(req.result[req.queryIndex.allUncoveredSportsCourt], req.result[req.queryIndex.haveUncoveredSportsCourt]); + let director_room = matchQueries(req.result[req.queryIndex.allDirectorRoom], req.result[req.queryIndex.haveDirectorRoom]); + let secretary = matchQueries(req.result[req.queryIndex.allSecretary], req.result[req.queryIndex.haveSecretary]); + let teacher_room = matchQueries(req.result[req.queryIndex.allTeacherRoom], req.result[req.queryIndex.haveTeacherRoom]); + let kitchen = matchQueries(req.result[req.queryIndex.allKitchen], req.result[req.queryIndex.haveKitchen]); + let storeroom = matchQueries(req.result[req.queryIndex.allStoreroom], req.result[req.queryIndex.haveStoreroom]); + let warehouse = matchQueries(req.result[req.queryIndex.allWarehouse], req.result[req.queryIndex.haveWarehouse]); + let internet = matchQueries(req.result[req.queryIndex.allInternet], req.result[req.queryIndex.haveInternet]); + let broadband_internet = matchQueries(req.result[req.queryIndex.allBroadbandInternet], req.result[req.queryIndex.haveBroadbandInternet]); + let inside_bathroom = matchQueries(req.result[req.queryIndex.allInsideBathroom], req.result[req.queryIndex.haveInsideBathroom]); + let inside_kids_bathroom = matchQueries(req.result[req.queryIndex.allInsideKidsBathroom], req.result[req.queryIndex.haveInsideKidsBathroom]); + let eletric_energy = matchQueries(req.result[req.queryIndex.allEletricEnergy], req.result[req.queryIndex.haveEletricEnergy]); + let water_supply = matchQueries(req.result[req.queryIndex.allWaterSupply], req.result[req.queryIndex.haveWaterSupply]); + let filtered_water = matchQueries(req.result[req.queryIndex.allFilteredWater], req.result[req.queryIndex.haveFilteredWater]); + let sewage_treatment = matchQueries(req.result[req.queryIndex.allSewage], req.result[req.queryIndex.haveSewage]); + let special_multifunction_room = matchQueries(req.result[req.queryIndex.allMultifunctionRoom], req.result[req.queryIndex.haveMultifunctionRoom]); + let special_bathroom = matchQueries(req.result[req.queryIndex.allSpecialBathroom], req.result[req.queryIndex.haveSpecialBathroom]); + let adapted_building = matchQueries(req.result[req.queryIndex.allAdaptedBuilding], req.result[req.queryIndex.haveAdaptedBuilding]); + + req.result = [{ + school_place, + libraries, + libraries_reading_room, + computer_lab, + science_lab, + kids_park, + nursery, + sports_court, + covered_sports_court, + uncovered_sports_court, + director_room, + secretary, + teacher_room, + kitchen, + storeroom, + warehouse, + internet, + broadband_internet, + inside_bathroom, + inside_kids_bathroom, + eletric_energy, + water_supply, + filtered_water, + sewage_treatment, + special_multifunction_room, + special_bathroom, + adapted_building + }]; + + next(); +}, id2str.multitransform(false), response('infrastructure')); + +module.exports = infrastructureApp; diff --git a/src/libs/routes_v2/liquidEnrollmentRatio.js b/src/libs/routes_v2/liquidEnrollmentRatio.js new file mode 100644 index 0000000000000000000000000000000000000000..63bd91685a8df488731a267d268a929a6252a8df --- /dev/null +++ b/src/libs/routes_v2/liquidEnrollmentRatio.js @@ -0,0 +1,434 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const liquidEnrollmentRatioApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const multiQuery = require(`${libs}/middlewares/multiQuery`); + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +liquidEnrollmentRatioApp.use(cache('15 day')); + +// Complete range of the enrollments dataset. +// Returns a tuple of start and ending years of the complete enrollments dataset. +liquidEnrollmentRatioApp.get('/year_range', (req, res, next) => { + req.sql.from('pnad') + .field('DISTINCT pnad.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + req.oldResult = req.result; + + req.sql = squel.select(); + + req.sql.from('matricula') + .field('DISTINCT matricula.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + let distinct_years = []; + let new_result = []; + for (let i = 0; i < req.oldResult.length; i++) { + for (let j = 0; j < req.result.length; j++) { + if(req.oldResult[i].year == req.result[j].year) { + distinct_years.push(req.oldResult[i]); + } + } + } + new_result.push({start_year: distinct_years[distinct_years.length -1].year, end_year: distinct_years[0].year}); + req.result = new_result; + next(); +}, response('range')); + +liquidEnrollmentRatioApp.get('/years', (req, res, next) => { + req.sql.from('pnad') + .field('DISTINCT pnad.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + req.oldResult = req.result; + + req.sql = squel.select(); + + req.sql.from('matricula') + .field('DISTINCT matricula.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + let new_result = [] + for (let i = 0; i < req.oldResult.length; i++) { + for (let j = 0; j < req.result.length; j++) { + if(req.oldResult[i].year == req.result[j].year) { + new_result.push(req.oldResult[i]); + } + } + } + req.result = new_result; + next(); +}, response('years')); + +liquidEnrollmentRatioApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'pnad\''); + next(); +}, query, response('source')); + +liquidEnrollmentRatioApp.get('/education_level_short', (req, res, next) => { + req.result = [ + {id: null, name: 'Não classificada'}, + {id: 1, name: 'Creche'}, + {id: 2, name: 'Pré-Escola'}, + {id: 3, name: 'Ensino Fundamental - anos iniciais'}, + {id: 4, name: 'Ensino Fundamental - anos finais'}, + {id: 5, name: 'Ensino Médio'} + ]; + next(); +}, response('education_level_short')); + +liquidEnrollmentRatioApp.get('/gender', (req, res, next) => { + req.result = [ + {id: 1, name: 'Masculino'}, + {id: 2, name: 'Feminino'} + ]; + next(); +}, response('gender')); + +liquidEnrollmentRatioApp.get('/ethnic_group', (req, res, next) => { + req.result = [ + {id: 0, name: 'Sem declaração'}, + {id: 1, name: 'Branca'}, + {id: 2, name: 'Preta'}, + {id: 3, name: 'Parda'}, + {id: 4, name: 'Amarela'}, + {id: 5, name: 'Indígena'} + ]; + next(); +}, response('ethnic_group')); + +liquidEnrollmentRatioApp.get('/location', (req, res, next) => { + req.result = [ + {id: 1, name: 'Urbana'}, + {id: 2, name: 'Rural'} + ]; + next(); +}, response('location')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: '@' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: '@' + } +}).addValue({ + name: 'ethnic_group', + table: '@', + tableField: 'cor_raca_id', + resultField: 'ethnic_group_id', + where: { + relation: '=', + type: 'integer', + field: 'cor_raca_id' + } +}).addValue({ + name: 'min_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'gender', + table: '@', + tableField: 'sexo', + resultField: 'gender_id', + where: { + relation: '=', + type: 'integer', + field: 'sexo' + } +}).addValue({ + name: 'location', + table: '@', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'education_level_short', + table: 'matricula', + tableField: 'etapa_resumida', + resultField: 'education_level_short_id', + where: { + relation: '=', + type: 'integer', + field: 'etapa_resumida' + } +}); + +function matchQueries(queryTotal, queryPartial) { + let match = []; + queryPartial.forEach((result) => { + let newObj = {}; + let keys = Object.keys(result); + keys.forEach((key) => { + newObj[key] = result[key]; + }); + // console.log('NEW OBJ'); + // console.log(newObj); + // remove total + let index = keys.indexOf('total'); + if(index > -1) keys.splice(index, 1); + // remove education_level_short_id + index = keys.indexOf('education_level_short_id'); + if(index > -1) keys.splice(index, 1); + // remove education_level_short_name + index = keys.indexOf('education_level_short_name'); + if(index > -1) keys.splice(index, 1); + let objMatch = null; + + for(let i = 0; i < queryTotal.length; ++i) { + let total = queryTotal[i]; + let foundMatch = true; + for(let j = 0; j < keys.length; ++j) { + let key = keys[j]; + if(total[key] !== result[key]) { + foundMatch = false; + break; + } + } + if(foundMatch) { + objMatch = total; + break; + } + } + + if(objMatch) { + // console.log('MATCH!!!!'); + // console.log(objMatch); + newObj.total = (result.total / objMatch.total) * 100; + newObj.partial = result.total; + newObj.denominator = objMatch.total + match.push(newObj); + } + }); + // console.log('TAMANHOS'); + // console.log(queryTotal.length); + // console.log(queryPartial.length); + // console.log(match.length); + return match; +} + +function ConvertEnrollment(result) { + if (result == 1) { + return '(matricula.faixa_etaria_31_03 = 1 AND matricula.etapa_resumida = 1)' + } else if (result == 2) { + return '(matricula.faixa_etaria_31_03 = 2 AND matricula.etapa_resumida = 2)' + } else if (result == 4) { + return '(matricula.faixa_etaria_31_03 = 3 AND matricula.etapa_resumida = 3)' + } else if (result == 5) { + return '(matricula.faixa_etaria_31_03 = 4 AND matricula.etapa_resumida = 4)' + } else if (result == 6) { + return '(matricula.faixa_etaria_31_03 = 5 AND matricula.etapa_resumida = 5)' + } +} + + +function convertPnad(result) { + if (result == 1) { + return 'pnad.faixa_etaria_31_03 = 1' + } else if (result == 2) { + return 'pnad.faixa_etaria_31_03 = 2' + } else if (result == 4) { + return 'pnad.faixa_etaria_31_03 = 3' + } else if (result == 5) { + return 'pnad.faixa_etaria_31_03 = 4' + } else if (result == 6) { + return 'pnad.faixa_etaria_31_03 = 5' + } +} + +liquidEnrollmentRatioApp.get('/', rqf.parse(),(req, res, next) => { + req.numerator = {}; + req.denominator = {}; + let liquidEnrollmentRatioApp = {}; + + req.sql.from('matricula') + .field('count(*)', 'total') + .field('matricula.ano_censo', 'year') + .group('matricula.ano_censo') + .order('matricula.ano_censo') + .where('matricula.tipo <= 3') + + if ("education_level_short" in req.filter) { + + if (Array.isArray(req.filter.education_level_short)) { + var stringQuery = ''; + for(let i = 0; i < req.filter.education_level_short.length - 1; i++) { + stringQuery = stringQuery + ConvertEnrollment(req.filter.education_level_short[i]) + ' OR '; + } + + stringQuery = stringQuery + ConvertEnrollment(req.filter.education_level_short[req.filter.education_level_short.length - 1]); + delete req.filter.education_level_short; + req.sql.where(stringQuery); + req.sql.field('matricula.faixa_etaria_31_03', 'age_range') + req.sql.group('matricula.faixa_etaria_31_03', 'age_range'); + } + + } else if ( "education_level_short" in req.dims ) { + + req.sql.field('matricula.faixa_etaria_31_03', 'age_range') + req.sql.where('(matricula.etapa_resumida = 1 AND matricula.faixa_etaria_31_03 = 1) OR (matricula.etapa_resumida = 2 AND matricula.faixa_etaria_31_03 = 2) OR (matricula.etapa_resumida = 3 AND matricula.faixa_etaria_31_03 = 3) OR (matricula.etapa_resumida = 4 AND matricula.faixa_etaria_31_03 = 4) OR (matricula.etapa_resumida = 5 AND matricula.faixa_etaria_31_03 = 5)'); + req.sql.group('matricula.faixa_etaria_31_03', 'age_range'); + + } else { + res.status(400); + next({ + status: 400, + message: 'Wrong/No filter specified' + }); + } + + next(); +}, rqf.build(), query, id2str.transform(), (req, res, next) => { + req.numerator = req.result; + req.resetSql(); + req.sql.field('sum(peso)', 'total') + .field('pnad.ano_censo','year') + .from('pnad') + .group('pnad.ano_censo') + .order('pnad.ano_censo') + + //remove education_level_short how filter and add faixa_etaria_31_03 in filter + + if ("education_level_short" in req.filter) { + + if (Array.isArray(req.filter.education_level_short)) { + var stringQuery = ''; + for(let i = 0; i < req.filter.education_level_short.length - 1; i++) { + stringQuery = stringQuery + convertPnad(req.filter.education_level_short[i]) + ' OR '; + } + stringQuery = stringQuery + convertPnad(req.filter.education_level_short[req.filter.education_level_short.length - 1]); + req.sql.where(stringQuery); + } + req.sql.field('pnad.faixa_etaria_31_03', 'age_range') + req.sql.group('pnad.faixa_etaria_31_03', 'age_range'); + + } else if ( "education_level_short" in req.dims ) { + + req.sql.field('pnad.faixa_etaria_31_03','age_range') + req.sql.where('pnad.faixa_etaria_31_03 = 1 OR pnad.faixa_etaria_31_03 = 2 OR pnad.faixa_etaria_31_03 = 3 OR pnad.faixa_etaria_31_03 = 4 OR pnad.faixa_etaria_31_03 = 5') + req.sql.group('pnad.faixa_etaria_31_03', 'age_range'); + } else { + res.status(400); + next({ + status: 400, + message: 'Wrong/No filter specified' + }); + } + + next(); +}, rqf.parse(), (req, res, next) => { + if ("education_level_short" in req.filter) { + delete req.filter.education_level_short; + } + if ("education_level_short" in req.dims) { + delete req.dims.education_level_short; + } + next(); +}, rqf.build(), query, id2str.transform(), (req, res, next) => { + req.denominator = req.result; + + //division to generate req.result final + req.result = [] + let liquidEnrollment = matchQueries(req.denominator, req.numerator); + req.result = liquidEnrollment; + next(); +}, response('liquidEnrollmentRatio')); + +module.exports = liquidEnrollmentRatioApp; diff --git a/src/libs/routes_v2/location.js b/src/libs/routes_v2/location.js new file mode 100644 index 0000000000000000000000000000000000000000..d493c452f8dfa1c16a5731d5088fbdf700ff5b08 --- /dev/null +++ b/src/libs/routes_v2/location.js @@ -0,0 +1,135 @@ +const express = require('express'); + +const locationApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const request = require(`request`); + +const config = require(`${libs}/config`); + +const passport = require('passport'); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +locationApp.use(cache('15 day')) + +let rqf = new ReqQueryFields(); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'id', + table: 'localizacao_escolas', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id' + } +}).addValue({ + name: 'mesoregion', + table: 'municipio', + tableField: ['nome_mesorregiao', 'mesorregiao_id'], + resultField: ['mesoregion_name', 'mesoregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'mesorregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: '@' + } +}).addValue({ + name: 'microregion', + table: 'municipio', + tableField: ['nome_microrregiao', 'microrregiao_id'], + resultField: ['microregion_name', 'microregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'microrregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: '@' + } +}).addValueToField({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: '@' + } +}, 'dims'); + +locationApp.get('/school', rqf.parse(), (req, res, next) => { + req.dims.city=true; + req.dims.mesoregion=true; + req.dims.microregion=true; + + req.sql.from('localizacao_escolas') + .field('localizacao_escolas.nome', 'name') + .field('localizacao_escolas.id', 'id') + .field('localizacao_escolas.latitude', 'latitude') + .field('localizacao_escolas.longitude', 'longitude') + .group('localizacao_escolas.nome') + .group('localizacao_escolas.id') + .group('localizacao_escolas.latitude') + .group('localizacao_escolas.longitude'); + next(); +}, rqf.build(), query, id2str.transform(), response('location')); + +locationApp.get('/campi', rqf.parse(), (req, res, next) => { + req.dims.city=true; + req.dims.mesoregion=true; + req.dims.microregion=true; + + req.sql.from('localizacao_campi') + .field('localizacao_campi.nome', 'name') + .field('localizacao_campi.id', 'id') + .field('localizacao_campi.ies_id', 'ies_id') + .field('localizacao_campi.latitude', 'latitude') + .field('localizacao_campi.longitude', 'longitude') + .group('localizacao_campi.nome') + .group('localizacao_campi.id') + .group('localizacao_campi.ies_id') + .group('localizacao_campi.latitude') + .group('localizacao_campi.longitude'); + next(); +}, rqf.build(), query, id2str.transform(), response('location')); + +module.exports = locationApp; \ No newline at end of file diff --git a/src/libs/routes_v2/mesoregion.js b/src/libs/routes_v2/mesoregion.js new file mode 100644 index 0000000000000000000000000000000000000000..001976f2f053e9226249fc1bfdda4d68f36916da --- /dev/null +++ b/src/libs/routes_v2/mesoregion.js @@ -0,0 +1,86 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const mesoregionApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +mesoregionApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'municipio' + } +}).addValue({ + name: 'mesoregion', + table: 'municipio', + tableField: 'mesorregiao_id', + where: { + relation: '=', + type: 'integer', + field: 'mesorregiao_id' + } +}); + +mesoregionApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('municipio') + .field('municipio.nome_mesorregiao', 'name') + .field('municipio.mesorregiao_id', 'id') + .field('municipio.estado_id', 'state_id') + .group('municipio.nome_mesorregiao') + .group('municipio.mesorregiao_id') + .group('municipio.estado_id') + .order('municipio.mesorregiao_id'); + next(); +}, query, response('mesoregion')); + +module.exports = mesoregionApp; diff --git a/src/libs/routes_v2/message.js b/src/libs/routes_v2/message.js new file mode 100644 index 0000000000000000000000000000000000000000..f9e0e330a9aba1c098308ca4b4aaf67153c69aac --- /dev/null +++ b/src/libs/routes_v2/message.js @@ -0,0 +1,55 @@ +/* +Copyright (C) 2021 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const messageApp = express.Router(); + +const email = require(`../middlewares/email`); + +const log = require(`../log`)(module); + +messageApp.post('/', (req, res, next) => { + var reqName = req.body.name + var reqEmail = req.body.email + var reqContents = req.body.contents + var reqOrigin = req.body.origin ? req.body.origin : ""; + + var sub = "Contato " + reqOrigin + let mailOptions = { + to: ["dadoseducacionais@ufpr.br", reqEmail], + from: `\"${reqName}\" <dadoseducacionais@ufpr.br>`, + text: reqContents, + subject: sub + } + + email(mailOptions, (err, info) => { + if(err) { + log.error(err); + console.log(err); + res.status(500).json({msg: 'Undelivered Contact Mail'}); + } else { + log.info(`Message ${info.messageId} sent: ${info.response}`); + res.json({msg: 'Contact Mail Successfully Delivered'}); + } + }); +}) + +module.exports = messageApp; \ No newline at end of file diff --git a/src/libs/routes_v2/microregion.js b/src/libs/routes_v2/microregion.js new file mode 100644 index 0000000000000000000000000000000000000000..c4aba0fea760cbadeba7264e1f081436bc850634 --- /dev/null +++ b/src/libs/routes_v2/microregion.js @@ -0,0 +1,99 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const microregionApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +microregionApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'municipio' + } +}).addValue({ + name: 'mesoregion', + table: 'municipio', + tableField: 'mesorregiao_id', + where: { + relation: '=', + type: 'integer', + field: 'mesorregiao_id' + } +}).addValue({ + name: 'microregion', + table: 'municipio', + tableField: 'microrregiao_id', + where: { + relation: '=', + type: 'integer', + field: 'microrregiao_id' + } +}); + +microregionApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('municipio') + .field('municipio.nome_microrregiao', 'name') + .field('municipio.microrregiao_id', 'id') + .field('municipio.nome_mesorregiao', 'mesoregion_name') + .field('municipio.mesorregiao_id', 'mesoregion_id') + .field('municipio.estado_id', 'state_id') + .group('municipio.nome_microrregiao') + .group('municipio.microrregiao_id') + .group('municipio.nome_mesorregiao') + .group('municipio.mesorregiao_id') + .group('municipio.estado_id') + .order('municipio.microrregiao_id'); + next(); +}, query, response('microregion')); + +module.exports = microregionApp; diff --git a/src/libs/routes_v2/outOfSchool.js b/src/libs/routes_v2/outOfSchool.js new file mode 100644 index 0000000000000000000000000000000000000000..fcd57867675e0556f57c46fccc71af4cfacb787e --- /dev/null +++ b/src/libs/routes_v2/outOfSchool.js @@ -0,0 +1,377 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const outOfSchoolApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +outOfSchoolApp.use(cache('15 day')); + +outOfSchoolApp.get('/year_range', (req, res, next) => { + req.sql.from('pnad') + .field('MIN(pnad.ano_censo)', 'start_year') + .field('MAX(pnad.ano_censo)', 'end_year') + .where('pnad.ano_censo >= 2007 AND pnad.ano_censo <= 2015'); + next(); +}, query, response('range')); + +outOfSchoolApp.get('/years', (req, res, next) => { + req.sql.from('pnad'). + field('DISTINCT pnad.ano_censo', 'year') + .where('pnad.ano_censo >= 2007 AND pnad.ano_censo <= 2015'); + next(); +}, query, response('years')); + +outOfSchoolApp.get('/full_age_range', (req, res, next) => { + req.result = [ + {id: 1, name: '0 a 3 anos'}, + {id: 2, name: '4 a 5 anos'}, + {id: 3, name: '6 a 10 anos'}, + {id: 4, name: '11 a 14 anos'}, + {id: 5, name: '15 a 17 anos'}, + {id: 6, name: '18 a 24 anos'}, + {id: 7, name: '25 a 29 anos'}, + {id: 8, name: '30 a 40 anos'}, + {id: 9, name: '41 a 50 anos'}, + {id: 10, name: '51 a 64 anos'}, + {id: 11, name: 'Mais de 64 anos'} + ]; + next(); +}, response('full_age_range')); + +outOfSchoolApp.get('/ethnic_group', (req, res, next) => { + req.result = [ + {id: 0, name: 'Sem declaração'}, + {id: 1, name: 'Branca'}, + {id: 2, name: 'Preta'}, + {id: 3, name: 'Parda'}, + {id: 4, name: 'Amarela'}, + {id: 5, name: 'Indígena'} + ]; + next(); +}, response('ethnic_group')); + +outOfSchoolApp.get('/location', (req, res, next) => { + req.result = [ + {id: 1, name: 'Urbana'}, + {id: 2, name: 'Rural'} + ]; + next(); +}, response('location')); + +outOfSchoolApp.get('/gender', (req, res, next) => { + req.result = [ + {id: 1, name: 'Masculino'}, + {id: 2, name: 'Feminino'} + ]; + next(); +}, response('gender')); + +outOfSchoolApp.get('/fifth_household_income', (req, res, next) => { + req.result = [ + {id: 1, name: '20% menores'}, + {id: 2, name: '2o quinto'}, + {id: 3, name: '3o quinto'}, + {id: 4, name: '4o quinto'}, + {id: 5, name: '20% maiores'}, + {id: -1, name: 'Sem declaração'} + ]; + next(); +},response('fifth_household_income')); + +outOfSchoolApp.get('/extremes_household_income', (req, res, next) => { + req.result = [ + {id: 1, name: '10% menores'}, + {id: 2, name: '10% maiores'}, + {id: -1, name: 'Sem declaração'} + ]; + next(); +}, response('extremes_household_income')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'pnad' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'pnad' + } +}).addValue({ + name: 'ethnic_group', + table: 'pnad', + tableField: 'cor_raca_id', + resultField: 'ethnic_group_id', + where: { + relation: '=', + type: 'integer', + field: 'cor_raca_id' + } +}).addValue({ + name: 'min_year', + table: 'pnad', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: 'pnad', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'pnad', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: 'pnad', + field: 'ano_censo' + } +}).addValue({ + name: 'full_age_range', + table: 'pnad', + tableField: 'faixa_etaria_31_03', + resultField: 'full_age_range_id', + where: { + relation: '=', + type: 'integer', + field: 'faixa_etaria_31_03' + } +}).addValue({ + name: 'gender', + table: 'pnad', + tableField: 'sexo', + resultField: 'gender_id', + where: { + relation: '=', + type: 'integer', + field: 'sexo' + } +}).addValue({ + name: 'location', + table: 'pnad', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'extremes_household_income', + table: 'pnad', + tableField: 'extremos_nivel_rendimento', + resultField: 'extremes_household_income_id', + where: { + relation: '=', + type: 'integer', + field: 'extremos_nivel_rendimento' + } +}).addValue({ + name: 'fifth_household_income', + table: 'pnad', + tableField: 'quintil_nivel_rendimento', + resultField: 'fifth_household_income_id', + where: { + relation: '=', + type: 'integer', + field: 'quintil_nivel_rendimento' + } +}); + +outOfSchoolApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('pnad') + .field('SUM(pnad.peso)', 'total') + .field('pnad.ano_censo', 'year') + .where('pnad.escolaridade_familiar >= 1 AND pnad.escolaridade_familiar <= 4 AND pnad.frequenta_escola_creche = 4') + .group('pnad.ano_censo') + .order('pnad.ano_censo'); + + next(); +}, query, addMissing(rqf), id2str.transform(), response('out_of_school')); + +// Versão para o SimCAQ +let simcaqRqf = new ReqQueryFields(); + +simcaqRqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'brazil_total', + table: 'populacao_fora_da_escola', + tableField: 'brasil', + resultField: 'brazil_total_id', + where: { + relation: '=', + type: 'boolean', + field: 'brasil' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: 'nome', + resultField: 'state_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'populacao_fora_da_escola' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: 'nome', + resultField: 'city_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'populacao_fora_da_escola' + } +}).addValue({ + name: 'pfe', + table: 'populacao_fora_da_escola', + tableField: 'codigo_pfe', + resultField: 'pfe_id', + where: { + relation: '=', + type: 'integer', + field: 'codigo_pfe' + } +}).addValue({ + name: 'min_year', + table: 'populacao_fora_da_escola', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: 'populacao_fora_da_escola', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'populacao_fora_da_escola', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: 'populacao_fora_da_escola', + field: 'ano_censo' + } +}); + +outOfSchoolApp.get('/simcaq', simcaqRqf.parse(), (req, res, next) => { + if ('state' in req.filter || 'city' in req.filter || 'state' in req.dims || 'city' in req.dims) { // Query in state/city level + + if ('city' in req.filter && 'state' in req.filter) delete req.filter.state // use only the city filter because of the table particularities + + req.sql.from('populacao_fora_da_escola') + .field('SUM(populacao_fora_da_escola.pop_fora_escola)', 'total') + .field("'Brasil'", 'name') + .field('populacao_fora_da_escola.ano_censo') + .group('populacao_fora_da_escola.ano_censo') + .order('populacao_fora_da_escola.ano_censo'); + } else { // Query in 'Brasil' level + req.sql.from('populacao_fora_da_escola') + .field('SUM(populacao_fora_da_escola.pop_fora_escola)', 'total') + .field("'Brasil'", 'name') + .field('populacao_fora_da_escola.ano_censo') + .where('populacao_fora_da_escola.brasil = 1') + .group('populacao_fora_da_escola.ano_censo') + .order('populacao_fora_da_escola.ano_censo'); + } + + next(); +}, simcaqRqf.build(), query, (req, res, next) => { + req.result.forEach((i) => { + i.total = parseInt(i.total); + }); + next(); +}, addMissing(simcaqRqf), id2str.transform(), response('out_of_school')); + +module.exports = outOfSchoolApp; diff --git a/src/libs/routes_v2/pibpercapita.js b/src/libs/routes_v2/pibpercapita.js new file mode 100644 index 0000000000000000000000000000000000000000..c5c77a924ecaa848ab8f6cfb38e25d4bf8455121 --- /dev/null +++ b/src/libs/routes_v2/pibpercapita.js @@ -0,0 +1,250 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const pibpercapitaApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +pibpercapitaApp.use(cache('15 day')); + +pibpercapitaApp.get('/year_range', (req, res, next) => { + req.sql.from('ibge_pib') + .field('MIN(ibge_pib.ano_censo)', 'start_year') + .field('MAX(ibge_pib.ano_censo)', 'end_year') + .where('ibge_pib.ano_censo > 2013'); + next(); +}, query, response('range')); + +pibpercapitaApp.get('/years', (req, res, next) => { + req.sql.from('ibge_pib'). + field('DISTINCT ibge_pib.ano_censo', 'year') + .where('ibge_pib.ano_censo > 2013'); + next(); +}, query, response('years')); + +pibpercapitaApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'ibge_pib\''); + next(); +}, query, response('source')); + +pibpercapitaApp.get('/income_level', (req, res, next) => { + req.result = [ + {id: 1, name: "1º quintil – 20% menores"}, + {id: 2, name: "2º quintil"}, + {id: 3, name: "3º quintil"}, + {id: 4, name: "4º quintil"}, + {id: 5, name: "5º quintil – 20% maiores"}, + ]; + next(); +}, response('income_level')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'ibge_pib' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'ibge_pib' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: '@' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: '@' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'regiao_id', + table: 'ibge_pib' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'ibge_pib' + } +}).addValue({ + name: 'min_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'income_level', + table: 'ibge_pib', + tableField: 'nivel_renda_per_capita', + resultField: 'income_level_id', + where: { + relation: '=', + type: 'integer', + field: 'nivel_renda_per_capita' + } +}).addValue({ + name: 'income_level_brasil', + table: 'ibge_pib', + tableField: 'nivel_renda_brasil', + resultField: 'income_level_id', + where: { + relation: '=', + type: 'integer', + field: 'nivel_renda_brasil' + } +}).addValue({ + name: 'income_level_uf', + table: 'ibge_pib', + tableField: 'nivel_renda_uf', + resultField: 'income_level_id', + where: { + relation: '=', + type: 'integer', + field: 'nivel_renda_uf' + } +});; + +pibpercapitaApp.get('/', rqf.parse(), (req, res, next) => { + if ('income_level' in req.dims) { // Retorna os quintis + delete req.dims.income_level + + req.sql.from('pib_quintis') + .field('pib_quintis.valor', 'total') + .field('pib_quintis.tipo', 'income_level_id') + .field('pib_quintis.ano_censo', 'year') + .group('pib_quintis.ano_censo') + .group('pib_quintis.valor') + .group('pib_quintis.tipo') + .order('pib_quintis.tipo') + + if (!('state' in req.filter)) { + req.sql.where('pib_quintis.estado_id = 0') + } + if ('city' in req.filter) { + req.sql.join('ibge_pib', null, 'ibge_pib.nivel_renda_brasil=pib_quintis.tipo AND ibge_pib.ano_censo=pib_quintis.ano_censo') + } + } + + else if (("city" in req.dims) || ("city" in req.filter)) { + req.sql.from('ibge_pib') + .field('ibge_pib.pib_per_capita', 'total') + .field('ibge_pib.ano_censo', 'year') + .group('ibge_pib.ano_censo') + .group('ibge_pib.pib_per_capita') + .order('ibge_pib.ano_censo') + } else { + req.sql.from('ibge_pib') + .field('SUM(ibge_pib.pib)/SUM(ibge_pib.populacao)', 'total') + .field('ibge_pib.ano_censo', 'year') + .group('ibge_pib.ano_censo') + .order('ibge_pib.ano_censo') + } + next(); +}, rqf.build(), query, (req, res, next) => { + req.result.forEach((i) => { + let value = parseFloat(i.total); + let isnum = /^\d+$/.test(value); + if (isnum == true) { + value = value.toFixed(2) + } + // console.log(i.total); + + let res = value.toString().split("."); + //rounding decimal. + let decimal = Math.round(res[1].toString().substring(0,2) + (".") + res[1].toString().substring(2,3)); + //case 0 after comma + if (res[1].toString().substring(0,1) == 0) { + i.total = parseFloat(res[0] + "." + "0" + decimal); + } else { + i.total = parseFloat(res[0] + "." + decimal); + } + // console.log(i.total); + }); + next(); + }, id2str.transform(false), response("pibpercapita")); + + +module.exports = pibpercapitaApp; diff --git a/src/libs/routes_v2/population.js b/src/libs/routes_v2/population.js new file mode 100644 index 0000000000000000000000000000000000000000..fca3b0d6b309aba53aa0d9ff8e47eaf7d6f85d74 --- /dev/null +++ b/src/libs/routes_v2/population.js @@ -0,0 +1,163 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const populationApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +populationApp.use(cache('15 day')); + +populationApp.get('/year_range', (req, res, next) => { + req.sql.from('ibge_pib') + .field('MIN(ibge_pib.ano_censo)', 'start_year') + .field('MAX(ibge_pib.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +populationApp.get('/years', (req, res, next) => { + req.sql.from('ibge_pib'). + field('DISTINCT ibge_pib.ano_censo', 'year'); + next(); +}, query, response('years')); + +// populationApp.get('/city_size', (req, res, next) => { +// req.result = [ +// {id: 1, name: "0 - 5000"}, +// {id: 2, name: "5001 - 10000"}, +// {id: 3, name: "10001 - 20000"}, +// {id: 4, name: "20001 - 50000"}, +// {id: 5, name: "50001 - 100000"}, +// {id: 6, name: "100001 - 500000"}, +// {id: 7, name: "mais que 500000"} +// ]; +// next(); +// }, response('city_size')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'ibge_pib' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'ibge_pib' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'ibge_pib' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'ibge_pib' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'regiao_id', + table: 'ibge_pib' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'ibge_pib' + } +}).addValue({ + name: 'min_year', + table: 'ibge_pib', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'ibge_pib', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}); + +populationApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('ibge_pib') + .field('SUM(ibge_pib.populacao)', 'total') + .field('ibge_pib.ano_censo', 'year') + .group('ibge_pib.ano_censo') + .order('ibge_pib.ano_censo') + + next(); +}, query, addMissing(rqf), id2str.transform(false), response('population')); + +module.exports = populationApp; diff --git a/src/libs/routes_v2/portalMec.js b/src/libs/routes_v2/portalMec.js new file mode 100644 index 0000000000000000000000000000000000000000..e0e5353e54db8dc4a9c9814b84c9d2904fdb7950 --- /dev/null +++ b/src/libs/routes_v2/portalMec.js @@ -0,0 +1,136 @@ +const express = require('express'); + +const portalMecApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'day', + table: 'docente', + tableField: 'nasc_dia', + resultField: 'born_day_id', + where: { + relation: '=', + type: 'integer', + table: 'docente', + field: 'nasc_dia' + } +}).addValue({ + name: 'month', + table: 'docente', + tableField: 'nasc_mes_id', + resultField: 'born_month', + where: { + relation: '=', + type: 'integer', + table: 'docente', + field: 'nasc_mes' + } +}).addValue({ + name: 'year', + table: 'docente', + tableField: 'nasc_ano_id', + resultField: 'born_year', + where: { + relation: '=', + type: 'integer', + table: 'docente', + field: 'nasc_ano' + } +}).addValue({ + name: 'teacher', + table: 'docente', + tableField: 'id', + resultField: 'teacher_id', + where: { + relation: '=', + type: 'integer', + table: 'docente', + field: 'id' + } +}).addValue({ + name: 'min_year', + table: 'docente', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: 'docente', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'docente', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: 'docente', + field: 'ano_censo' + } +}); + +portalMecApp.get('/', rqf.parse(), (req, res, next) => { + + req.sql.field('docente.id_docente') + .field('docente.ano_censo', 'year') + .field('docente.cod_quimica', 'Química') + .field('docente.cod_fisica', 'Física') + .field('docente.cod_matematica', 'Matemática') + .field('docente.cod_biologia', 'Biologia') + .field('docente.cod_ciencias', 'Ciências') + .field('docente.cod_literat_port', 'Língua/ Literatura Portuguesa') + .field('docente.cod_literat_ing', 'Língua/ Literatura estrangeira - Inglês') + .field('docente.cod_literat_esp', 'Língua/ Literatura estrangeira - Espanhol') + .field('docente.cod_literat_frances', 'Língua/ Literatura estrangeira - Francês') + .field('docente.literat_outra', 'Língua/ Literatura estrangeira - Outra') + .field('docente.cod_literat_indigena', 'Língua/ Literatura estrangeira - Língua Indígena') + .field('docente.cod_artes', 'Artes (Educação Artística, Teatro, Dança, Música, Artes Plásticas e outras)') + .field('docente.cod_ed_fisica', 'Educação Física') + .field('docente.cod_hist', 'História') + .field('docente.cod_geo', 'Geografia') + .field('docente.cod_filos', 'Filosofia') + .field('docente.cod_ensino_religioso', 'Ensino Religioso') + .field('docente.cod_estudos_sociais', 'Estudos Sociais') + .field('docente.cod_sociologia', 'Sociologia') + .field('docente.cod_inf_comp', 'Informática/ Computação') + .field('docente.cod_profissionalizante', 'Disciplinas profissionalizantes') + .field('docente.cod_disc_atendimento_especiais', 'Disciplinas voltadas ao atendimento às necessidades educacionais específicas dos alunos que são público alvo da educação especial e às práticas educacionais inclusivas') + .field('docente.cod_disc_diversidade_socio_cult', 'Disciplinas voltadas à diversidade sociocultural (Disciplinas pedagógicas)') + .field('docente.cod_libras', 'Libras') + .field('docente.cod_disciplina_pedag', 'Disciplinas pedagógicas') + .field('docente.cod_outras_disciplina', 'Outras disciplinas') + .from('docente') + next(); + +}, rqf.build(), query, response('portalMec')); + +module.exports = portalMecApp; diff --git a/src/libs/routes_v2/portalMecInep.js b/src/libs/routes_v2/portalMecInep.js new file mode 100644 index 0000000000000000000000000000000000000000..2b23589130d1775c89520af1b8ee2827ac31add7 --- /dev/null +++ b/src/libs/routes_v2/portalMecInep.js @@ -0,0 +1,60 @@ +const express = require('express'); + +const portalMecInepApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'school_cod', + table: 'escola', + tableField: 'id', + resultField: 'school_cod_id', + where: { + relation: '=', + type: 'integer', + table: 'escola', + field: 'id' + } +}); + +portalMecInepApp.get('/', rqf.parse(), (req, res, next) => { + + req.sql.field('DISTINCT escola.id', 'id') + .field('escola.nome_escola', 'name') + .from('escola') + .join('estado', null, 'estado.id=escola.estado_id') + .field('estado.nome', 'state_name') + .join('municipio', null, 'municipio.id=escola.municipio_id') + .field('municipio.nome', 'city_name') + + next(); + +}, rqf.build(), query, response('portalMec_inep')); + +module.exports = portalMecInepApp; diff --git a/src/libs/routes_v2/rateSchool.js b/src/libs/routes_v2/rateSchool.js new file mode 100644 index 0000000000000000000000000000000000000000..a6a91b7be08919cc1ab12a304ee1832cfddfc84e --- /dev/null +++ b/src/libs/routes_v2/rateSchool.js @@ -0,0 +1,337 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const rateSchoolApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const multiQuery = require(`${libs}/middlewares/multiQuery`); + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +rateSchoolApp.use(cache('15 day')); + +let rqf = new ReqQueryFields(); + +// Complete range of the enrollments dataset. +// Returns a tuple of start and ending years of the complete enrollments dataset. +rateSchoolApp.get('/year_range', (req, res, next) => { + req.sql.from('pnad') + .field('MIN(pnad.ano_censo)', 'start_year') + .field('MAX(pnad.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +rateSchoolApp.get('/years', (req, res, next) => { + req.sql.from('pnad') + .field('DISTINCT pnad.ano_censo', 'year'); + next(); +}, query, response('years')); + +rateSchoolApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'pnad\''); + next(); +}, query, response('source')); + +rateSchoolApp.get('/ethnic_group_pnad', (req, res, next) => { + req.result = [ + {id: 0, name: 'Indígena'}, + {id: 1, name: 'Branca e amarela'}, + {id: 2, name: 'Preta e parda'}, + {id: 9, name: 'Sem declaração'} + ]; + next(); +}, response('ethnic_group_pnad')); + +rateSchoolApp.get('/age_range', (req, res, next) => { + req.result = [ + {id: 1, name: '0 a 3 anos'}, + {id: 2, name: '4 a 5 anos'}, + {id: 3, name: '6 a 10 anos'}, + {id: 4, name: '11 a 14 anos'}, + {id: 5, name: '15 a 17 anos'}, + {id: 6, name: '18 a 24 anos'} + ]; + next(); +}, response('age_range')); + +rateSchoolApp.get('/gender', (req, res, next) => { + req.result = [ + {id: 1, name: 'Masculino'}, + {id: 2, name: 'Feminino'} + ]; + next(); +}, response('gender')); + +rateSchoolApp.get('/location', (req, res, next) => { + req.result = [ + {id: 1, name: 'Urbana'}, + {id: 2, name: 'Rural'} + ]; + next(); +}, response('location')); + +rateSchoolApp.get('/fifth_household_income', (req, res, next) => { + req.result = [ + {id: 1, name: '20% menores'}, + {id: 2, name: '2o quinto'}, + {id: 3, name: '3o quinto'}, + {id: 4, name: '4o quinto'}, + {id: 5, name: '20% maiores'}, + {id: -1, name: 'Sem declaração'} + ]; + next(); +},response('fifth_household_income')); + +rateSchoolApp.get('/extremes_household_income', (req, res, next) => { + req.result = [ + {id: 1, name: '10% menores'}, + {id: 2, name: '10% maiores'}, + {id: -1, name: 'Sem declaração'} + ]; + next(); +}, response('extremes_household_income')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'pnad' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'pnad' + } +}).addValue({ + name: 'ethnic_group_pnad', + table: 'pnad', + tableField: 'cor_raca', + resultField: 'ethnic_group_pnad_id', + where: { + relation: '=', + type: 'integer', + field: 'cor_raca' + } +}).addValue({ + name: 'min_year', + table: 'pnad', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: 'pnad', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'pnad', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: 'pnad', + field: 'ano_censo' + } +}).addValue({ + name: 'age_range', + table: 'pnad', + tableField: 'faixa_etaria_31_03', + resultField: 'age_range_id', + where: { + relation: '=', + type: 'integer', + field: 'faixa_etaria_31_03' + } +}).addValue({ + name: 'gender', + table: 'pnad', + tableField: 'sexo', + resultField: 'gender_id', + where: { + relation: '=', + type: 'integer', + field: 'sexo' + } +}).addValue({ + name: 'location', + table: 'pnad', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'extremes_household_income', + table: 'pnad', + tableField: 'extremos_nivel_rendimento', + resultField: 'extremes_household_income_id', + where: { + relation: '=', + type: 'integer', + field: 'extremos_nivel_rendimento' + } +}).addValue({ + name: 'fifth_household_income', + table: 'pnad', + tableField: 'quintil_nivel_rendimento', + resultField: 'fifth_household_income_id', + where: { + relation: '=', + type: 'integer', + field: 'quintil_nivel_rendimento' + } +}); + +function matchQueries(queryTotal, queryPartial) { + let match = []; + queryTotal.forEach((result) => { + let newObj = {}; + let keys = Object.keys(result); + keys.forEach((key) => { + newObj[key] = result[key]; + }); + // console.log('NEW OBJ'); + // console.log(newObj); + let index = keys.indexOf('total'); + if(index > -1) keys.splice(index, 1); + let objMatch = null; + + for(let i = 0; i < queryPartial.length; ++i) { + let partial = queryPartial[i]; + let foundMatch = true; + for(let j = 0; j < keys.length; ++j) { + let key = keys[j]; + if(partial[key] !== result[key]) { + foundMatch = false; + break; + } + } + if(foundMatch) { + objMatch = partial; + break; + } + } + + if(objMatch) { + // console.log(objMatch); + newObj.denominator = result.total; + newObj.partial = objMatch.total; + newObj.total = (objMatch.total / result.total) * 100; + match.push(newObj); + } + }); + + return match; +} + +rateSchoolApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.querySet = []; + req.queryIndex = {}; + + log.debug(req.sql.toParam()); + if ("age_range" in req.filter || "age_range" in req.dims) { + let freq_total = req.sql.clone(); + freq_total.field('sum(pnad.peso)', 'total') + .field('pnad.ano_censo','year') + .from('pnad') + .group('pnad.ano_censo') + .order('pnad.ano_censo') + .where('pnad.faixa_etaria_31_03 < 7') + req.queryIndex.freq_total = req.querySet.push(freq_total) - 1; + + let freq_nursery = req.sql.clone(); + freq_nursery.field('sum(pnad.peso)', 'total') + .field('pnad.ano_censo','year') + .from('pnad') + .group('pnad.ano_censo') + .order('pnad.ano_censo') + .where('pnad.frequenta_escola_creche = 2') + .where('pnad.faixa_etaria_31_03 < 7') + req.queryIndex.freq_nursery = req.querySet.push(freq_nursery) - 1; + } + next(); +}, multiQuery, (req, res, next) => { + if ("age_range" in req.filter || "age_range" in req.dims) { + log.debug(req.result[req.queryIndex.freq_total]); + log.debug(req.result[req.queryIndex.freq_nursery]) + let school_attendance_rate = matchQueries(req.result[req.queryIndex.freq_total], req.result[req.queryIndex.freq_nursery]); + req.result = school_attendance_rate; + } else { + res.status(400); + next({ + status: 400, + message: 'Wrong/No filter specified' + }); + } + log.debug(req.result) + next(); +}, id2str.transform(false), response('rateSchool')); + +module.exports = rateSchoolApp; diff --git a/src/libs/routes_v2/region.js b/src/libs/routes_v2/region.js new file mode 100644 index 0000000000000000000000000000000000000000..5df65e726e1895f256f276ce22a32b1c7cc41712 --- /dev/null +++ b/src/libs/routes_v2/region.js @@ -0,0 +1,72 @@ +const express = require('express'); + +const regionApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +regionApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addValue({ + name: 'id', + table: '@', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id', + table: '@' + } +}).addValue({ + name: 'id_not', + table: '@', + tableField: 'id', + where: { + relation: '<>', + type: 'integer', + field: 'id', + table: '@' + } +}).addField({ + name: 'search', + field: false, + where: true +}).addValueToField({ + name: 'name', + table: '@', + tableField: 'nome', + where: { + relation: 'LIKE', + type: 'string', + field: 'nome', + table: '@' + } +}, 'search'); + +regionApp.get('/', rqf.parse(), (req, res, next) => { + req.sql.from('regiao') + .field('id') + .field('nome', 'name'); + next(); +}, rqf.build(), query, response('region')); + +module.exports = regionApp; diff --git a/src/libs/routes/resetToken.js b/src/libs/routes_v2/resetToken.js similarity index 95% rename from src/libs/routes/resetToken.js rename to src/libs/routes_v2/resetToken.js index 34ece8455adf7b77208dc200a95641ed04638609..3d67a1e2390dcd206f248fa3af59bda16e2fcbb6 100644 --- a/src/libs/routes/resetToken.js +++ b/src/libs/routes_v2/resetToken.js @@ -32,7 +32,7 @@ resetTokenApp.get('/:token', (req, res, next) => { }) return next({msg: 'Token expired', status: 410}); } - User.findById(rToken.userId, (err, user) => { + User.findByPk(rToken.userId, (err, user) => { if(err) { log.error(err); next(err); @@ -55,7 +55,7 @@ resetTokenApp.post('/:token', (req, res, next) => { res.statusCode = 404; return next({msg: 'Token not found', status:404}); } - User.findById(rToken.userId, (err, user) => { + User.findByPk(rToken.userId, (err, user) => { if(err) { log.error(err); next(err); diff --git a/src/libs/routes_v2/school.js b/src/libs/routes_v2/school.js new file mode 100644 index 0000000000000000000000000000000000000000..8a44a234bb15fe8daa9612169e4f150a04708a93 --- /dev/null +++ b/src/libs/routes_v2/school.js @@ -0,0 +1,716 @@ +const express = require('express'); + +const schoolApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const ReqBody = require(`${libs}/middlewares/reqBody`); + +const request = require(`request`); + +const config = require(`${libs}/config`); + +const passport = require('passport'); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); +let rqfCount = new ReqQueryFields(); +let reqBody = new ReqBody(); + +// Return location +schoolApp.get('/year_range', cache('15 day'), (req, res, next) => { + req.sql.from('escola_agregada') + .field('MIN(escola_agregada.ano_censo)', 'start_year') + .field('MAX(escola_agregada.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +schoolApp.get('/years', cache('15 day'), (req, res, next) => { + req.sql.from('escola_agregada'). + field('DISTINCT escola_agregada.ano_censo', 'year'); + next(); +}, query, response('years')); + +schoolApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'escola_agregada\''); + next(); +}, query, response('source')); + +schoolApp.get('/location', cache('15 day'), (req, res, next) => { + req.result = [ + {id: 1, name: 'Urbana'}, + {id: 2, name: 'Rural'} + ]; + next(); +}, response('location')); + +schoolApp.get('/diff_location', cache('15 day'), (req, res, next) => { + req.result = [ + {id: 0, name: "Não está em localidade diferenciada"}, + {id: 1, name: "Área de assentamento"}, + {id: 2, name: "Terra indígena"}, + {id: 3, name: "Terra remanescente de quilombos"}, + ]; + next(); +}, response('diff_location')); + +schoolApp.get('/adm_dependency', (req, res, next) => { + req.result = []; + + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.admDependency(i) + }); + }; + next(); +}, response('adm_dependency')); + +schoolApp.get('/adm_dependency_detailed', cache('15 day'), (req, res, next) => { + req.result = []; + for(let i = 1; i <= 8; i++) { + req.result.push({ + id: i, + name: id2str.admDependencyPriv(i) + }); + }; + next(); +}, response('adm_dependency_detailed')); + +schoolApp.get('/government_agreement', cache('15 day'), (req, res, next) => { + req.result = [{ + id: "null", + name: id2str.governmentAgreement("null") + }]; + for(let i = 1; i <= 6; ++i) { + req.result.push({ + id: i, + name: id2str.governmentAgreement(i) + }); + }; + next(); +}, response('government_agreement')); + +schoolApp.get('/agreement', cache('15 day'), (req, res, next) => { + req.result = [ + {id: 1, name: 'Municipal'}, + {id: 2, name: 'Estadual'}, + {id: 3, name: 'Estadual e Municipal'} + ]; + next(); +}, response('agreement')); + +schoolApp.get('/education_day_care_child', (req, res, next) => { + req.result = [ + {id: null, name: 'Não Declarado'}, + {id: 0, name: 'Não'}, + {id: 1, name: 'Sim'} + ]; + next(); +}, response('education_day_care_child')); + +schoolApp.get('/education_preschool_child', cache('15 day'), (req, res, next) => { + req.result = [ + {id: null, name: 'Não Declarado'}, + {id: 0, name: 'Não'}, + {id: 1, name: 'Sim'} + ]; + next(); +}, response('education_preschool_child')); + +schoolApp.get('/education_begin_elementary_school', cache('15 day'), (req, res, next) => { + req.result = [ + {id: null, name: 'Não Declarado'}, + {id: 0, name: 'Não'}, + {id: 1, name: 'Sim'} + ]; + next(); +}, response('education_begin_elementary_school')); + +schoolApp.get('/education_end_elementary_school', cache('15 day'), (req, res, next) => { + req.result = [ + {id: null, name: 'Não Declarado'}, + {id: 0, name: 'Não'}, + {id: 1, name: 'Sim'} + ]; + next(); +}, response('education_end_elementary_school')); + +schoolApp.get('/education_middle_school', cache('15 day'), (req, res, next) => { + req.result = [ + {id: null, name: 'Não Declarado'}, + {id: 0, name: 'Não'}, + {id: 1, name: 'Sim'} + ]; + next(); +}, response('education_middle_school')); + +schoolApp.get('/education_professional', cache('15 day'), (req, res, next) => { + req.result = [ + {id: null, name: 'Não Declarado'}, + {id: 0, name: 'Não'}, + {id: 1, name: 'Sim'} + ]; + next(); +}, response('education_professional')); + +schoolApp.get('/education_eja', cache('15 day'), (req, res, next) => { + req.result = [ + {id: null, name: 'Não Declarado'}, + {id: 0, name: 'Não'}, + {id: 1, name: 'Sim'} + ]; + next(); +}, response('education_eja')); + + +schoolApp.get('/arrangement', cache('15 day'), (req, res, next) => { + req.result = [ + {id: 0, name: 'Creche'}, + {id: 1, name: 'Pré Escola'}, + {id: 2, name: 'Ensino Fundamental - AI'}, + {id: 3, name: 'Ensino Fundamental - AF'}, + {id: 4, name: 'Ed. Infantil Unificada/Multietapa/Multissérie/Correção fluxo'}, + {id: 5, name: 'Ensino Médio'}, + {id: 6, name: 'Ensino EJA'}, + {id: 7, name: 'Educação Profissional'}, + {id: 8, name: 'Educação Especial Exclusiva'} + ]; + next(); +}, response('arrangement')); + +schoolApp.get('/integral_time', cache('15 day'), (req, res, next) => { + req.result = []; + for(let i = 0; i <= 2; ++i) { + req.result.push({ + id: i, + name: id2str.integralTime(i) + }); + } + next(); +}, response('integral_time')); + + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addValue({ + name: 'id', + table: 'escola_agregada', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'escola_agregada' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'escola_agregada' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'escola_agregada' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'escola_agregada' + } +}).addValue({ + name: 'year', + table: 'escola_agregada', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo', + table: 'escola_agregada' + } +}).addValue({ + name: 'min_year', + table: 'escola_agregada', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'escola_agregada', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'adm_dependency', + table: 'escola_agregada', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}).addValue({ + name: 'min_year', + table: 'escola_agregada', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'escola_agregada', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}).addField({ + name: 'search', + field: true, + where: true +}).addValueToField({ + name: 'city_name', + table: 'municipio', + tableField: 'nome', + resultField: 'city_name', + dontGroup: true, + where: { + relation: 'LIKE', + type: 'string', + field: 'nome' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'escola_agregada' + } +}, 'search') +.addValueToField({ + name: 'state_name', + table: 'estado', + tableField: 'nome', + resultField: 'state_name', + dontGroup: true, + where: { + relation: 'LIKE', + type: 'string', + field: 'sigla' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'escola_agregada' + } +}, 'search').addValue({ + name: 'diff_location', + table: 'escola_agregada', + tableField: 'localizacao_diferenciada_par', + resultField: 'diff_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_diferenciada_par' + } +}); + +rqfCount.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'id', + table: 'escola_agregada', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id' + } +}).addValueToField({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'escola_agregada' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'escola_agregada' + } +}, 'dims').addValueToField({ + name: 'city', + table: 'municipio', + tableField: 'nome', + resultField: 'city_name', + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'escola_agregada' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'escola_agregada' + } +}, 'filter').addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'escola_agregada' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'escola_agregada' + } +}).addValue({ + name: 'mesoregion', + table: 'municipio', + tableField: ['nome_mesorregiao', 'mesorregiao_id'], + resultField: ['mesoregion_name', 'mesoregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'mesorregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'escola_agregada' + } +}).addValue({ + name: 'microregion', + table: 'municipio', + tableField: ['nome_microrregiao', 'microrregiao_id'], + resultField: ['microregion_name', 'microregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'microrregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'escola_agregada' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'escola_agregada' + } +}).addValue({ + name: 'year', + table: 'escola_agregada', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo', + table: 'escola_agregada' + } +}).addValue({ + name: 'location', + table: 'escola_agregada', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'diff_location', + table: 'escola_agregada', + tableField: 'localizacao_diferenciada_par', + resultField: 'diff_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_diferenciada_par' + } +}).addValue({ + name: 'rural_location', + table: 'escola_agregada', + tableField: 'localidade_area_rural', + resultField: 'rural_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localidade_area_rural' + } +}).addValue({ + name: 'arrangement', + table: 'escola_agregada', + tableField: 'arranjo', + resultField: 'arrangement_id', + where: { + relation: '=', + type: 'integer', + field: 'arranjo' + } +}).addValue({ + name: 'adm_dependency', + table: 'escola_agregada', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}).addValue({ + name: 'adm_dependency_detailed', + table: 'escola_agregada', + tableField: 'dependencia_adm_priv', + resultField: 'adm_dependency_detailed_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_priv' + } +}).addValue({ + name: 'government_agreement', + table: 'escola_agregada', + tableField: 'dependencia_convenio_publico', + resultField: 'government_agreement_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_convenio_publico' + } +}).addValue({ + name: 'integral_time', + table: 'escola_agregada', + tableField: 'tempo_integral', + resultField: 'integral_time_id', + where: { + relation: '=', + type: 'boolean', + field: 'tempo_integral' + } +}).addValue({ + name: 'agreement', + table: 'escola_agregada', + tableField: 'tipo_convenio_pp', + resultField: 'agreement_id', + where: { + relation: '=', + type: 'integer', + field: 'tipo_convenio_pp' + } +}).addValue({ + name: 'education_day_care_child', + table: 'escola_agregada', + tableField: 'reg_infantil_creche_t1', + resultField: 'education_day_care_child_id', + where: { + relation: '=', + type: 'boolean', + field: 'reg_infantil_creche_t1' + } +}).addValue({ + name: 'education_preschool_child', + table: 'escola_agregada', + tableField: 'reg_infantil_preescola_t1', + resultField: 'education_preschool_child_id', + where: { + relation: '=', + type: 'boolean', + field: 'reg_infantil_preescola_t1' + } +}).addValue({ + name: 'education_begin_elementary_school', + table: 'escola_agregada', + tableField: 'reg_fund_ai_t1', + resultField: 'education_begin_elementary_school_id', + where: { + relation: '=', + type: 'boolean', + field: 'reg_fund_ai_t1' + } +}).addValue({ + name: 'education_end_elementary_school', + table: 'escola_agregada', + tableField: 'reg_fund_af_t1', + resultField: 'education_end_elementary_school_id', + where: { + relation: '=', + type: 'boolean', + field: 'reg_fund_af_t1' + } +}).addValue({ + name: 'education_middle_school', + table: 'escola_agregada', + tableField: 'reg_medio_medio_t1', + resultField: 'education_middle_school_id', + where: { + relation: '=', + type: 'boolean', + field: 'reg_medio_medio_t1' + } +}).addValue({ + name: 'education_professional', + table: 'escola_agregada', + tableField: 'educacao_profissional', + resultField: 'education_professional_id', + where: { + relation: '=', + type: 'boolean', + field: 'educacao_profissional' + } +}).addValue({ + name: 'education_eja', + table: 'escola_agregada', + tableField: 'ensino_eja', + resultField: 'education_eja_id', + where: { + relation: '=', + type: 'boolean', + field: 'ensino_eja' + } +}).addValue({ + name: 'min_year', + table: 'escola_agregada', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'escola_agregada', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'school_building', + table: 'escola_agregada', + tableField: 'local_func_predio_escolar', + resultField: 'school_building', + where: { + relation: '=', + type: 'boolean', + field: 'local_func_predio_escolar' + } +}); +schoolApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + + req.sql.from('escola_agregada') + .field('escola_agregada.id') + .field('escola_agregada.ano_censo', 'year') + .field('escola_agregada.nome_escola', 'name') + .field('escola_agregada.estado_id', 'state_id') + .field('escola_agregada.municipio_id', 'city_id'); + next(); +}, query, response('school')); + +schoolApp.get('/count', cache('15 day'), rqfCount.parse(), (req, res, next) => { + let arrang = ["arranjo_creche", "arranjo_pre", "arranjo_fundamental_ai", "arranjo_fundamental_af", "arranjo_multietapa", "arranjo_ensino_medio", "ensino_eja", "educacao_profissional", "ensino_especial"]; + + req.sql.from('escola_agregada') + .field('COUNT(escola_agregada.id)', 'total') + .field("'Brasil'", 'name') + .field('escola_agregada.ano_censo', 'year') + .group('escola_agregada.ano_censo') + .order('escola_agregada.ano_censo') + .where('escola_agregada.situacao_funcionamento_pareada = 1 AND (escola_agregada.ensino_regular = 1 OR escola_agregada.ensino_eja=1 or escola_agregada.educacao_profissional=1)') + + //Transforma a query em OR se tiver o filtro do arranjo + if (req.filter.arrangement) { + let arrangementQuery = ""; + for (let i = 0; i < req.filter.arrangement.length - 1; i++) { + arrangementQuery += 'escola_agregada.' + arrang[req.filter.arrangement[i]] + ' = 1 OR '; + } + // o ultimo elemento precisa ser sem o OR + arrangementQuery += 'escola_agregada.' + arrang[req.filter.arrangement[req.filter.arrangement.length - 1]] + ' = 1'; + req.sql.where('' + arrangementQuery); + } + delete req.filter.arrangement + next(); +}, rqfCount.build(), query, id2str.transform(), addMissing(rqfCount), response('school')); + +module.exports = schoolApp; diff --git a/src/libs/routes_v2/schoolInfrastructure.js b/src/libs/routes_v2/schoolInfrastructure.js new file mode 100644 index 0000000000000000000000000000000000000000..00b87e03d8a405acf14a686f27b24582a7c8a2b6 --- /dev/null +++ b/src/libs/routes_v2/schoolInfrastructure.js @@ -0,0 +1,741 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const infrastructureApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const multiQuery = require(`${libs}/middlewares/multiQuery`); + +const response = require(`${libs}/middlewares/response`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +infrastructureApp.use(cache('15 day')); + +infrastructureApp.get('/year_range', (req, res, next) => { + req.sql.from('escola_agregada') + .field('MIN(escola_agregada.ano_censo)', 'start_year') + .field('MAX(escola_agregada.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +infrastructureApp.get('/years', (req, res, next) => { + req.sql.from('escola_agregada') + .field('DISTINCT escola_agregada.ano_censo', 'year'); + next(); +}, query, response('years')); + +infrastructureApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'escola_agregada\''); + next(); +}, query, response('source')); + +infrastructureApp.get('/location', (req, res, next) => { + req.result = [ + {id: 1, name: 'Urbana'}, + {id: 2, name: 'Rural'} + ]; + next(); +}, response('location')); + +infrastructureApp.get('/rural_location', (req, res, next) => { + req.result = [ + {id: 1, name: "Urbana"}, + {id: 2, name: "Rural"}, + {id: 3, name: "Rural - Área de assentamento"}, + {id: 4, name: "Rural - Terra indígena"}, + {id: 5, name: "Rural - Área remanescente de quilombos"}, + {id: 6, name: "Rural - Unidade de uso sustentável"} + ]; + next(); +}, response('rural_location')); + +infrastructureApp.get('/adm_dependency', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.admDependency(i) + }); + }; + next(); +}, response('adm_dependency')); + +infrastructureApp.get('/adm_dependency_detailed', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 6; ++i) { + req.result.push({ + id: i, + name: id2str.admDependencyPriv(i) + }); + }; + next(); +}, response('adm_dependency_detailed')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValueToField({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'escola_agregada' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'escola_agregada' + } +}, 'dims').addValueToField({ + name: 'city', + table: 'municipio', + tableField: 'id', + resultField: 'city_id', + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'escola_agregada' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'escola_agregada' + } +}, 'filter').addValueToField({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'escola_agregada' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'escola_agregada' + } +}, 'dims').addValueToField({ + name: 'state', + table: 'estado', + tableField: 'id', + resultField: 'state_id', + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'escola_agregada' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'escola_agregada' + } +}, 'filter').addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'escola_agregada' + } +}).addValue({ + name: 'location', + table: 'escola_agregada', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'rural_location', + table: 'escola_agregada', + tableField: 'localidade_area_rural', + resultField: 'rural_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localidade_area_rural' + } +}).addValue({ + name: 'adm_dependency', + table: 'escola_agregada', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}).addValue({ + name: 'adm_dependency_detailed', + table: 'escola_agregada', + tableField: 'dependencia_adm_priv', + resultField: 'adm_dependency_detailed_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_priv' + } +}).addValue({ + name: 'min_year', + table: 'escola_agregada', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'escola_agregada', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}); + +function matchQueries(queryTotal, queryPartial, queryNeeded, zeroPercentage=false) { + let match = []; + queryTotal.forEach((result) => { + let newObj = {}; + let keys = Object.keys(result); + keys.forEach((key) => { + newObj[key] = result[key]; + }); + let index = keys.indexOf('total'); + if(index > -1) keys.splice(index, 1); + let partialMatch = null; + let needMatch = null; + + for(let i = 0; i < queryPartial.length; ++i) { + let partial = queryPartial[i]; + let foundMatch = true; + for(let j = 0; j < keys.length; ++j) { + let key = keys[j]; + if(partial[key] !== result[key]) { + foundMatch = false; + break; + } + } + if(foundMatch) { + partialMatch = partial; + break; + } + } + if(queryPartial.length == 0) { + partialMatch = JSON.parse(JSON.stringify(result)); + partialMatch.total = 0; + } + + for(let i = 0; i < queryNeeded.length; ++i) { + let needed = queryNeeded[i]; + let foundMatch = true; + for(let j = 0; j < keys.length; ++j) { + let key = keys[j]; + if(needed[key] !== result[key]) { + foundMatch = false; + break; + } + } + if(foundMatch) { + needMatch = needed; + break; + } + } + + if(queryNeeded.length == 0) { + needMatch = JSON.parse(JSON.stringify(result)); + needMatch.total = 0; + } + + newObj.percentage = ( ( partialMatch ? partialMatch.total : 0) / result.total) * 100; + if(zeroPercentage) newObj.percentage = 0; + newObj.partial = ( partialMatch ? partialMatch.total : 0); + newObj.total = result.total; + newObj.need_adaptation = needMatch ? needMatch.total : 0; + match.push(newObj); + }); + + return match; +} + +infrastructureApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.querySet = []; + req.queryIndex = {}; + + // Local de funcionamento + let allSchools = req.sql.clone(); + allSchools.from('escola_agregada').field('COUNT(escola_agregada.id)', 'total') + .field("'Brasil'", 'name') + .field('escola_agregada.ano_censo', 'year') + .group('escola_agregada.ano_censo') + .where('escola_agregada.situacao_de_funcionamento = 1') + .where('escola_agregada.ensino_regular = 1 OR escola_agregada.ensino_eja = 1 OR escola_agregada.educacao_profissional = 1') + .where('escola_agregada.local_func_predio_escolar = 1') + .where('escola_agregada.dependencia_adm_id <= 3') + .order('escola_agregada.ano_censo'); + req.queryIndex.allSchools = req.querySet.push(allSchools) - 1; + + let allUrbanSchools = allSchools.clone(); + allUrbanSchools.where('escola_agregada.localizacao_id = 1'); + req.queryIndex.allUrbanSchools = req.querySet.push(allUrbanSchools) - 1; + + let allCountrySchools = allSchools.clone(); + allCountrySchools.where('escola_agregada.localizacao_id = 2'); + req.queryIndex.allCountrySchools = req.querySet.push(allCountrySchools) - 1; + + let allSchoolsNotSchoolBuilding = req.sql.clone(); + allSchoolsNotSchoolBuilding.from('escola_agregada').field('COUNT(escola_agregada.id)', 'total') + .field("'Brasil'", 'name') + .field('escola_agregada.ano_censo', 'year') + .group('escola_agregada.ano_censo') + .where('escola_agregada.situacao_de_funcionamento = 1') + .where('escola_agregada.ensino_regular = 1 OR escola_agregada.ensino_eja = 1 OR escola_agregada.educacao_profissional = 1') + .where('escola_agregada.local_func_predio_escolar = 0') + .where('escola_agregada.dependencia_adm_id <= 3') + .order('escola_agregada.ano_censo'); + req.queryIndex.allSchoolsNotSchoolBuilding = req.querySet.push(allSchoolsNotSchoolBuilding) - 1; + + // Bibliotecas + req.queryIndex.allLibraries = req.queryIndex.allUrbanSchools; + + let haveLibraries = allUrbanSchools.clone(); + haveLibraries.where('escola_agregada.biblioteca = 1'); + req.queryIndex.haveLibraries = req.querySet.push(haveLibraries) - 1; + + let needLibraries = allUrbanSchools.clone(); + needLibraries.where('escola_agregada.biblioteca = 0'); + req.queryIndex.needLibraries = req.querySet.push(needLibraries) - 1; + + // Sala de leitura + req.queryIndex.allLibrariesReadingRoom = req.queryIndex.allCountrySchools; + + let haveLibrariesReadingRoom = allCountrySchools.clone(); + haveLibrariesReadingRoom.where('escola_agregada.biblioteca_sala_leitura = true'); + req.queryIndex.haveLibrariesReadingRoom = req.querySet.push(haveLibrariesReadingRoom) - 1; + + let needLibrariesReadingRoom = allCountrySchools.clone(); + needLibrariesReadingRoom.where('escola_agregada.biblioteca_sala_leitura = false'); + req.queryIndex.needLibrariesReadingRoom = req.querySet.push(needLibrariesReadingRoom) - 1; + + // Laboratório de informática + // Se (situacao_de_funcionamento=1) & (dependencia_adm_id<=3) & (CEBES027P1=1) & + // (ensino_regular=1 | ensino_eja=1 | educacao_profissional=1) & + // ( reg_fund_ai_t1=1 | reg_fund_af_t1=1 | reg_medio_medio_t1=1 | ensino_eja_fund= 1 | ensino_eja_medio= 1 | ensino_eja_prof= 1 | esp_eja_fund=1 | + // esp_eja_medio=1 | ensino_esp_exclusiva_eja_prof=1) então conta id + let allInfLab = allSchools.clone(); + allInfLab.where('etapa_en_fundamental_anos_iniciais = 1 OR etapa_en_fundamental_anos_finais = 1 OR etapa_en_medio = 1'); + req.queryIndex.allInfLab = req.querySet.push(allInfLab) - 1; + + let haveInfLab = allInfLab.clone(); + haveInfLab.where('escola_agregada.lab_informatica = 1'); + req.queryIndex.haveInfLab = req.querySet.push(haveInfLab) - 1; + + let needInfLab = allInfLab.clone(); + needInfLab.where('escola_agregada.lab_informatica = 0'); + req.queryIndex.needInfLab = req.querySet.push(needInfLab) - 1; + + // Laboratório de ciências + let allScienceLab = allSchools.clone(); + allScienceLab.where('reg_fund_af_t1=1 OR reg_medio_medio_t1=1 OR ensino_eja_fund=1 OR ensino_eja_medio=1 OR ensino_eja_prof=1 OR esp_eja_fund=1 OR esp_eja_medio=1 OR ensino_esp_exclusiva_eja_prof=1'); + req.queryIndex.allScienceLab = req.querySet.push(allScienceLab) - 1; + + let haveScienceLab = allScienceLab.clone(); + haveScienceLab.where('escola_agregada.lab_ciencias = 1 AND (etapa_en_fundamental_anos_finais = 1 OR etapa_en_medio = 1)'); + req.queryIndex.haveScienceLab = req.querySet.push(haveScienceLab) - 1; + + let needScienceLab = allScienceLab.clone(); + needScienceLab.where('escola_agregada.lab_ciencias = false'); + req.queryIndex.needScienceLab = req.querySet.push(needScienceLab) - 1; + + // Parque infantil + // Se (situacao_de_funcionamento=1) and (ensino_regular=1 OR ensino_eja=1 OR educacao_profissional=1) and + // (local_func_predio_escolar=1) and (dependencia_adm_id<=3) and (reg_infantil_creche_t1=1 or reg_infantil_preescola_t1=1 or reg_fund_ai_t1=1) então conta id + let allKidsPark = allSchools.clone(); + allKidsPark.where('escola_agregada.etapa_ed_infantil_creche = 1 OR escola_agregada.etapa_en_fundamental_anos_iniciais = 1'); + req.queryIndex.allKidsPark = req.querySet.push(allKidsPark) - 1; + + let haveKidsPark = allKidsPark.clone(); + haveKidsPark.where('escola_agregada.parque_infantil = 1'); + req.queryIndex.haveKidsPark = req.querySet.push(haveKidsPark) - 1; + + let needKidsPark = allKidsPark.clone(); + needKidsPark.where('escola_agregada.parque_infantil = 0'); + req.queryIndex.needKidsPark = req.querySet.push(needKidsPark) - 1; + + // // Berçário + // let allCribs = allSchools.clone(); + // allCribs.where('escola_agregada.reg_infantil_creche_t1 = 1'); + // req.queryIndex.allCribs = req.querySet.push(allCribs) - 1; + + // let haveCribs = allCribs.clone(); + // haveCribs.where('escola_agregada.bercario = 1'); + // req.queryIndex.haveCribs = req.querySet.push(haveCribs) - 1; + + // let needCribs = allCribs.clone(); + // needCribs.where('escola_agregada.bercario = 0'); + // req.queryIndex.needCribs = req.querySet.push(needCribs) - 1; + + // Quadra de esportes + let allSportsCourt = allSchools.clone(); + allSportsCourt.where('escola_agregada.localizacao_id = 1 AND (etapa_en_fundamental_anos_iniciais = 1 OR etapa_en_fundamental_anos_finais = 1 OR etapa_en_medio = 1)'); + req.queryIndex.allSportsCourt = req.querySet.push(allSportsCourt) - 1; + + let haveSportsCourt = allSportsCourt.clone(); + haveSportsCourt.where('escola_agregada.quadra_esportes = 1 AND (etapa_en_fundamental_anos_iniciais = 1 OR etapa_en_fundamental_anos_finais = 1 OR etapa_en_medio = 1)'); + req.queryIndex.haveSportsCourt = req.querySet.push(haveSportsCourt) - 1; + + let needSportsCourt = allSportsCourt.clone(); + needSportsCourt.where('escola_agregada.quadra_esportes = 0 AND (etapa_en_fundamental_anos_iniciais = 1 OR etapa_en_fundamental_anos_finais = 1 OR etapa_en_medio = 1)'); + req.queryIndex.needSportsCourt = req.querySet.push(needSportsCourt) - 1; + + // Quadras a serem cobertas + // Se (situacao_de_funcionamento=1) and (ensino_regular=1 OR ensino_eja=1 OR educacao_profissional=1) and (local_func_predio_escolar=1) and + // (dependencia_adm_id<=3) and (reg_fund_ai_t1=1 or reg_fund_af_t1=1 or reg_medio_medio_t1=1 or ensino_eja_fund= 1 or ensino_eja_medio= 1 or + // ensino_eja_prof= 1 or esp_eja_fund=1 or esp_eja_medio=1 or ensino_esp_exclusiva_eja_prof=1) and (quadra_esportes_descoberta=1) então conta id + let allSportsCourtCoverage = allSportsCourt.clone(); + allSportsCourtCoverage.where('escola_agregada.quadra_esportes_descoberta = 1'); + req.queryIndex.allSportsCourtCoverage = req.querySet.push(allSportsCourtCoverage) -1; + + req.queryIndex.haveSportsCourtCoverage = req.queryIndex.allSportsCourtCoverage; // It must be [] + + req.queryIndex.needSportsCourtCoverage = req.queryIndex.allSportsCourtCoverage; + + // Pátio + req.queryIndex.allCourtyard = req.queryIndex.allSchools; + + let haveCourtyard = allSchools.clone(); + haveCourtyard.where('escola_agregada.func_predio_escolar = 1 AND (escola_agregada.patio = 1 OR escola_agregada.patio = 2)'); + req.queryIndex.haveCourtyard = req.querySet.push(haveCourtyard) - 1; + + let needCourtyard = allSchools.clone(); + needCourtyard.where('escola_agregada.func_predio_escolar = 1 AND escola_agregada.patio = 0'); + req.queryIndex.needCourtyard = req.querySet.push(needCourtyard) - 1; + + // Pátios a serem cobertos + let allCourtyardCoverage = allSchools.clone(); + allCourtyardCoverage.where('escola_agregada.patio = 1'); + req.queryIndex.allCourtyardCoverage = req.querySet.push(allCourtyardCoverage) - 1; + + req.queryIndex.haveCourtyardCoverage = req.queryIndex.allCourtyardCoverage; // It must be [] + + req.queryIndex.needCourtyardCoverage = req.queryIndex.allCourtyardCoverage; + + // Sala de direção + req.queryIndex.allDirectorRoom = req.queryIndex.allUrbanSchools; + + let haveDirectorRoom = allUrbanSchools.clone(); + haveDirectorRoom.where('escola_agregada.sala_diretoria = 1'); + req.queryIndex.haveDirectorRoom = req.querySet.push(haveDirectorRoom) - 1; + + let needDirectorRoom = allUrbanSchools.clone(); + needDirectorRoom.where('escola_agregada.sala_diretoria = 0'); + req.queryIndex.needDirectorRoom = req.querySet.push(needDirectorRoom) - 1; + + // Secretaria + req.queryIndex.allSecretary = req.queryIndex.allSchools; + + let haveSecretary = allSchools.clone(); + haveSecretary.where('escola_agregada.secretaria = 1'); + req.queryIndex.haveSecretary = req.querySet.push(haveSecretary) - 1; + + let needSecretary = allSchools.clone(); + needSecretary.where('escola_agregada.secretaria = 0'); + req.queryIndex.needSecretary = req.querySet.push(needSecretary) - 1; + + // Sala de professores + req.queryIndex.allTeacherRoom = req.queryIndex.allSchools; + + let haveTeacherRoom = allSchools.clone(); + haveTeacherRoom.where('escola_agregada.sala_professor = 1'); + req.queryIndex.haveTeacherRoom = req.querySet.push(haveTeacherRoom) - 1; + + let needTeacherRoom = allSchools.clone(); + needTeacherRoom.where('escola_agregada.sala_professor = 0'); + req.queryIndex.needTeacherRoom = req.querySet.push(needTeacherRoom) - 1; + + // Cozinha + req.queryIndex.allKitchen = req.queryIndex.allSchools; + + let haveKitchen = allSchools.clone(); + haveKitchen.where('escola_agregada.cozinha = 1'); + req.queryIndex.haveKitchen = req.querySet.push(haveKitchen) - 1; + + let needKitchen = allSchools.clone(); + needKitchen.where('escola_agregada.cozinha = 0'); + req.queryIndex.needKitchen = req.querySet.push(needKitchen) - 1; + + // Despensa + req.queryIndex.allStoreroom = req.queryIndex.allSchools; + + let haveStoreroom = allSchools.clone(); + haveStoreroom.where('escola_agregada.despensa = 1'); + req.queryIndex.haveStoreroom = req.querySet.push(haveStoreroom) - 1; + + let needStoreroom = allSchools.clone(); + needStoreroom.where('escola_agregada.despensa = 0'); + req.queryIndex.needStoreroom = req.querySet.push(needStoreroom) - 1; + + // Almoxarifado + req.queryIndex.allWarehouse = req.queryIndex.allSchools; + + let haveWarehouse = allSchools.clone(); + haveWarehouse.where('escola_agregada.almoxarifado = 1'); + req.queryIndex.haveWarehouse = req.querySet.push(haveWarehouse) - 1; + + let needWarehouse = allSchools.clone(); + needWarehouse.where('escola_agregada.almoxarifado = 0'); + req.queryIndex.needWarehouse = req.querySet.push(needWarehouse) - 1; + + // Internet + req.queryIndex.allInternet = req.queryIndex.allCountrySchools; + + let haveInternet = allCountrySchools.clone(); + haveInternet.where('escola_agregada.internet = 1 AND localizacao_id = 2'); + req.queryIndex.haveInternet = req.querySet.push(haveInternet) - 1; + + let needInternet = allCountrySchools.clone(); + needInternet.where('escola_agregada.internet = 0 AND localizacao_id = 2'); + req.queryIndex.needInternet = req.querySet.push(needInternet) - 1; + + // Internet banda larga + // Se (situacao_de_funcionamento=1) and (ensino_regular=1 OR ensino_eja=1 OR educacao_profissional=1) and (local_func_predio_escolar=1) and + // (dependencia_adm_id<=3) and (localizacao_id=2) então conta id + req.queryIndex.allBroadbandInternet = req.queryIndex.allUrbanSchools; + + let haveBroadbandInternet = allUrbanSchools.clone(); + haveBroadbandInternet.where('escola_agregada.internet_banda_larga = 1 AND localizacao_id = 1'); + req.queryIndex.haveBroadbandInternet = req.querySet.push(haveBroadbandInternet) - 1; + + let needBroadbandInternet = allUrbanSchools.clone(); + needBroadbandInternet.where('escola_agregada.internet_banda_larga = 0 AND localizacao_id = 1'); + req.queryIndex.needBroadbandInternet = req.querySet.push(needBroadbandInternet) - 1; + + // Banheiro + req.queryIndex.allInsideBathroom = req.queryIndex.allSchools; + + let haveInsideBathroom = allSchools.clone(); + haveInsideBathroom.where('escola_agregada.banheiro = 1'); + req.queryIndex.haveInsideBathroom = req.querySet.push(haveInsideBathroom) - 1; + + let needInsideBathroom = allSchools.clone(); + needInsideBathroom.where('escola_agregada.banheiro = 0'); + req.queryIndex.needInsideBathroom = req.querySet.push(needInsideBathroom) - 1; + + // Banheiro adequado para educação infantil dentro do prédio + // Se (situacao_de_funcionamento=1) and (ensino_regular=1 OR ensino_eja=1 OR educacao_profissional=1) and (local_func_predio_escolar=1) and + // (dependencia_adm_id<=3) and (reg_infantil_creche_t1=1 or reg_infantil_preescola_t1=1 or reg_fund_ai_t1=1) então conta id + let allInsideKidsBathroom = allSchools.clone(); + allInsideKidsBathroom.where('reg_infantil_creche_t1=1 OR reg_infantil_preescola_t1=1 OR reg_fund_ai_t1=1'); + req.queryIndex.allInsideKidsBathroom = req.querySet.push(allInsideKidsBathroom) - 1; + + let haveInsideKidsBathroom = allInsideKidsBathroom.clone(); + haveInsideKidsBathroom.where('escola_agregada.sanitario_ei = 1 AND (escola_agregada.etapa_ed_infantil_creche = 1 OR escola_agregada.etapa_en_fundamental_anos_iniciais = 1) AND localizacao_id IN (1, 2)'); + req.queryIndex.haveInsideKidsBathroom = req.querySet.push(haveInsideKidsBathroom) - 1; + + let needInsideKidsBathroom = allInsideKidsBathroom.clone(); + needInsideKidsBathroom.where('escola_agregada.sanitario_ei = 0 AND (escola_agregada.etapa_ed_infantil_creche = 1 OR escola_agregada.etapa_en_fundamental_anos_iniciais = 1) AND localizacao_id IN (1, 2)'); + req.queryIndex.needInsideKidsBathroom = req.querySet.push(needInsideKidsBathroom) - 1; + + // Fornecimento de energia + req.queryIndex.allEletricPower = req.queryIndex.allSchools; + + let haveEletricPower = allSchools.clone(); + haveEletricPower.where('escola_agregada.energia_inexistente = 0'); + req.queryIndex.haveEletricPower = req.querySet.push(haveEletricPower) - 1; + + let needEletricPower = allSchools.clone(); + needEletricPower.where('escola_agregada.energia_inexistente = 1'); + req.queryIndex.needEletricPower = req.querySet.push(needEletricPower) - 1; + + // Abastecimento de água + req.queryIndex.allWaterSupply = req.queryIndex.allSchools; + + let haveWaterSupply = allSchools.clone(); + haveWaterSupply.where('escola_agregada.agua_inexistente = 0'); + req.queryIndex.haveWaterSupply = req.querySet.push(haveWaterSupply) - 1; + + let needWaterSupply = allSchools.clone(); + needWaterSupply.where('escola_agregada.agua_inexistente = 1'); + req.queryIndex.needWaterSupply = req.querySet.push(needWaterSupply) - 1; + + // Água Potável + req.queryIndex.allFilteredWater = req.queryIndex.allSchools; + + let haveFilteredWater = allSchools.clone(); + haveFilteredWater.where('escola_agregada.agua_potavel = 1'); + req.queryIndex.haveFilteredWater = req.querySet.push(haveFilteredWater) - 1; + + let needFilteredWater = allSchools.clone(); + needFilteredWater.where('escola_agregada.agua_potavel = 0'); + req.queryIndex.needFilteredWater = req.querySet.push(needFilteredWater) - 1; + + // Coleta de esgoto + req.queryIndex.allSewage = req.queryIndex.allSchools; + + let haveSewage = allSchools.clone(); + haveSewage.where('escola_agregada.esgoto_rede_publica = 1 OR escola_agregada.esgoto_fossa_septica = 1'); + req.queryIndex.haveSewage = req.querySet.push(haveSewage) - 1; + + let needSewage = allSchools.clone(); + needSewage.where('escola_agregada.esgoto_rede_publica = 0 AND escola_agregada.esgoto_fossa_septica = 0'); + req.queryIndex.needSewage = req.querySet.push(needSewage) - 1; + + // Dependências adaptada para pessoas com deficiências + req.queryIndex.allAdaptedBuilding = req.queryIndex.allSchools; + + let haveAdaptedBuilding = allSchools.clone(); + haveAdaptedBuilding.where('escola_agregada.acessibilidade_inexistente = 0'); + req.queryIndex.haveAdaptedBuilding = req.querySet.push(haveAdaptedBuilding) - 1; + + let needAdaptedBuilding = allSchools.clone(); + needAdaptedBuilding.where('escola_agregada.acessibilidade_inexistente = 1'); + req.queryIndex.needAdaptedBuilding = req.querySet.push(needAdaptedBuilding) - 1; + + // Banheiros adaptados para pessoas com deficiências + req.queryIndex.allSpecialBathroom = req.queryIndex.allSchools; + + let haveSpecialBathroom = allSchools.clone(); + haveSpecialBathroom.where('escola_agregada.sanitario_pne = 1'); + req.queryIndex.haveSpecialBathroom = req.querySet.push(haveSpecialBathroom) - 1; + + let needSpecialBathroom = allSchools.clone(); + needSpecialBathroom.where('escola_agregada.sanitario_pne = 0'); + req.queryIndex.needSpecialBathroom = req.querySet.push(needSpecialBathroom) - 1; + + + next(); +}, multiQuery, (req, res, next) => { + + let schools_in_school_buildings = req.result[req.queryIndex.allSchools]; + let urban_schools_in_school_buildings = req.result[req.queryIndex.allUrbanSchools]; + let country_schools_in_school_buildings = req.result[req.queryIndex.allCountrySchools]; + let schools_not_in_school_buildings = req.result[req.queryIndex.allSchoolsNotSchoolBuilding]; + + // Faz o matching entre os resultados + let libraries = matchQueries(req.result[req.queryIndex.allLibraries], req.result[req.queryIndex.haveLibraries], req.result[req.queryIndex.needLibraries]); + let libraries_reading_room = matchQueries(req.result[req.queryIndex.allLibrariesReadingRoom], req.result[req.queryIndex.haveLibrariesReadingRoom], req.result[req.queryIndex.needLibrariesReadingRoom]); + let computer_lab = matchQueries(req.result[req.queryIndex.allInfLab], req.result[req.queryIndex.haveInfLab], req.result[req.queryIndex.needInfLab]); + let science_lab = matchQueries(req.result[req.queryIndex.allScienceLab], req.result[req.queryIndex.haveScienceLab], req.result[req.queryIndex.needScienceLab]); + let kids_park = matchQueries(req.result[req.queryIndex.allKidsPark], req.result[req.queryIndex.haveKidsPark], req.result[req.queryIndex.needKidsPark]); + // let nursery = matchQueries(req.result[req.queryIndex.allCribs], req.result[req.queryIndex.haveCribs], req.result[req.queryIndex.needCribs]); + let sports_court = matchQueries(req.result[req.queryIndex.allSportsCourt], req.result[req.queryIndex.haveSportsCourt], req.result[req.queryIndex.needSportsCourt]); + let sports_court_coverage = matchQueries(req.result[req.queryIndex.allSportsCourtCoverage], [], req.result[req.queryIndex.needSportsCourtCoverage], true); // have = [] + let courtyard = matchQueries(req.result[req.queryIndex.allCourtyard], req.result[req.queryIndex.haveCourtyard], req.result[req.queryIndex.needCourtyard]); + let courtyard_coverage = matchQueries(req.result[req.queryIndex.allCourtyardCoverage], [], req.result[req.queryIndex.needCourtyardCoverage], true); // have = [] + let director_room = matchQueries(req.result[req.queryIndex.allDirectorRoom], req.result[req.queryIndex.haveDirectorRoom], req.result[req.queryIndex.needDirectorRoom]); + let secretary = matchQueries(req.result[req.queryIndex.allSecretary], req.result[req.queryIndex.haveSecretary], req.result[req.queryIndex.needSecretary]); + let teacher_room = matchQueries(req.result[req.queryIndex.allTeacherRoom], req.result[req.queryIndex.haveTeacherRoom], req.result[req.queryIndex.needTeacherRoom]); + let kitchen = matchQueries(req.result[req.queryIndex.allKitchen], req.result[req.queryIndex.haveKitchen], req.result[req.queryIndex.needKitchen]); + let storeroom = matchQueries(req.result[req.queryIndex.allStoreroom], req.result[req.queryIndex.haveStoreroom], req.result[req.queryIndex.needStoreroom]); + let warehouse = matchQueries(req.result[req.queryIndex.allWarehouse], req.result[req.queryIndex.haveWarehouse], req.result[req.queryIndex.needWarehouse]); + let internet = matchQueries(req.result[req.queryIndex.allInternet], req.result[req.queryIndex.haveInternet], req.result[req.queryIndex.needInternet]); + let broadband_internet = matchQueries(req.result[req.queryIndex.allBroadbandInternet], req.result[req.queryIndex.haveBroadbandInternet], req.result[req.queryIndex.needBroadbandInternet]); + let inside_bathroom = matchQueries(req.result[req.queryIndex.allInsideBathroom], req.result[req.queryIndex.haveInsideBathroom], req.result[req.queryIndex.needInsideBathroom]); + let inside_kids_bathroom = matchQueries(req.result[req.queryIndex.allInsideKidsBathroom], req.result[req.queryIndex.haveInsideKidsBathroom], req.result[req.queryIndex.needInsideKidsBathroom]); + let eletrical_power = matchQueries(req.result[req.queryIndex.allEletricPower], req.result[req.queryIndex.haveEletricPower], req.result[req.queryIndex.needEletricPower]); + let water_supply = matchQueries(req.result[req.queryIndex.allWaterSupply], req.result[req.queryIndex.haveWaterSupply], req.result[req.queryIndex.needWaterSupply]); + let filtered_water = matchQueries(req.result[req.queryIndex.allFilteredWater], req.result[req.queryIndex.haveFilteredWater], req.result[req.queryIndex.needFilteredWater]); + let sewage = matchQueries(req.result[req.queryIndex.allSewage], req.result[req.queryIndex.haveSewage], req.result[req.queryIndex.needSewage]); + let adapted_building = matchQueries(req.result[req.queryIndex.allAdaptedBuilding], req.result[req.queryIndex.haveAdaptedBuilding], req.result[req.queryIndex.needAdaptedBuilding]); + let adapted_bathroom = matchQueries(req.result[req.queryIndex.allSpecialBathroom], req.result[req.queryIndex.haveSpecialBathroom], req.result[req.queryIndex.needSpecialBathroom]); + + req.result = [{ + schools_in_school_buildings, + urban_schools_in_school_buildings, + country_schools_in_school_buildings, + schools_not_in_school_buildings, + libraries, + libraries_reading_room, + computer_lab, + science_lab, + kids_park, + sports_court, + sports_court_coverage, + courtyard, + courtyard_coverage, + director_room, + secretary, + teacher_room, + kitchen, + storeroom, + warehouse, + internet, + broadband_internet, + inside_bathroom, + inside_kids_bathroom, + eletric_energy: eletrical_power, + water_supply, + filtered_water, + sewage_treatment: sewage, + adapted_building, + special_bathroom: adapted_bathroom + }]; + + next(); +}, id2str.multitransform(false), response('infrastructure')); + +module.exports = infrastructureApp; diff --git a/src/libs/routes_v2/schoolLocation.js b/src/libs/routes_v2/schoolLocation.js new file mode 100644 index 0000000000000000000000000000000000000000..5c0d98ff96fd30d232119a17e906eb14df5cd76e --- /dev/null +++ b/src/libs/routes_v2/schoolLocation.js @@ -0,0 +1,114 @@ +const express = require('express'); + +const schoolLocationApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const request = require(`request`); + +const config = require(`${libs}/config`); + +const passport = require('passport'); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'id', + table: 'localizacao_escolas', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id' + } +}).addValue({ + name: 'mesoregion', + table: 'municipio', + tableField: ['nome_mesorregiao', 'mesorregiao_id'], + resultField: ['mesoregion_name', 'mesoregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'mesorregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'localizacao_escolas' + } +}).addValue({ + name: 'microregion', + table: 'municipio', + tableField: ['nome_microrregiao', 'microrregiao_id'], + resultField: ['microregion_name', 'microregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'microrregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'localizacao_escolas' + } +}).addValueToField({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: '@' + } +}, 'dims'); + +schoolLocationApp.get('/', rqf.parse(), (req, res, next) => { + req.dims.city=true; + req.dims.mesoregion=true; + req.dims.microregion=true; + + req.sql.from('localizacao_escolas') + .field('localizacao_escolas.nome', 'name') + .field('localizacao_escolas.id', 'id') + .field('localizacao_escolas.latitude', 'latitude') + .field('localizacao_escolas.longitude', 'longitude') + .group('localizacao_escolas.nome') + .group('localizacao_escolas.id') + .group('localizacao_escolas.latitude') + .group('localizacao_escolas.longitude'); + next(); +}, rqf.build(), query, id2str.transform(), response('school_location')); + +module.exports = schoolLocationApp; diff --git a/src/libs/routes_v2/simcaqAggregatedEnrollment.js b/src/libs/routes_v2/simcaqAggregatedEnrollment.js new file mode 100644 index 0000000000000000000000000000000000000000..7562acfacb79c1df45b67eefec68682531125a0c --- /dev/null +++ b/src/libs/routes_v2/simcaqAggregatedEnrollment.js @@ -0,0 +1,211 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const simcaqAggregatedEnrollmentApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const reqBody = require(`${libs}/middlewares/reqBody`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +const id2str = require(`${libs}/middlewares/id2str`); + +simcaqAggregatedEnrollmentApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'year', + table: 'simcaq_matricula_agregada', + tableField: 'ano_censo', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'simcaq_matricula_agregada' + } +}, 'dims').addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'simcaq_matricula_agregada' + } +}, 'dims').addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'simcaq_matricula_agregada' + } +}, 'dims').addValue({ + name: 'school', + table: 'escola_agregada', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_id', + foreignTable: 'simcaq_matricula_agregada' + } +}, 'dims').addValue({ + name: 'locale', + table: 'simcaq_matricula_agregada', + tableField: 'localizacao_id', + resultField: 'locale_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'adm_dependency_id', + table: 'simcaq_matricula_agregada', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}).addValue({ + name: 'adm_dependency_detailed_id', + table: 'simcaq_matricula_agregada', + tableField: 'dependencia_adm_priv', + resultField: 'adm_dependency_detailed_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_priv' + } +}).addValue({ + name: 'diff_location_id', + table: 'simcaq_matricula_agregada', + tableField: 'localizacao_diferenciada_par', + resultField: 'diff_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_diferenciada_par' + } +}).addValue({ + name: 'school_building', + table: 'simcaq_matricula_agregada', + tableField: 'local_func_predio_escolar', + where: { + relation: '=', + type: 'boolean', + field: 'local_func_predio_escolar' + } +}).addValue({ + name: 'rural_location_id', + table: 'simcaq_matricula_agregada', + tableField: 'localidade_area_rural', + where: { + relation: '=', + type: 'integer', + field: 'localidade_area_rural' + } +}).addValue({ + name: 'school_year_id', + table: 'simcaq_matricula_agregada', + tableField: 'serie_ano_id', + resultField: 'school_year_id', + where: { + relation: '=', + type: 'integer', + field: 'serie_ano_id' + } +}).addValue({ + name: 'education_level_short_id', + table: 'simcaq_matricula_agregada', + tableField: 'etapa_resumida', + resultField: 'education_level_short_id', + where: { + relation: '=', + type: 'integer', + field: 'etapa_resumida' + } +}); + +simcaqAggregatedEnrollmentApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('simcaq_matricula_agregada') + .field('SUM(simcaq_matricula_agregada.num_matriculas)', 'num_enrollments') + .field('simcaq_matricula_agregada.ano_censo', 'year') + .group('simcaq_matricula_agregada.ano_censo'); + next(); +}, query, id2str.transform(), response('aggregatedEnrollment')); + +module.exports = simcaqAggregatedEnrollmentApp; diff --git a/src/libs/routes_v2/simcaqClassroomSize.js b/src/libs/routes_v2/simcaqClassroomSize.js new file mode 100644 index 0000000000000000000000000000000000000000..d70d084ec14d30dad60945547234ff23079d7bf8 --- /dev/null +++ b/src/libs/routes_v2/simcaqClassroomSize.js @@ -0,0 +1,147 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const simcaqClassroomSizeApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const reqBody = require(`${libs}/middlewares/reqBody`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +const id2str = require(`${libs}/middlewares/id2str`); + +simcaqClassroomSizeApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'simcaq_tamanho_das_turmas' + } +}, 'dims').addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'simcaq_tamanho_das_turmas' + } +}, 'dims').addValue({ + name: 'school', + table: 'escola_agregada', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_id', + foreignTable: 'simcaq_tamanho_das_turmas' + } +}, 'dims').addValue({ + name: 'education_level_short_id', + table: 'simcaq_tamanho_das_turmas', + tableField: 'etapa', + where: { + relation: '=', + type: 'integer', + field: 'etapa' + } +}).addValue({ + name: 'location', + table: 'simcaq_tamanho_das_turmas', + tableField: 'localizacao_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'adm_dependency_public_id', + table: 'simcaq_tamanho_das_turmas', + tableField: 'rede', + where: { + relation: '=', + type: 'integer', + field: 'rede' + } +}).addValue({ + name: 'year', + table: 'simcaq_tamanho_das_turmas', + tableField: 'ano_censo', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo' + } +}); + +simcaqClassroomSizeApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('simcaq_tamanho_das_turmas') + .field('AVG(simcaq_tamanho_das_turmas.num_matricula)', 'average_classroom_size') + .field('simcaq_tamanho_das_turmas.etapa', 'education_level_short_id') + .field('simcaq_tamanho_das_turmas.ano_censo', 'year') + .group('simcaq_tamanho_das_turmas.ano_censo') + .group('simcaq_tamanho_das_turmas.etapa'); + next(); +}, query, id2str.transform(), response('simcaqClassroomSize')); + +module.exports = simcaqClassroomSizeApp; diff --git a/src/libs/routes_v2/simcaqDivisionOfResponsibility.js b/src/libs/routes_v2/simcaqDivisionOfResponsibility.js new file mode 100644 index 0000000000000000000000000000000000000000..b9704b3b7d8590dbef02653a254840d0914e9af3 --- /dev/null +++ b/src/libs/routes_v2/simcaqDivisionOfResponsibility.js @@ -0,0 +1,140 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const simcaqDivisionOfResponsibilityApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const reqBody = require(`${libs}/middlewares/reqBody`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +const id2str = require(`${libs}/middlewares/id2str`); + +simcaqDivisionOfResponsibilityApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'year', + table: 'simcaq_divisao_de_responsabilidade', + tableField: 'ano_censo', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'simcaq_divisao_de_responsabilidade' + } +}, 'dims').addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'simcaq_divisao_de_responsabilidade' + } +}, 'dims').addValue({ + name: 'school', + table: 'escola_agregada', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_id', + foreignTable: 'simcaq_divisao_de_responsabilidade' + } +}, 'dims').addValue({ + name: 'education_level_short_id', + table: 'simcaq_divisao_de_responsabilidade', + tableField: 'etapa', + where: { + relation: '=', + type: 'integer', + field: 'etapa' + } +}).addValue({ + name: 'adm_dependency_public_id', + table: 'simcaq_divisao_de_responsabilidade', + tableField: 'rede', + where: { + relation: '=', + type: 'integer', + field: 'rede' + } +}); + +simcaqDivisionOfResponsibilityApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('simcaq_divisao_de_responsabilidade') + .field('simcaq_divisao_de_responsabilidade.ano_censo', 'year') + .field('SUM(simcaq_divisao_de_responsabilidade.total_matriculas)', 'enrollments') + .field('simcaq_divisao_de_responsabilidade.etapa', 'education_level_short_id') + .field('simcaq_divisao_de_responsabilidade.rede', 'adm_dependency_public_id') + .group('simcaq_divisao_de_responsabilidade.ano_censo') + .group('simcaq_divisao_de_responsabilidade.etapa') + .group('simcaq_divisao_de_responsabilidade.rede'); + next(); +}, query, id2str.transform(), response('divisionOfResponsibility')); + +module.exports = simcaqDivisionOfResponsibilityApp; diff --git a/src/libs/routes_v2/simcaqEnrollmentDiagnosis.js b/src/libs/routes_v2/simcaqEnrollmentDiagnosis.js new file mode 100644 index 0000000000000000000000000000000000000000..1d6c70828d546668c6c70b805ac44bf62b618d29 --- /dev/null +++ b/src/libs/routes_v2/simcaqEnrollmentDiagnosis.js @@ -0,0 +1,156 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const simcaqEnrollmentDiagnosisApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const reqBody = require(`${libs}/middlewares/reqBody`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +const id2str = require(`${libs}/middlewares/id2str`); + +simcaqEnrollmentDiagnosisApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'year', + table: 'simcaq_diagnostico_de_matricula', + tableField: 'ano_censo', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'simcaq_diagnostico_de_matricula' + } +}, 'dims').addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'simcaq_diagnostico_de_matricula' + } +}, 'dims').addValue({ + name: 'school', + table: 'escola_agregada', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_id', + foreignTable: 'simcaq_diagnostico_de_matricula' + } +}, 'dims').addValue({ + name: 'education_level_short_id', + table: 'simcaq_diagnostico_de_matricula', + tableField: 'etapa', + where: { + relation: '=', + type: 'integer', + field: 'etapa' + } +}).addValue({ + name: 'location', + table: 'simcaq_diagnostico_de_matricula', + tableField: 'localizacao_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'adm_dependency', + table: 'simcaq_diagnostico_de_matricula', + tableField: 'dependencia_adm_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}); + +simcaqEnrollmentDiagnosisApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('simcaq_diagnostico_de_matricula') + .field('simcaq_diagnostico_de_matricula.etapa', 'education_level_short_id') + .field('SUM(simcaq_diagnostico_de_matricula.total)', 'total') + .field('SUM(simcaq_diagnostico_de_matricula.matriculas_federal)', 'federal_enrollments') + .field('SUM(simcaq_diagnostico_de_matricula.matriculas_estadual)', 'state_enrollments') + .field('SUM(simcaq_diagnostico_de_matricula.matriculas_municipal)', 'city_enrollments') + .field('SUM(simcaq_diagnostico_de_matricula.matriculas_priv_conv_sem_fin)', 'private_affiliated_non_profit_enrollments') + .field('SUM(simcaq_diagnostico_de_matricula.matriculas_priv_conv_com_fin)', 'private_affiliated_for_profit_enrollments') + .field('SUM(simcaq_diagnostico_de_matricula.matriculas_priv_nao_conv_sem_fin)', 'private_not_affiliated_non_profit_enrollments') + .field('SUM(simcaq_diagnostico_de_matricula.matriculas_priv_nao_conv_com_fin)', 'private_not_affiliated_for_profit_enrollments') + .field('SUM(simcaq_diagnostico_de_matricula.matriculas_urbana)', 'urban_enrollments') + .field('SUM(simcaq_diagnostico_de_matricula.matriculas_rural)', 'rural_enrollments') + .field('ano_censo', 'year') + .group('ano_censo') + .group('simcaq_diagnostico_de_matricula.etapa'); + next(); +}, query, id2str.transform(), response('enrollmentDiagnosis')); + +module.exports = simcaqEnrollmentDiagnosisApp; diff --git a/src/libs/routes_v2/simcaqEnrollmentProjection.js b/src/libs/routes_v2/simcaqEnrollmentProjection.js new file mode 100644 index 0000000000000000000000000000000000000000..cb472b4eafaa8780fcf8f31fff74beb73a0cbf44 --- /dev/null +++ b/src/libs/routes_v2/simcaqEnrollmentProjection.js @@ -0,0 +1,143 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const simcaqEnrollmentProjectionApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const reqBody = require(`${libs}/middlewares/reqBody`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +const id2str = require(`${libs}/middlewares/id2str`); + +simcaqEnrollmentProjectionApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'year', + table: 'simcaq_projecao_de_matricula', + tableField: 'ano_censo', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'simcaq_projecao_de_matricula' + } +}, 'dims').addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'simcaq_projecao_de_matricula' + } +}, 'dims').addValue({ + name: 'school', + table: 'escola_agregada', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_id', + foreignTable: 'simcaq_projecao_de_matricula' + } +}, 'dims').addValue({ + name: 'education_level_short_id', + table: 'simcaq_projecao_de_matricula', + tableField: 'etapa', + where: { + relation: '=', + type: 'integer', + field: 'etapa' + } +}).addValue({ + name: 'adm_dependency_public_id', + table: 'simcaq_projecao_de_matricula', + tableField: 'rede', + where: { + relation: '=', + type: 'integer', + field: 'rede' + } +}); + +simcaqEnrollmentProjectionApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('simcaq_projecao_de_matricula') + .field('simcaq_projecao_de_matricula.ano_censo', 'year') + .field('simcaq_projecao_de_matricula.etapa', 'education_level_short_id') + .field('simcaq_projecao_de_matricula.rede', 'adm_dependency_public_id') + .field('SUM(simcaq_projecao_de_matricula.total_matriculas)', 'total_enrollments') + .field('SUM(simcaq_projecao_de_matricula.matriculas_diurno)', 'daytime_enrollments') + .field('SUM(simcaq_projecao_de_matricula.matriculas_noturno)', 'nighttime_enrollments') + .field('SUM(simcaq_projecao_de_matricula.total_tempo_integral)', 'fulltime_enrollments') + .group('simcaq_projecao_de_matricula.ano_censo') + .group('simcaq_projecao_de_matricula.etapa') + .group('simcaq_projecao_de_matricula.rede'); + next(); +}, query, id2str.transform(), response('enrollmentProjection')); + +module.exports = simcaqEnrollmentProjectionApp; diff --git a/src/libs/routes_v2/simcaqFirstReport.js b/src/libs/routes_v2/simcaqFirstReport.js new file mode 100644 index 0000000000000000000000000000000000000000..6c037cf477179b1bc9602cfb791333967aeb20c3 --- /dev/null +++ b/src/libs/routes_v2/simcaqFirstReport.js @@ -0,0 +1,161 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const simcaqFirstReportApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const reqBody = require(`${libs}/middlewares/reqBody`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +const id2str = require(`${libs}/middlewares/id2str`); + +simcaqFirstReportApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'year', + table: 'simcaq_relatorio_1', + tableField: 'ano_censo', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'adm_dependency', + table: 'simcaq_relatorio_1', + tableField: 'dependencia_adm_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'simcaq_relatorio_1' + } +}, 'dims').addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'simcaq_relatorio_1' + } +}, 'dims').addValue({ + name: 'school', + table: 'escola_agregada', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_id', + foreignTable: 'simcaq_relatorio_1' + } +}, 'dims').addValue({ + name: 'location', + table: 'simcaq_relatorio_1', + tableField: 'localizacao_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'education_level_short_id', + table: 'simcaq_relatorio_1', + tableField: 'etapa', + where: { + relation: '=', + type: 'integer', + field: 'etapa' + } +}).addValue({ + name: 'shift_id', + table: 'simcaq_relatorio_1', + tableField: 'turno', + where: { + relation: '=', + type: 'integer', + field: 'turno' + } +}); + +simcaqFirstReportApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('simcaq_relatorio_1') + .field('simcaq_relatorio_1.etapa', 'education_level_short_id') + .field('simcaq_relatorio_1.turno', 'shift_id') + .field('simcaq_relatorio_1.localizacao_id', 'location_id') + .field('SUM(simcaq_relatorio_1.num_matriculas)', 'num_enrollments') + .field('SUM(simcaq_relatorio_1.num_escolas)', 'num_schools') + .field('ano_censo', 'year') + .group('ano_censo') + .group('simcaq_relatorio_1.etapa') + .group('simcaq_relatorio_1.turno') + .group('simcaq_relatorio_1.localizacao_id'); + next(); +}, query, id2str.transform(), response('simcaqFirstReport')); + +module.exports = simcaqFirstReportApp; diff --git a/src/libs/routes_v2/simcaqNewClasses.js b/src/libs/routes_v2/simcaqNewClasses.js new file mode 100644 index 0000000000000000000000000000000000000000..4922270e8b72542ba43ba50f7aff4c347daa1e7a --- /dev/null +++ b/src/libs/routes_v2/simcaqNewClasses.js @@ -0,0 +1,131 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const simcaqNewClassesApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const reqBody = require(`${libs}/middlewares/reqBody`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +const id2str = require(`${libs}/middlewares/id2str`); + +simcaqNewClassesApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'year', + table: 'simcaq_novas_salas', + tableField: 'ano_censo', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'simcaq_novas_salas' + } +}, 'dims').addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'simcaq_novas_salas' + } +}, 'dims').addValue({ + name: 'school', + table: 'escola_agregada', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_id', + foreignTable: 'simcaq_novas_salas' + } +}, 'dims').addValue({ + name: 'adm_dependency_public_id', + table: 'simcaq_novas_salas', + tableField: 'rede', + where: { + relation: '=', + type: 'integer', + field: 'rede' + } +}); + +simcaqNewClassesApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('simcaq_novas_salas') + .field('SUM(num_salas_urbana)', 'number_of_urban_classes') + .field('SUM(num_salas_rural)', 'number_of_rural_classes') + .field('SUM(num_salas_total)', 'total_number_of_classes') + .field('simcaq_novas_salas.rede', 'adm_dependency_public_id') + .field('simcaq_novas_salas.ano_censo', 'year') + .group('simcaq_novas_salas.rede') + .group('simcaq_novas_salas.ano_censo'); + next(); +}, query, id2str.transform(), response('simcaqNewClasses')); + +module.exports = simcaqNewClassesApp; diff --git a/src/libs/routes_v2/simcaqNumberOfEmployees.js b/src/libs/routes_v2/simcaqNumberOfEmployees.js new file mode 100644 index 0000000000000000000000000000000000000000..3496aa09249f5a6bcdfc51b824febacacf70e667 --- /dev/null +++ b/src/libs/routes_v2/simcaqNumberOfEmployees.js @@ -0,0 +1,129 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const simcaqNumberOfEmployeesApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const reqBody = require(`${libs}/middlewares/reqBody`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +const id2str = require(`${libs}/middlewares/id2str`); + +simcaqNumberOfEmployeesApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'year', + table: 'simcaq_numero_de_funcionarios', + tableField: 'ano_censo', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'simcaq_numero_de_funcionarios' + } +}, 'dims').addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'simcaq_numero_de_funcionarios' + } +}, 'dims').addValue({ + name: 'school', + table: 'escola_agregada', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_id', + foreignTable: 'simcaq_numero_de_funcionarios' + } +}, 'dims').addValue({ + name: 'adm_dependency_public_id', + table: 'simcaq_numero_de_funcionarios', + tableField: 'rede', + where: { + relation: '=', + type: 'integer', + field: 'rede' + } +}); + +simcaqNumberOfEmployeesApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('simcaq_numero_de_funcionarios') + .field('SUM(num_funcionarios)', 'number_of_employees') + .field('simcaq_numero_de_funcionarios.rede', 'adm_dependency_public_id') + .field('simcaq_numero_de_funcionarios.ano_censo', 'year') + .group('simcaq_numero_de_funcionarios.rede') + .group('simcaq_numero_de_funcionarios.ano_censo'); + next(); +}, query, id2str.transform(), response('simcaqNumberOfEmployees')); + +module.exports = simcaqNumberOfEmployeesApp; diff --git a/src/libs/routes_v2/simcaqNumberOfTeachers.js b/src/libs/routes_v2/simcaqNumberOfTeachers.js new file mode 100644 index 0000000000000000000000000000000000000000..00f6d9422317d829973f5581923b79b06d24420b --- /dev/null +++ b/src/libs/routes_v2/simcaqNumberOfTeachers.js @@ -0,0 +1,103 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const simcaqNumberOfTeachersApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const reqBody = require(`${libs}/middlewares/reqBody`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +const id2str = require(`${libs}/middlewares/id2str`); + +simcaqNumberOfTeachersApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'year', + table: 'simcaq_num_professores', + tableField: 'ano_censo', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'local_id', + table: 'simcaq_num_professores', + tableField: 'local_id', + where: { + relation: '=', + type: 'integer', + field: 'local_id' + } +}).addValue({ + name: 'level_id', + table: 'simcaq_num_professores', + tableField: 'nivel', + where: { + relation: '=', + type: 'integer', + field: 'nivel' + } +}).addValue({ + name: 'type_id', + table: 'simcaq_num_professores', + tableField: 'tipo', + where: { + relation: '=', + type: 'integer', + field: 'tipo' + } +}); + +simcaqNumberOfTeachersApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('simcaq_num_professores') + .field('total', 'number_of_teachers') + .field('simcaq_num_professores.ano_censo', 'year') + .field('simcaq_num_professores.nivel', 'level_id') + .field('simcaq_num_professores.tipo', 'type_id') + .field('simcaq_num_professores.local_id', 'local_id'); + next(); +}, query, id2str.transform(), response('simcaqNumberOfTeachers')); + +module.exports = simcaqNumberOfTeachersApp; diff --git a/src/libs/routes_v2/simcaqResult.js b/src/libs/routes_v2/simcaqResult.js new file mode 100644 index 0000000000000000000000000000000000000000..3ba50ad0948b0bbbc42da746efdb5b47f183e14f --- /dev/null +++ b/src/libs/routes_v2/simcaqResult.js @@ -0,0 +1,140 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const simcaqResultApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const reqBody = require(`${libs}/middlewares/reqBody`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +const id2str = require(`${libs}/middlewares/id2str`); + +simcaqResultApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'simcaq_resultado' + } +}, 'dims').addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'simcaq_resultado' + } +}, 'dims').addValue({ + name: 'school', + table: 'escola_agregada', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_id', + foreignTable: 'simcaq_resultado' + } +}, 'dims').addValue({ + name: 'adm_dependency_public_id', + table: 'simcaq_resultado', + tableField: 'rede', + where: { + relation: '=', + type: 'integer', + field: 'rede' + } +}).addValue({ + name: 'year', + table: 'simcaq_resultado', + tableField: 'ano_censo', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'supply_dimension_id', + table: 'simcaq_resultado', + tableField: 'dimensao_oferta', + where: { + relation: '=', + type: 'integer', + field: 'dimensao_oferta' + } +}); + +simcaqResultApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('simcaq_resultado') + .field('SUM(simcaq_resultado.atual)', 'current') + .field('simcaq_resultado.rede', 'adm_dependency_public_id') + .field('simcaq_resultado.ano_censo', 'year') + .field('simcaq_resultado.dimensao_oferta', 'supply_dimension_id') + .group('simcaq_resultado.ano_censo') + .group('simcaq_resultado.rede') + .group('simcaq_resultado.dimensao_oferta'); + next(); +}, query, id2str.transform(), response('simcaqResult')); + +module.exports = simcaqResultApp; diff --git a/src/libs/routes_v2/simcaqSchoolInfrastructure.js b/src/libs/routes_v2/simcaqSchoolInfrastructure.js new file mode 100644 index 0000000000000000000000000000000000000000..f10022cb63c511bb5857b9a188b2dd1bcc026420 --- /dev/null +++ b/src/libs/routes_v2/simcaqSchoolInfrastructure.js @@ -0,0 +1,87 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const simcaqSchoolInfrastructureApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const reqBody = require(`${libs}/middlewares/reqBody`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +const id2str = require(`${libs}/middlewares/id2str`); + +simcaqSchoolInfrastructureApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'year', + table: 'simcaq_school_infrastructure', + tableField: 'ano_censo', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'scholar_dependency', + table: 'simcaq_school_infrastructure', + tableField: 'scholar_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'scholar_dependency_id' + } +}); + +simcaqSchoolInfrastructureApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('simcaq_school_infrastructure') + .field('simcaq_school_infrastructure.ano_censo', 'year') + .field('simcaq_school_infrastructure.scholar_dependency_id', 'scholar_dependency_id') + .field('SUM(simcaq_school_infrastructure.total_schools)', 'total_schools') + .field('SUM(total_no_dependency)', 'total_schools_without_dependency') + .field('SUM(total_with_dependency)', 'total_schools_with_dependency') + .group('simcaq_school_infrastructure.ano_censo') + .group('simcaq_school_infrastructure.scholar_dependency_id'); + next(); +}, query, id2str.transform(), response('simcaqSchoolInfrastructure')); + +module.exports = simcaqSchoolInfrastructureApp; diff --git a/src/libs/routes_v2/simcaqSecondReport.js b/src/libs/routes_v2/simcaqSecondReport.js new file mode 100644 index 0000000000000000000000000000000000000000..421bd6f2142aaefc14fe2aaeeddd9768863743ee --- /dev/null +++ b/src/libs/routes_v2/simcaqSecondReport.js @@ -0,0 +1,134 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const simcaqSecondReportApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const reqBody = require(`${libs}/middlewares/reqBody`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +const id2str = require(`${libs}/middlewares/id2str`); + +simcaqSecondReportApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'year', + table: 'simcaq_relatorio_2', + tableField: 'ano_censo', + where : { + relation: '=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'simcaq_relatorio_2' + } +}, 'dims').addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'simcaq_relatorio_2' + } +}, 'dims').addValue({ + name: 'school', + table: 'escola_agregada', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_id', + foreignTable: 'simcaq_relatorio_2' + } +}, 'dims').addValue({ + name: 'adm_dependency_detailed_id', + table: 'simcaq_relatorio_2', + tableField: 'dependencia_adm_priv', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_priv' + } +}); + +simcaqSecondReportApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('simcaq_relatorio_2') + .field('sum(num_matriculas_total)' ,'num_enrollments_total') + .field('sum(num_matriculas_rural)' ,'num_enrollments_rural') + .field('sum(num_matriculas_urbana)' ,'num_enrollments_urban') + .field('sum(num_escolas_total)' ,'num_schools_total') + .field('sum(num_escolas_rural)' ,'num_schools_rural') + .field('sum(num_escolas_urbana)' ,'num_schools_urban') + .field('dependencia_adm_priv', 'adm_dependency_detailed_id') + .field('ano_censo', 'year') + .group('ano_censo') + .group('dependencia_adm_priv'); + next(); +}, query, id2str.transform(), response('simcaqSecondReport')); + +module.exports = simcaqSecondReportApp; diff --git a/src/libs/routes_v2/simcaqTeacherCityPlan.js b/src/libs/routes_v2/simcaqTeacherCityPlan.js new file mode 100644 index 0000000000000000000000000000000000000000..72c199132d108fc18b11882bcbf0f0d24bdd69fa --- /dev/null +++ b/src/libs/routes_v2/simcaqTeacherCityPlan.js @@ -0,0 +1,139 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const simcaqTeacherCityPlanApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const reqBody = require(`${libs}/middlewares/reqBody`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +const id2str = require(`${libs}/middlewares/id2str`); + +simcaqTeacherCityPlanApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'year', + table: 'simcaq_docente_municipio_plano', + tableField: 'ano_censo', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_municipio_id', + foreignTable: 'simcaq_docente_municipio_plano' + } +}, 'dims').addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_estado_id', + foreignTable: 'simcaq_docente_municipio_plano' + } +}, 'dims').addValue({ + name: 'school', + table: 'escola_agregada', + tableField: ['nome', 'id'], + resultField: ['school_name', 'school_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_id', + foreignTable: 'simcaq_docente_municipio_plano' + } +}, 'dims').addValue({ + name: 'country', + table: 'simcaq_docente_municipio_plano', + tableField: ['escola_pais_nome', 'escola_pais_id'], + resultField: ['country_name', 'country_id'], + where: { + relation: '=', + type: 'integer', + field: 'escola_pais_id' + } +}).addValue({ + name: 'adm_dependency_id', + table: 'simcaq_docente_municipio_plano', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}); + +simcaqTeacherCityPlanApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('simcaq_docente_municipio_plano') + .field('simcaq_docente_municipio_plano.num_docentes', 'num_teachers') + .field('simcaq_docente_municipio_plano.dependencia_adm_id', 'adm_dependency_id') + .field('simcaq_docente_municipio_plano.ano_censo', 'year'); + next(); +}, query, id2str.transform(), response('simcaqTeacherCityPlan')); + +module.exports = simcaqTeacherCityPlanApp; diff --git a/src/libs/routes_v2/simcaqWorkload.js b/src/libs/routes_v2/simcaqWorkload.js new file mode 100644 index 0000000000000000000000000000000000000000..b4584224f16b94b2490885493293f41ebb5b8f30 --- /dev/null +++ b/src/libs/routes_v2/simcaqWorkload.js @@ -0,0 +1,151 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const simcaqWorkloadApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const reqBody = require(`${libs}/middlewares/reqBody`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +const id2str = require(`${libs}/middlewares/id2str`); + +simcaqWorkloadApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'year', + table: 'simcaq_carga_horaria_de_ensino', + tableField: 'ano_censo', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'simcaq_carga_horaria_de_ensino' + } +}, 'dims').addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'simcaq_carga_horaria_de_ensino' + } +}, 'dims').addValue({ + name: 'school', + table: 'escola_agregada', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_id', + foreignTable: 'simcaq_carga_horaria_de_ensino' + } +}, 'dims').addValue({ + name: 'adm_dependency_public_id', + table: 'simcaq_carga_horaria_de_ensino', + tableField: 'rede', + where: { + relation: '=', + type: 'integer', + field: 'rede' + } +}).addValue({ + name: 'education_level_short_id', + table: 'simcaq_carga_horaria_de_ensino', + tableField: 'etapa', + where: { + relation: '=', + type: 'integer', + field: 'etapa' + } +}).addValue({ + name: 'shift_id', + table: 'simcaq_carga_horaria_de_ensino', + tableField: 'turno', + where: { + relation: '=', + type: 'integer', + field: 'turno' + } +}); + +simcaqWorkloadApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('simcaq_carga_horaria_de_ensino') + .field('AVG(duracao_turma_horas)', 'average_workload') + .field('simcaq_carga_horaria_de_ensino.etapa', 'education_level_short_id') + .field('simcaq_carga_horaria_de_ensino.turno', 'shift_id') + .field('simcaq_carga_horaria_de_ensino.rede', 'adm_dependency_public_id') + .field('simcaq_carga_horaria_de_ensino.ano_censo', 'year') + .group('simcaq_carga_horaria_de_ensino.etapa') + .group('simcaq_carga_horaria_de_ensino.turno') + .group('simcaq_carga_horaria_de_ensino.rede') + .group('simcaq_carga_horaria_de_ensino.ano_censo'); + next(); +}, query, id2str.transform(), response('simcaqWorkload')); + +module.exports = simcaqWorkloadApp; diff --git a/src/libs/routes/simulation.js b/src/libs/routes_v2/simulation.js similarity index 100% rename from src/libs/routes/simulation.js rename to src/libs/routes_v2/simulation.js diff --git a/src/libs/routes_v2/siope.js b/src/libs/routes_v2/siope.js new file mode 100644 index 0000000000000000000000000000000000000000..1ef9f1010c69179db623a60c74623c85be9a9215 --- /dev/null +++ b/src/libs/routes_v2/siope.js @@ -0,0 +1,186 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const siopeApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const multiQuery = require(`${libs}/middlewares/multiQuery`); + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +siopeApp.use(cache('15 day')); + +siopeApp.get('/years', (req, res, next) => { + req.sql.from('siope_mun') + .field('DISTINCT siope_mun.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + req.oldResult = req.result; + + req.sql = squel.select(); + + req.sql.from('siope_uf') + .field('DISTINCT siope_uf.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + let result = Object.assign(req.oldResult, req.result); + req.result = result; + next(); +}, response('years')); + +rqf.addField({ + name: 'filter', + field: true, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'siope_mun' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'siope_mun' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['id','nome','sigla'], + resultField: ['state_id','state_name','state_abbreviation'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: '@' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: '@' + } +}).addValue({ + name: 'min_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}); + + + +siopeApp.get('/', rqf.parse(), (req, res, next) => { + req.querySet = []; + req.queryIndex = {}; + + let siopeUf = req.sql.clone(); + siopeUf.from('siope_uf') + .field('siope_uf.ano_censo', 'year') + .field('siope_uf.estado_id', 'state_id') + .field('siope_uf.fundeb', 'fundeb') + .field('siope_uf.total_impostos', 'impostos') + .field('siope_uf.total_mde', 'MDE') + .group('siope_uf.ano_censo') + .group('siope_uf.estado_id') + .group('siope_uf.fundeb') + .group('siope_uf.total_impostos') + .group('siope_uf.total_mde') + .order('siope_uf.ano_censo'); + req.queryIndex.siopeUf = req.querySet.push(siopeUf) - 1; + + let siopeMun = req.sql.clone(); + siopeMun.from('siope_mun') + .field('siope_mun.ano_censo', 'year') + .field('siope_mun.estado_id', 'state_id') + .field('siope_mun.municipio_id', 'city_id') + .field('siope_mun.fundeb', 'fundeb') + .field('siope_mun.total_impostos', 'impostos') + .field('siope_mun.total_mde', 'MDE') + .group('siope_mun.ano_censo') + .group('siope_mun.estado_id') + .group('siope_mun.municipio_id') + .group('siope_mun.fundeb') + .group('siope_mun.total_impostos') + .group('siope_mun.total_mde') + .order('siope_mun.ano_censo'); + req.queryIndex.siopeMun = req.querySet.push(siopeMun) - 1; + + next(); +}, rqf.multibuild(), multiQuery, (req, res, next) => { + + let result = [] + + req.result[req.queryIndex.siopeUf].forEach((item) => { + result.push(item) + }); + req.result[req.queryIndex.siopeMun].forEach((item) => { + result.push(item) + }); + + req.result = result; + next(); + +}, response('siope')); + +module.exports = siopeApp; diff --git a/src/libs/routes_v2/spatial.js b/src/libs/routes_v2/spatial.js new file mode 100644 index 0000000000000000000000000000000000000000..d4f48fe8eda00fe562b60e83bf69416c81694d33 --- /dev/null +++ b/src/libs/routes_v2/spatial.js @@ -0,0 +1,373 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const log = require(`${libs}/log`)(module); + +const query = require(`${libs}/middlewares/query`).query; + +const sqlQuery = require(`${libs}/db/query_exec`); + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const spatialApp = express(); + +let rqf = new ReqQueryFields(); + +function processResultSet(querySet, querySetLabels = ["result"], singleResult = false) { + const resultMap = new Map(); + let resultIdx = 0; + // loop relies on the fact that Promise.all maintains the order of the original iterable + for(let result of querySet) { + const resultLbl = querySetLabels[resultIdx]; + resultMap[resultLbl] = []; + if (singleResult) { + resultMap[resultLbl] = result[0]; + } else { + for(let row of result) { + resultMap[resultLbl].push(row); + } + } + resultIdx++; + } + return resultMap; +} + +function dbExecAll(querySet = []) { + // Issue all queries concurrently to the database, for every query object in the iterable + // NOTE: Array.map() returns a copy of the original array with each object 'mapped'. + return querySet.map((qry) => { return sqlQuery(qry.toString()); }); +} + +rqf.addField({ + name: 'filter', + field: true, + where: true +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'estado_id' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id' + } +}).addValue({ + name: 'school', + table: 'escola', + tableField: 'nome_escola', + resultField: 'school_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + } +}); + +spatialApp.get('/sociodemographic', rqf.parse(), rqf.build(), (req, res, next) => { + const populationYearQry = squel.select() + .field('MAX(ibge_populacao.ano_censo)') + .from('ibge_populacao'); + + const populationQry = req.sql.clone() + .field('\'Brasil\'', 'name') + .field('SUM(populacao)', 'population') + .field('ibge_populacao.ano_censo', 'census_year') + .from('ibge_populacao') + .where(`ibge_populacao.ano_censo IN (${populationYearQry.toString()})`) + .group('ibge_populacao.ano_censo'); + + const pibYearQry = squel.select() + .field('MAX(ibge_pib.ano_censo)') + .from('ibge_pib'); + + const pibQry = req.sql.clone() + .field('\'Brasil\'', 'name') + .field('AVG(ibge_pib.pib_per_capita)', 'gdp_per_capita') + .field('ibge_pib.ano_censo', 'census_year') + .from('ibge_pib') + .where(`ibge_pib.ano_censo IN (${pibYearQry.toString()})`) + .group('ibge_pib.ano_censo'); + + const idhYearQry = squel.select() + .field('MAX(adh_idh.ano_censo)') + .from('adh_idh'); + + const idhQry = req.sql.clone() + .field('\'Brasil\'', 'name') + .field('AVG(idhm)', 'idhm') + .field('adh_idh.ano_censo', 'census_year') + .from('adh_idh') + .where(`adh_idh.ano_censo IN (${idhYearQry.toString()})`) + .group('adh_idh.ano_censo'); + + const analfabYearQry = squel.select() + .field('MAX(adh_analfabetismo.ano_censo)') + .from('adh_analfabetismo'); + + const analfabQry = req.sql.clone() + .field('\'Brasil\'', 'name') + .field('AVG(t_analf15m)', 'analfabetism') + .field('adh_analfabetismo.ano_censo', 'census_year') + .from('adh_analfabetismo') + .where(`adh_analfabetismo.ano_censo IN (${analfabYearQry.toString()})`) + .group('adh_analfabetismo.ano_censo'); + + const giniYearQry = squel.select() + .field('MAX(adh_gini.ano_censo)') + .from('adh_gini'); + + const giniQry = req.sql.clone() + .field('\'Brasil\'', 'name') + .field('AVG(gini)', 'gini') + .field('adh_gini.ano_censo', 'census_year') + .from('adh_gini') + .where(`adh_gini.ano_censo IN (${giniYearQry.toString()})`) + .group('adh_gini.ano_censo'); + + // map query objects to their respective response labels + const queryLabels = [ "population", "gdp", "idh", "analfab", "gini" ]; + const querySet = [ populationQry, pibQry, idhQry, analfabQry, giniQry ]; + // wait until all queries finish or one of them fail + Promise.all(dbExecAll(querySet)).then((queryResults) => { + req.result = processResultSet(queryResults, queryLabels, true); + next(); + }).catch((error) => { + log.error(`[SQL query error] ${error}`); + next(error); + }); +}, response('spatial')); + +spatialApp.get('/educational', rqf.parse(), rqf.build(), (req, res, next) => { + const censusYearQry = squel.select() + .field('MAX(escola.ano_censo)', 'ano_censo') + .from('escola') + .toString(); + + const totalSchoolsQry = req.sql.clone() + .field('\'Brasil\'', 'name') + .field('\'Total\'', 'location_name') + .field('COUNT(DISTINCT(escola.id))', 'total') + .field('escola.ano_censo', 'census_year') + .from('turma') + .from('escola') + .where('escola.ano_censo=turma.ano_censo AND escola.id=turma.escola_id') + .where(`escola.ano_censo IN (${censusYearQry})`) + .where('turma.tipo_turma_id = 0') + .group('escola.ano_censo'); + + const schoolsPerLocationQry = req.sql.clone() + .field('\'Brasil\'', 'name') + .field('COUNT(DISTINCT(escola.id))', 'total') + .field('escola.ano_censo', 'census_year') + .field('localizacao.descricao', 'location_name') + .from('localizacao') + .from('turma') + .from('escola') + .where('escola.localizacao_id=localizacao.id') + .where('escola.ano_censo=turma.ano_censo AND escola.id=turma.escola_id') + .where(`escola.ano_censo IN (${censusYearQry})`) + .where('turma.tipo_turma_id = 0') + .group('escola.localizacao_id') + .group('escola.ano_censo') + .group('localizacao.descricao') + .order('localizacao.descricao'); + + const schoolsPerAdmDependencyQry = req.sql.clone() + .field('\'Brasil\'', 'name') + .field('COUNT(DISTINCT(escola.id))', 'total') + .field('escola.ano_censo', 'census_year') + .field('dependencia_adm.nome', 'adm_dependency_name') + .from('dependencia_adm') + .from('escola') + .where('escola.dependencia_adm_id=dependencia_adm.id') + .where(`escola.ano_censo IN (${censusYearQry})`) + .group('escola.ano_censo') + .group('dependencia_adm.nome') + .order('escola.ano_censo') + .order('dependencia_adm.nome'); + + const enrollmentsQry = req.sql.clone() + .field('\'Brasil\'', 'name') + .field('COALESCE(SUM(uc201.matriculas), 0)', 'total') + .field('uc201.ano_censo', 'census_year') + .from('uc201') + .group('uc201.ano_censo'); + + const enrollmentsPerAdmDepQry = req.sql.clone() + .field('\'Brasil\'', 'name') + .field('COALESCE(SUM(uc201.matriculas), 0)', 'total') + .field('uc201.ano_censo', 'census_year') + .field('dependencia_adm.nome', 'adm_dependency_name') + .from('dependencia_adm') + .from('uc201') + .where('uc201.dependencia_adm_id=dependencia_adm.id') + .group('dependencia_adm.nome') + .group('uc201.ano_censo'); + + const enrollmentsPerSchoolLevelQry = req.sql.clone() + .field('\'Brasil\'', 'name') + .field('COALESCE(SUM(uc201.matriculas), 0)', 'total') + .field('uc201.ano_censo', 'census_year') + .field('etapa_ensino.desc_etapa', 'school_level_name') + .field('dependencia_adm.nome', 'adm_dependency_name') + .from('etapa_ensino') + .from('dependencia_adm') + .from('uc201') + .where('uc201.etapas_mod_ensino_segmento_id=etapa_ensino.id') + .where('uc201.dependencia_adm_id=dependencia_adm.id') + .group('etapa_ensino.desc_etapa') + .group('dependencia_adm.nome') + .group('uc201.ano_censo'); + + const enrollmentsPerLocationQry = req.sql.clone() + .field('\'Brasil\'', 'name') + .field('COALESCE(SUM(uc201.matriculas), 0)', 'total') + .field('uc201.ano_censo', 'census_year') + .field('localizacao.descricao', 'location_name') + .from('localizacao') + .from('uc201') + .where('uc201.localizacao=localizacao.id') + .group('localizacao.descricao') + .group('uc201.ano_censo'); + + const queryLabels = [ "school", "school_per_location", "school_per_adm_dependency", "enrollment", "enrollment_per_adm_dep", + "enrollment_per_school_level", "enrollment_per_location" ]; + const querySet = [ totalSchoolsQry, schoolsPerLocationQry, schoolsPerAdmDependencyQry, enrollmentsQry, + enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry, enrollmentsPerLocationQry]; + // wait until all queries finish or one of them fail + Promise.all(dbExecAll(querySet)).then((queryResults) => { + req.result = processResultSet(queryResults, queryLabels); + next(); + }).catch((error) => { + log.error(`[SQL query error] ${error}`); + next(error); + }); +}, response('spatial')); + +spatialApp.get('/educational/school_level', rqf.parse(), rqf.build(), (req, res, next) => { + const enrollmentsPerSchoolLevelYearQry = squel.select() + .field('MAX(matricula.ano_censo)', 'census_year') + .from('matricula'); + + const enrollmentsPerSchoolLevelQry = req.sql.clone() + .field('COALESCE(COUNT(matricula.id), 0)', 'total') + .field('matricula.ano_censo', 'census_year') + .field('matricula.serie_ano_id', 'school_year') + .field('etapa_ensino.desc_etapa', 'school_level') + .from('etapa_ensino') + .from('matricula') + .where(`matricula.ano_censo IN (${enrollmentsPerSchoolLevelYearQry.toString()})`) + .where('matricula.etapa_ensino_id = etapa_ensino.id') + .where('matricula.tipo <= 3') + .group('etapa_ensino.desc_etapa') + .group('etapa_ensino.id') + .group('matricula.serie_ano_id') + .group('matricula.ano_censo') + .order('etapa_ensino.id') + .order('matricula.serie_ano_id') + .order('matricula.ano_censo'); + + const queryLabels = [ 'enrollment_per_school_level', 'enrollment_census_year' ]; + const querySet = [ enrollmentsPerSchoolLevelQry, enrollmentsPerSchoolLevelYearQry ]; + // wait until all queries finish or one of them fail + Promise.all(dbExecAll(querySet, enrollmentsPerSchoolLevelYearQry)).then((queryResults) => { + const result = queryResults[0]; + const censusYear = queryResults[1][0]['census_year']; + + let school_levels = {}; + for(let i = 0; i < result.length; ++i) { + const school_year = id2str.schoolYear(result[i].school_year); + const school_level = result[i].school_level; + const census_year = result[i].census_year; + if (typeof school_levels[school_level] === 'undefined') { + school_levels[school_level] = {}; + } + school_levels[school_level][school_year] = parseInt(result[i].total, 10); + } + + let response = []; + for(let level in school_levels) { + if (school_levels.hasOwnProperty(level)) { + let sclevel = {}; + sclevel["degree"] = level; + sclevel["census_year"] = parseInt(censusYear, 10); + sclevel["table"] = []; + for(let school_year in school_levels[level]) { + if (school_levels[level].hasOwnProperty(school_year)) { + let enrollment = { 'title' : school_year, + 'value' : school_levels[level][school_year] }; + sclevel["table"].push(enrollment); + } + } + response.push(sclevel); + } + } + req.result = response; + next(); + }).catch((error) => { + log.error(`[SQL query error] ${error}`); + next(error); + }); +}, response('spatial')); + +module.exports = spatialApp; diff --git a/src/libs/routes_v2/state.js b/src/libs/routes_v2/state.js new file mode 100644 index 0000000000000000000000000000000000000000..c9830b20a52b2997ab96f020c893a00e10d4c3df --- /dev/null +++ b/src/libs/routes_v2/state.js @@ -0,0 +1,108 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const stateApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +stateApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addValue({ + name: 'id', + table: 'estado', + tableField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'id' + } +}).addValue({ + name: 'id_not', + table: 'estado', + tableField: 'id', + where: { + relation: '<>', + type: 'integer', + field: 'id' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'regiao_id', + table: 'estado' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'estado' + } +}).addField({ + name: 'search', + field: false, + where: true +}).addValueToField({ + name: 'name', + table: 'estado', + tableField: 'nome', + where: { + relation: 'LIKE', + type: 'string', + field: 'nome' + } +}, 'search'); + +stateApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('estado') + .field('estado.id').group('estado.id') + .field('regiao_id', 'region_id').group('regiao_id') + .field('estado.nome', 'name').group('estado.nome') + .field('estado.sigla', 'abbreviation').group('estado.sigla') + .field('estado.longitude', 'longitude').group('estado.longitude') + .field('estado.latitude', 'latitude').group('estado.latitude') + .where('estado.id <> 99'); + next(); +}, query, response('state')); + +module.exports = stateApp; diff --git a/src/libs/routes_v2/studentsAee.js b/src/libs/routes_v2/studentsAee.js new file mode 100644 index 0000000000000000000000000000000000000000..2a45a2f5f038407b2fe6b9dbb4b44c504ce4e77e --- /dev/null +++ b/src/libs/routes_v2/studentsAee.js @@ -0,0 +1,219 @@ +const express = require('express'); + +const studentsAeeApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const request = require(`request`); + +const config = require(`${libs}/config`); + +const passport = require('passport'); + +const download = require(`${libs}/middlewares/downloadDatabase`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); +let rqfCount = new ReqQueryFields(); + +// cubApp.get('/year_range', (req, res, next) => { + +// req.sql.from('cub') +// .field('MIN(cub.ano_censo)', 'start_year') +// .field('MAX(cub.ano_censo)', 'end_year'); +// next(); +// }, query, response('range')); + +// cubApp.get('/years', (req, res, next) => { +// req.sql.from('cub') +// .field('DISTINCT cub.ano_censo', 'year'); +// next(); +// }, query, response('years')); + +// cubApp.get('/months', (req, res, next) => { +// req.sql.from('cub') +// .field('DISTINCT cub.mes_censo', 'month'); +// next(); +// }, query, response('months')); + +// cubApp.get('/years_months', (req, res, next) => { +// req.sql.from('cub') +// .field('DISTINCT cub.ano_censo AS "year", cub.mes_censo AS "month"'); +// next(); +// }, query, response('years_months')); + +// cubApp.get('/price_type', (req, res, next) => { +// req.sql.from('cub') +// .field('DISTINCT cub.tipo_preco', 'price_type'); +// next(); +// }, query, response('price_type')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValueToField({ + name: 'state', // working + table: 'estado', + tableField: ['sigla', 'id'], + resultField: ['sigla_uf', 'cod_uf'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'numero_estudantes_aee' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'numero_estudantes_aee' + } +}, 'filter').addValueToField({ + name: 'city', // working + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'numero_estudantes_aee' + } +}, 'filter').addValue({ + name: 'region', // working + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'numero_estudantes_aee' + } +}).addValueToField({ + name: 'school', // working + table: 'escola', + tableField: ['nome_escola', 'id'], + resultField: ['school_name', 'school_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id', 'ano_censo'], + foreign: ['escola_id', 'ano_censo'], + foreignTable: 'numero_estudantes_aee' + } +}, 'filter').addValueToField({ + name: 'locale_id', // working + table: 'numero_estudantes_aee', + tableField: 'localidade_area_rural', + resultField: 'locale_id', + where: { + relation: '=', + type: 'integer', + field: 'localidade_area_rural' + } +}, 'filter').addValue({ + name: 'ethnic_group', // working + table: 'numero_estudantes_aee', + tableField: 'cor_raca_id', + resultField: 'ethnic_group_id', + where: { + relation: '=', + type: 'integer', + field: 'cor_raca_id' + } +}).addValue({ + name: 'adm_dependency', // working + table: 'numero_estudantes_aee', + tableField: 'dependencia_adm_priv', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_priv' + } +}).addValue({ + name:'age_range_all', // working + table: 'numero_estudantes_aee', + tableField: 'faixa_etaria_31_03', + resultField: 'age_range_all_id', + where: { + relation: '=', + type: 'integer', + field: 'faixa_etaria_31_03' + } + }).addValue({ + name: 'gender', // working + table: 'numero_estudantes_aee', + tableField: 'sexo', + resultField: 'gender_id', + where: { + relation: '=', + type: 'integer', + field: 'sexo' + } +}).addValue({ + name: 'activity_days', // working + table: 'numero_estudantes_aee', + tableField: 'dias_atividade', + resultField: 'activity_days_id', + where: { + relation: '=', + type: 'integer', + field: 'dias_atividade' + } +}).addField({ + name: 'special_service', // working + table: 'numero_estudantes_aee', + tableField: 'disc_atendimento_especiais', + resultField: 'special_service_id', + where: { + relation: '=', + type: 'integer', + field: 'disc_atendimento_especiais' + } +}); + +studentsAeeApp.get('/', rqf.parse(), (req, res, next) => { + req.sql.from('numero_estudantes_aee') + .field('numero_estudantes_aee.ano_censo') + .field('COUNT(distinct numero_estudantes_aee.id_aluno)', 'total') + .group('numero_estudantes_aee.ano_censo') + .order('numero_estudantes_aee.ano_censo') + next(); +}, rqf.build(), (req, res, next) => { + console.log(req.sql.toString()); + next(); +}, query, id2str.transform(), response('studentsAee')); + +module.exports = studentsAeeApp; diff --git a/src/libs/routes_v2/teacher.js b/src/libs/routes_v2/teacher.js new file mode 100644 index 0000000000000000000000000000000000000000..94e6d86c60933d906b9f0f8264ebfd14da5534c4 --- /dev/null +++ b/src/libs/routes_v2/teacher.js @@ -0,0 +1,576 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const teacherApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const config = require(`${libs}/config`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +teacherApp.use(cache('15 day')); + +// Returns a tuple of start and ending years of the complete enrollments dataset. +teacherApp.get('/year_range', (req, res, next) => { + req.sql.from('docente') + .field('MIN(docente.ano_censo)', 'start_year') + .field('MAX(docente.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +teacherApp.get('/years', (req, res, next) => { + req.sql.from('docente'). + field('DISTINCT docente.ano_censo', 'year'); + next(); +}, query, response('years')); + +teacherApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'docente\''); + next(); +}, query, response('source')); + +teacherApp.get('/location', (req, res, next) => { + req.result = [ + {id: 1, name: 'Urbana'}, + {id: 2, name: 'Rural'} + ]; + next(); +}, response('location')); + +teacherApp.get('/diff_location', (req, res, next) => { + req.result = [ + {id: 0, name: "A escola não está em localidade diferenciada"}, + {id: 1, name: "Área de assentamento"}, + {id: 2, name: "Terra indígena"}, + {id: 3, name: "Terra remanescente de quilombos"}, + ]; + next(); +}, response('diff_location')); + +teacherApp.get('/adm_dependency_detailed', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 8; ++i) { + req.result.push({ + id: i, + name: id2str.admDependencyPriv(i) + }); + }; + next(); +}, response('adm_dependency_detailed')); + +teacherApp.get('/adm_dependency', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.admDependency(i) + }); + }; + next(); +}, response('adm_dependency')); + +teacherApp.get('/education_level_mod', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 12; ++i) { + req.result.push({ + id: i, + name: id2str.educationLevelMod(i) + }); + } + req.result.push({ + id: 99, + name: id2str.educationLevelMod(99) + }); + next(); +}, response('education_level_mod')); + +teacherApp.get('/education_level_short', (req, res, next) => { + req.result = [ + {id: null, name: 'Não classificada'}, + {id: 1, name: 'Creche'}, + {id: 2, name: 'Pré-Escola'}, + {id: 3, name: 'Ensino Fundamental - anos iniciais'}, + {id: 4, name: 'Ensino Fundamental - anos finais'}, + {id: 5, name: 'Ensino Médio'}, + {id: 6, name: 'EJA'}, + {id: 7, name: 'EE exclusiva'} + ]; + next(); +}, response('education_level_short')); + +teacherApp.get('/education_type', (req, res, next) => { + req.sql.from('docente') + .field('DISTINCT nivel_tipo_formacao', 'id') + .order('id'); + next(); +}, query, (req, res, next) => { + req.result.forEach((result) => { + result.name = id2str.educationType(result.id); + }); + next(); +}, response('education_type')); + +teacherApp.get('/gender', (req, res, next) => { + req.result = [ + {id: 1, name: 'Masculino'}, + {id: 2, name: 'Feminino'} + ]; + next(); +}, response('gender')); + + +teacherApp.get('/contract_type', (req, res, next) => { + req.result = [{ + id: "null", + contractType: id2str.contractType("null") + }]; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.contractType(i) + }); + } + next(); +}, response('contract_type')); + +teacherApp.get('/ethnic_group', (req, res, next) => { + req.result = []; + for(let i = 0; i <=5; ++i) { + req.result.push({ + id: i, + name: id2str.ethnicGroup(i) + }); + } + next(); +}, response('ethnic_group')); + +teacherApp.get('/initial_training', (req, res, next) => { + req.result = []; + for(let i = 1; i <=5; ++i) { + req.result.push({ + id: i, + name: id2str.initialTraining(i) + }); + } + next(); +}, response('initial_training')); + +teacherApp.get('/pos_training', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.posTraining(i) + }); + } + next(); +}, response('pos_training')); + +teacherApp.get('/licentiate_degree', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 3; ++i) { + req.result.push({ + id: i, + name: id2str.licentiateDegree(i) + }); + } + next(); +}, response('licentiate_degree')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'adm_dependency', + table: 'docente', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}).addValue({ + name: 'adm_dependency_detailed', + table: 'docente', + tableField: 'dependencia_adm_priv', + resultField: 'adm_dependency_detailed_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_priv' + } +}).addValue({ + name: 'contract_type', + table: 'docente', + tableField: 'tipo_contratacao', + resultField: 'contract_type_id', + where: { + relation: '=', + type: 'integer', + field: 'tipo_contratacao' + } +}).addValue({ + name: 'education_level_mod', + table: 'docente', + tableField: 'etapas_mod_ensino_segmento_id', + resultField: 'education_level_mod_id', + where: { + relation: '=', + type: 'integer', + field: 'etapas_mod_ensino_segmento_id' + } +}).addValue({ + name: 'education_level_short', + table: 'docente', + tableField: 'etapa_resumida', + resultField: 'education_level_short_id', + where: { + relation: '=', + type: 'integer', + field: 'etapa_resumida' + } +}).addValue({ + name: 'education_type', + table: 'docente', + tableField: 'nivel_tipo_formacao', + resultField: 'education_type_id', + where: { + relation: '=', + type: 'integer', + field: 'nivel_tipo_formacao' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_regiao_id', + foreignTable: 'docente' + } +}).addValue({ + name: 'mesoregion', + table: 'municipio', + tableField: ['nome_mesorregiao', 'mesorregiao_id'], + resultField: ['mesoregion_name', 'mesoregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'mesorregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'escola_municipio_id', + foreignTable: 'docente' + } +}).addValue({ + name: 'microregion', + table: 'municipio', + tableField: ['nome_microrregiao', 'microrregiao_id'], + resultField: ['microregion_name', 'microregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'microrregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'escola_municipio_id', + foreignTable: 'docente' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_estado_id', + foreignTable: 'docente' + } +}).addValueToField({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_municipio_id', + foreignTable: 'docente' + } +}, 'dims').addValueToField({ + name: 'city', + table: 'municipio', + tableField: 'nome', + resultField: 'city_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'escola_municipio_id', + foreignTable: 'docente' + } +}, 'filter').addValueToField({ + name: 'school', + table: 'escola', + tableField: ['nome_escola', 'id'], + resultField: ['school_name', 'school_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id', 'ano_censo'], + foreign: ['escola_id', 'ano_censo'], + foreignTable: 'docente' + } +}, 'dims').addValueToField({ + name: 'school', + table: 'escola', + tableField: 'nome_escola', + resultField: 'school_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id', 'ano_censo'], + foreign: ['escola_id', 'ano_censo'], + foreignTable: 'docente' + } +}, 'filter').addValue({ + name: 'location', + table: 'docente', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name: 'diff_location', + table: 'docente', + tableField: 'localizacao_diferenciada_par', + resultField: 'diff_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_diferenciada_par' + } +}).addValue({ + name: 'rural_location', + table: 'docente', + tableField: 'localidade_area_rural', + resultField: 'rural_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localidade_area_rural' + } +}).addValue({ + name: 'min_year', + table: 'docente', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'docente', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'gender', + table: 'docente', + tableField: 'sexo', + resultField: 'gender_id', + where: { + relation: '=', + type: 'integer', + field: 'sexo' + } +}).addValue({ + name: 'ethnic_group', + table: 'docente', + tableField: 'cor_raca', + resultField: 'ethnic_group_id', + where: { + relation: '=', + type: 'integer', + field: 'cor_raca' + } +}).addValue({ + name: 'initial_training', + table: 'docente', + tableField: 'formacao_inicial_docente', + resultField: 'initial_training_id', + where: { + relation: '=', + type: 'integer', + field: 'formacao_inicial_docente' + } +}).addValue({ + name: 'pos_training', + table: 'docente', + tableField: 'formacao_pos_docente', + resultField: 'pos_training_id', + where: { + relation: '=', + type: 'integer', + field: 'formacao_pos_docente' + } +}).addValue({ + name: 'licentiate_degree', + table: 'docente', + tableField: 'formacao_licenciatura_docente', + resultField: 'licentiate_degree_id', + where: { + relation: '=', + type: 'integer', + field: 'formacao_licenciatura_docente' + } +}); + +const sortYearPtid = (a, b) => { + if (a.year < b.year) + return -1 + if (a.year > b.year) + return 1 + + if (a.pos_training_id < b.pos_training_id) + return -1 + if (a.pos_training_id > b.pos_training_id) + return 1 + return 0 +} + +teacherApp.get('/', rqf.parse(), (req, res, next) => { + req.sql.field('COUNT(DISTINCT docente.id_docente)', 'total') + .field("'Brasil'", 'name') + .field('docente.ano_censo', 'year') + .from('docente') + .join('turma', null, 'docente.turma_id=turma.id AND docente.ano_censo=turma.ano_censo') + .group('docente.ano_censo') + .order('docente.ano_censo') + .where('(docente.tipo_docente = 1 OR docente.tipo_docente = 5) AND \ + ((docente.tipo_turma_id >= 0 AND docente.tipo_turma_id <= 3 AND docente.tipo_turma_atendimento_id is NULL) \ + OR ((docente.tipo_turma_atendimento_id = 1 OR docente.tipo_turma_atendimento_id = 2) AND docente.tipo_turma_id is NULL)) \ + AND (docente.ano_censo <> 2009 or (docente.escola_estado_id <> 42 and docente.escola_estado_id <> 43) )'); // não devemos trazer SC em 2009. + + // if("education_level_mod" in req.dims) { + // req.hadEducationLevelMod = true; + // req.sql.where('docente.etapas_mod_ensino_segmento_id < 11'); + // } + + next(); +}, rqf.build(), query, addMissing(rqf), (req, res, next) => { + // Função criada para preencher valores faltantes no gráfico do indicador de + // formação em pós graduação do MapFOR. + if (req.dims.pos_training){ + var year = req.result[0].year; + var posTrainingIds = req.result.map(obj => { + if (year == obj.year) + return obj.pos_training_id + }).filter(num => num !== undefined) + + var missingValues = []; + for(let i = 1; i <= 4; ++i) { + if ( !posTrainingIds.includes(i) ){ + missingValues.push(i); + } + } + + for (let curYear = 2012; curYear <= 2020; ++curYear){ + for (let ptId of missingValues){ + req.result.push({ + total:0, + name:"Brasil", + year:curYear, + pos_training_id:ptId, + pos_training_name:id2str.posTraining(ptId) + }) + } + } + req.result.sort(sortYearPtid) + + } + next(); +}, id2str.transform(), response('teacher')); + +module.exports = teacherApp; diff --git a/src/libs/routes_v2/transport.js b/src/libs/routes_v2/transport.js new file mode 100644 index 0000000000000000000000000000000000000000..74c1b0954a8cb71cb5e5fd275cdb82143c4dc944 --- /dev/null +++ b/src/libs/routes_v2/transport.js @@ -0,0 +1,400 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const transportApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +transportApp.use(cache('15 day')); + +transportApp.get('/year_range', (req, res, next) => { + req.sql.from('transporte') + .field('MIN(transporte.ano_censo)', 'start_year') + .field('MAX(transporte.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +transportApp.get('/years', (req, res, next) => { + req.sql.from('transporte') + .field('DISTINCT transporte.ano_censo', 'year'); + next(); +}, query, response('years')); + +transportApp.get('/adm_dependency', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.admDependency(i) + }); + }; + next(); +}, response('adm_dependency')); + +transportApp.get('/adm_dependency_detailed', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 6; ++i) { + req.result.push({ + id: i, + name: id2str.admDependencyPriv(i) + }); + }; + next(); +}, response('adm_dependency_detailed')); + +transportApp.get('/location', (req, res, next) => { + req.result = [ + {id: 1, name: 'Urbana'}, + {id: 2, name: 'Rural'} + ]; + next(); +}, response('location')); + +transportApp.get('/rural_location', (req, res, next) => { + req.result = [ + {id: 1, name: "Urbana"}, + {id: 2, name: "Rural"}, + {id: 3, name: "Rural - Área de assentamento"}, + {id: 4, name: "Rural - Terra indígena"}, + {id: 5, name: "Rural - Área remanescente de quilombos"}, + {id: 6, name: "Rural - Unidade de uso sustentável"} + ]; + next(); +}, response('rural_location')); + +transportApp.get('/education_level_mod', (req, res, next) => { + req.result = [ + {id: null, name: 'Não classificada'}, + {id: 1, name: 'Creche'}, + {id: 2, name: 'Pré-Escola'}, + {id: 4, name: 'Ensino Fundamental - anos iniciais'}, + {id: 5, name: 'Ensino Fundamental - anos finais'}, + {id: 6, name: 'Ensino Médio'}, + {id: 7, name: 'Turmas multiseriadas e multietapas'}, + {id: 8, name: 'EJA - Ensino Fundamental'}, + {id: 9, name: 'EJA - Ensino Médio'}, + {id: 10, name: 'Educação Profissional'} + ]; + next(); +}, response('education_level_mod')); + +transportApp.get('/service_type', (req, res, next) => { + req.result = [ + {id: 0, name: 'Não se aplica'}, + {id: 1, name: 'Classe hospitalar'}, + {id: 2, name: 'Unidade de Atendimento Socioeducativo'}, + {id: 3, name: 'Unidade Prisional'}, + {id: 4, name: 'Atividade Complementar '}, + {id: 5, name: 'Atendimento Educacional Especializado (AEE)'} + ]; + next(); +}, response('service_type')); + +transportApp.get('/transportation_manager', (req, res, next) => { + req.result = [ + {id: null, name: 'Não classificada'}, + {id: 1, name: 'Estadual'}, + {id: 2, name: 'Municipal'}, + ]; + next(); +}, response('transportation_manager')); + +transportApp.get('/source', (req, res, next) => { + req.sql.from('fonte') + .field('fonte', 'source') + .where('tabela = \'matricula\''); + next(); +}, query, response('source')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'school', + table: 'escola', + tableField: ['nome_escola', 'id'], + resultField: ['school_name', 'school_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id', 'ano_censo'], + foreign: ['escola_id', 'ano_censo'], + foreignTable: 'transporte' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'transporte' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'transporte' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'transporte' + } +}).addValue({ + name: 'state', + table: 'transporte', + tableField: ['estado_nome', 'estado_id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'transporte' + } +}).addValue({ + name: 'rural_location', + table: 'transporte', + tableField: 'localidade_area_rural', + resultField: 'rural_location_id', + where: { + relation: '=', + type: 'integer', + field: 'localidade_area_rural' + } +}).addValue({ + name: 'location', + table: 'transporte', + tableField: 'localizacao_id', + resultField: 'location_id', + where: { + relation: '=', + type: 'integer', + field: 'localizacao_id' + } +}).addValue({ + name:'adm_dependency', + table: 'transporte', + tableField: 'dependencia_adm_id', + resultField: 'adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_id' + } +}).addValue({ + name: 'adm_dependency_detailed', + table: 'transporte', + tableField: 'dependencia_adm_priv', + resultField: 'adm_dependency_detailed_id', + where: { + relation: '=', + type: 'integer', + field: 'dependencia_adm_priv' + } +}).addValue({ + name: 'transportation_manager', + table: 'transporte', + tableField: 'responsavel_transp', + resultField: 'transportation_manager_id', + where: { + relation: '=', + type: 'integer', + field: 'responsavel_transp' + } +}).addValue({ + name: 'education_level_mod', + table: 'transporte', + tableField: 'etapas_mod_ensino_segmento_id', + resultField: 'education_level_mod_id', + where: { + relation: '=', + type: 'integer', + field: 'etapas_mod_ensino_segmento_id' + } +}).addValue({ + name: 'service_type', + table: 'transporte', + tableField: 'tipo', + resultField: 'service_type_id', + where: { + relation: '=', + type: 'integer', + field: 'tipo' + } +}).addValue({ + name: 'min_year', + table: 'transporte', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'transporte', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'year', + table: 'transporte', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo' + } +}); + +transportApp.get('/', rqf.parse(), (req, res, next) => { + req.dims.year = true; + req.sql + .field('sum(transporte.total)', 'total') + .field("'Brasil'", 'name') + .from('transporte') + .where('transporte.transporte_id=0') + next(); +}, rqf.build(), query, id2str.transform(), (req, res, next) => { + req.total = req.result; + req.resetSql(); + next(); +}, rqf.parse(), (req, res, next) => { + req.dims.year = true; + req.sql + .field('sum(transporte.total)', 'total') + .field("'Brasil'", 'name') + .from('transporte') + .where('transporte.transporte_id=1') + next(); +}, rqf.build(), query, id2str.transform(), (req, res, next) => { + req.public_total = req.result; + req.resetSql(); + next(); + +}, rqf.parse(), (req, res, next) => { + req.dims.year = true; + req.sql + .field('sum(transporte.total)', 'total') + .field("'Brasil'", 'name') + .field('transporte.transporte_id', 'id') + .from('transporte') + .where('transporte.transporte_id>0') + .group('transporte.transporte_id') + .order('transporte.transporte_id') + next(); +}, rqf.build(), query, id2str.transform(), (req, res, next) => { + let transports = req.result; + + let results = []; + let obj = {}; + for (let i = 1; i < 13; i++) { + obj[id2str.transport(i)] = []; + } + + let i = 0 + while (i < transports.length) { + let result = []; + let j = 0; + let transport = transports[i]; + let totalArray = (transport.id == 1) ? req.total : req.public_total; + let match; + obj[id2str.transport(transport.id)] = result; + while (j < totalArray.length && i < transports.length) { + transport = transports[i]; + let transportTotal = totalArray[j]; + + let currentTransport = {}; + delete transport.id; + match = true; + Object.keys(transport).forEach(function(key) { + currentTransport[key] = transportTotal[key]; + if (key != 'total' && transport[key] != transportTotal[key]) { + match = false; + return; + } + }) + + if (match) { + currentTransport.partial = (match) ? transport.total : 0; + currentTransport.percentage = (match) ? transport.total/transportTotal.total * 100 : 0; + result.push(currentTransport); + i++; + j++; + } + else + j++; + } + } + results.push(obj) + req.result = results; + + next(); +}, response('transports')); + +module.exports = transportApp; diff --git a/src/libs/routes_v2/university.js b/src/libs/routes_v2/university.js new file mode 100644 index 0000000000000000000000000000000000000000..be7fe771609b5c4e6a89d98217724c60d0436a5d --- /dev/null +++ b/src/libs/routes_v2/university.js @@ -0,0 +1,347 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const universityApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const request = require(`request`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +const addMissing = require(`${libs}/middlewares/addMissing`); + +let rqf = new ReqQueryFields(); + +let rqfCount = new ReqQueryFields(); + +universityApp.use(cache('15 day')); + +universityApp.get('/upper_adm_dependency', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 7; ++i) { + req.result.push({ + id: i, + name: id2str.upperAdmDependency(i) + }); + }; + next(); +}, response('upper_adm_dependency')); + +universityApp.get('/years', (req, res, next) => { + req.sql.from('ies_ens_superior') + .field('DISTINCT ies_ens_superior.ano_censo', 'year') + next(); +}, query, response('years')); + +universityApp.get('/year_range', (req, res, next) => { + req.sql.from('ies_ens_superior') + .field('MIN(ies_ens_superior.ano_censo)', 'start_year') + .field('MAX(ies_ens_superior.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +universityApp.get('/academic_organization', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 5; ++i) { + req.result.push({ + id: i, + name: id2str.academicOrganization(i) + }); + }; + next(); +}, response('academic_organization')); + +universityApp.get('/capital', (req, res, next) => { + req.result = []; + for(let i = 0; i <= 1; ++i) { + req.result.push({ + id: i, + name: id2str.booleanVariable(i) + }); + }; + next(); +}, response('capital')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addValue({ + name: 'id', + table: 'ies_ens_superior', + tableField: 'cod_ies', + resultField: 'id', + where: { + relation: '=', + type: 'integer', + field: 'cod_ies' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'cod_municipio_ies', + table: 'ies_ens_superior' + }, + join: { + primary: 'id', + foreign: 'cod_municipio_ies', + foreignTable: 'ies_ens_superior' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'cod_uf_ies', + table: 'ies_ens_superior' + }, + join: { + primary: 'id', + foreign: 'cod_uf_ies', + foreignTable: 'ies_ens_superior' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: 'LIKE', + type: 'string', + field: 'id' + }, + join: { + primary: 'nome', + foreign: 'nome_regiao_ies', + foreignTable: 'ies_ens_superior' + } +}).addValue({ + name: 'year', + table: 'ies_ens_superior', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo', + table: 'ies_ens_superior' + } +}).addField({ + name: 'search', + field: true, + where: true +}).addValueToField({ + name: 'city_name', + table: 'municipio', + tableField: 'nome', + resultField: 'city_name', + dontGroup: true, + where: { + relation: 'LIKE', + type: 'string', + field: 'nome' + }, + join: { + primary: 'id', + foreign: 'cod_municipio_ies', + foreignTable: 'ies_ens_superior' + } +}, 'search') +.addValueToField({ + name: 'state_name', + table: 'estado', + tableField: 'nome', + resultField: 'state_name', + dontGroup: true, + where: { + relation: 'LIKE', + type: 'string', + field: 'sigla' + }, + join: { + primary: 'id', + foreign: 'cod_uf_ies', + foreignTable: 'ies_ens_superior' + } +}, 'search'); + + +rqfCount.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'cod_municipio_ies', + table: 'ies_ens_superior' + }, + join: { + primary: 'id', + foreign: 'cod_municipio_ies', + foreignTable: 'ies_ens_superior' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: 'LIKE', + type: 'string', + field: 'id' + }, + join: { + primary: 'nome', + foreign: 'nome_regiao_ies', + foreignTable: 'ies_ens_superior' + } + +}).addValue({ + name: 'min_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'cod_uf_ies', + table: '@' + }, + join: { + primary: 'id', + foreign: 'cod_uf_ies', + foreignTable: '@' + } +}).addValue({ + name: 'upper_adm_dependency', + table: 'ies_ens_superior', + tableField: 'par_categoria_administrativa', + resultField: 'upper_adm_dependency_id', + where: { + relation: '=', + type: 'integer', + table: 'ies_ens_superior', + field: 'cod_categoria_administrativa' + } +}).addValue({ + name: 'academic_organization', + table: 'ies_ens_superior', + tableField: 'cod_organizacao_academica', + resultField: 'academic_organization_id', + where: { + relation: '=', + type: 'integer', + table: 'ies_ens_superior', + field: 'cod_organizacao_academica' + } +}).addValue({ + name: 'capital', + table: 'ies_ens_superior', + tableField: 'tfd_capital_ies', + resultField: 'capital_id', + where: { + relation: '=', + type: 'integer', + table: 'ies_ens_superior', + field: 'capital_ies' + } +}); + +universityApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('ies_ens_superior') + .field('ies_ens_superior.cod_ies', 'id') + .field('ies_ens_superior.ano_censo', 'year') + .field('ies_ens_superior.nome_ies', 'name') + .field('ies_ens_superior.cod_uf_ies', 'state_id') + .field('ies_ens_superior.cod_municipio_ies', 'city_id') + .field('ies_ens_superior.cod_uf_ies/10', 'region_id'); + next(); + +}, query, response('university')); + +universityApp.get('/count', rqfCount.parse(), (req, res, next) => { + req.sql.field('COUNT(*)', 'total') + .field("'Brasil'", 'name') + .field('ies_ens_superior.ano_censo', 'year') + .from('ies_ens_superior') + .group('ies_ens_superior.ano_censo') + .order('ies_ens_superior.ano_censo') + + next(); +}, rqfCount.build(), query, addMissing(rqfCount), id2str.transform(), response('university')); + +module.exports = universityApp; diff --git a/src/libs/routes_v2/universityEnrollment.js b/src/libs/routes_v2/universityEnrollment.js new file mode 100644 index 0000000000000000000000000000000000000000..8df5aded0c1ea4f91cbbbbd5fff8e2ea1cd0b279 --- /dev/null +++ b/src/libs/routes_v2/universityEnrollment.js @@ -0,0 +1,848 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const universityEnrollmentApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +universityEnrollmentApp.get('/years', (req, res, next) => { + req.sql.from('aluno_ens_superior') + .field('DISTINCT aluno_ens_superior.ano_censo', 'year') + .where('aluno_ens_superior.ano_censo > 2010'); + next(); +}, query, response('years')); + +universityEnrollmentApp.get('/year_range', (req, res, next) => { + req.sql.from('aluno_ens_superior') + .field('MIN(aluno_ens_superior.ano_censo)', 'start_year') + .field('MAX(aluno_ens_superior.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +universityEnrollmentApp.get('/academic_organization', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 5; ++i) { + req.result.push({ + id: i, + name: id2str.academicOrganization(i) + }); + }; + next(); +}, response('academic_organization')); + +universityEnrollmentApp.get('/upper_adm_dependency', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 7; ++i) { + req.result.push({ + id: i, + name: id2str.upperAdmDependency(i) + }); + }; + next(); +}, response('upper_adm_dependency')); + +universityEnrollmentApp.get('/ocde_geral', (req, res, next) => { + req.result = []; + for(let i = 0; i <= 8; ++i) { + req.result.push({ + id: i, + name: id2str.ocdeGeral(i) + }); + }; + next(); +}, response('ocde_geral')); + + +universityEnrollmentApp.get('/finish', (req, res, next) => { + req.result = [] + for (let i = 0; i <= 1; ++i){ + req.result.push({ + id: i, + name: id2str.finishUniversity(i) + }) + } + next(); + +}, response('finish')); + +universityEnrollmentApp.get('/ocde_specific', (req, res, next) => { + req.result = []; + const defaultCase = null; + for(let i = 1; i <= 86; ++i) { + let obj = { + id: i, + name: id2str.ocdeSpecific(i) + }; + if (obj.name !== id2str.ocdeSpecific(defaultCase)){ + req.result.push(obj); + } + }; + req.result.push({ + id: defaultCase, + name: id2str.ocdeSpecific(defaultCase) + }); + next(); +}, response('ocde_specific')); + +universityEnrollmentApp.get('/ocde_detailed', (req, res, next) => { + req.result = []; + const defaultCase = null; + for(let i = 142; i <= 863; ++i) { + let obj = { + id: i, + name: id2str.ocdeDetailed(i) + }; + if (obj.name !== id2str.ocdeDetailed(defaultCase)){ + req.result.push(obj); + } + }; + req.result.push({ + id: defaultCase, + name: id2str.ocdeDetailed(defaultCase) + }); + next(); +}, response('ocde_detailed')); + +universityEnrollmentApp.get('/cine_geral', (req, res, next) => { + req.result = []; + for(let i = 0; i <= 10; ++i) { + req.result.push({ + id: i, + name: id2str.cineGeral(i) + }); + }; + next(); +}, response('cine_geral')); + +universityEnrollmentApp.get('/cine_specific', (req, res, next) => { + req.result = []; + const defaultCase = null; + for(let i = 1; i <= 104; ++i) { + let obj = { + id: i, + name: id2str.cineSpecific(i) + }; + if (obj.name !== id2str.cineSpecific(defaultCase)){ + req.result.push(obj); + } + }; + req.result.push({ + id: defaultCase, + name: id2str.cineSpecific(defaultCase) + }); + next(); +}, response('cine_specific')); + +universityEnrollmentApp.get('/cine_detailed', (req, res, next) => { + req.result = []; + const defaultCase = null; + for(let i = 11; i <= 1041; ++i) { + let obj = { + id: i, + name: id2str.cineDetailed(i) + }; + if (obj.name !== id2str.cineDetailed(defaultCase)){ + req.result.push(obj); + } + }; + req.result.push({ + id: defaultCase, + name: id2str.cineDetailed(defaultCase) + }); + next(); +}, response('cine_detailed')); + +universityEnrollmentApp.get('/upper_turn', (req, res, next) => { + req.result = [{ + id: "null", + name: id2str.upperTurn("null") + }]; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.upperTurn(i) + }); + }; + next(); +}, response('upper_turn')); + +universityEnrollmentApp.get('/student_deficiency', (req, res, next) => { + req.result = [{ + id: 9, + name: id2str.studentDeficiency(9) + }]; + for(let i = 0; i <= 1; ++i) { + req.result.push({ + id: i, + name: id2str.studentDeficiency(i) + }); + }; + next(); +}, response('student_deficiency')); + +universityEnrollmentApp.get('/ethnic_group_ies', (req, res, next) => { + req.result = [{ + id: 9, + name: id2str.ethnicGroupIES(9) + }]; + for(let i = 0; i <=5; ++i) { + req.result.push({ + id: i, + name: id2str.ethnicGroupIES(i) + }); + } + next(); +}, response('ethnic_group_ies')); + +universityEnrollmentApp.get('/school_type', (req, res, next) => { + req.result = [{ + id: 9, + name: id2str.schoolType(9) + }]; + for(let i = 1; i <= 2; ++i) { + req.result.push({ + id: i, + name: id2str.schoolType(i) + }); + }; + next(); +}, response('school_type')); + +universityEnrollmentApp.get('/university', (req, res, next) => { + req.sql.from('aluno_ens_superior') + .field('DISTINCT aluno_ens_superior.nome_ies', 'nome') + .field('aluno_ens_superior.cod_ies', 'cod') + next(); +}, query, response('university')); + +universityEnrollmentApp.get('/academic_level', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.academicLevel(i) + }); + }; + next(); +}, response('academic_level')); + +universityEnrollmentApp.get('/gender_ies', function (req, res, next) { + req.result = []; + for (var i = 1; i <= 2; ++i) { + req.result.push({ + id: i, + name: id2str.genderIES(i) + }); + }; + next(); +}, response('gender_ies')); + +universityEnrollmentApp.get('/upper_education_mod', function (req, res, next) { + req.result = []; + for (var i = 1; i <= 3; ++i) { + req.result.push({ + id: i, + name: id2str.upperEducationMod(i) + }); + }; + next(); +}, response('upper_education_mod')); + +universityEnrollmentApp.get('/age_student_code', function (req, res, next) { + req.result = []; + for (var i = 1; i <= 6; ++i) { + req.result.push({ + id: i, + name: id2str.ageStudentCode(i) + }); + }; + next(); +}, response('age_student_code')); + + +universityEnrollmentApp.get('/enter_situation/student_enter_situation', function (req, res, next) { + req.result = []; + for (var i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.enterSituation(i) + }); + }; + next(); +}, response('student_enter_situation')); + +universityEnrollmentApp.get('/enrollment_situation/student_enter_situation', function (req, res, next) { + req.result = []; + for (var i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.enterSituation(i) + }); + }; + next(); +}, response('student_enter_situation')); + + +universityEnrollmentApp.get('/enter_situation/student_enrollment_situation', function (req, res, next) { + req.result = []; + for (var i = 1; i <= 3; ++i) { + req.result.push({ + id: i, + name: id2str.enrollmentSituation(i) + }); + }; + next(); +}, response('student_enrollment_situation')); + +universityEnrollmentApp.get('/university', (req, res, next) => { + req.sql.from('aluno_ens_superior') + .field('DISTINCT aluno_ens_superior.nome_ies', 'nome') + .field('aluno_ens_superior.cod_ies', 'cod') + next(); +}, query, response('university')); + +universityEnrollmentApp.get('/localoffer', (req, res, next) => { + req.sql.from('localoferta_ens_superior', 'l') + .field('DISTINCT l.nome', 'localoffer_name') + .field('l.cod_local_oferta', 'localoffer_id'); + next(); +}, query, response('localoffer')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'localoferta_cod_municipio', + table: 'localoferta_ens_superior_matricula' + }, + join: { + primary: 'id', + foreign: 'localoferta_cod_municipio', + foreignTable: 'localoferta_ens_superior_matricula' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'localoferta_cod_uf', + table: 'localoferta_ens_superior_matricula' + }, + join: { + primary: 'id', + foreign: 'localoferta_cod_uf', + foreignTable: 'localoferta_ens_superior_matricula' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'localoferta_cod_regiao', + table: 'localoferta_ens_superior_matricula' + }, + join: { + primary: 'id', + foreign: 'localoferta_cod_regiao', + foreignTable: 'localoferta_ens_superior_matricula' + } +}).addValue({ + name: 'localoffer', + table: 'localoferta_ens_superior_matricula', + tableField: ['cod_local_oferta', 'localoferta_nome'], + resultField: ['localoffer_id', 'localoffer_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_local_oferta' + } +}).addValue({ + name: 'campi', + table: 'localoferta_ens_superior_matricula', + tableField: ['cod_local_oferta', 'localoferta_nome'], + resultField: ['campi_id', 'campi_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_local_oferta' + } +}).addValue({ + name: 'university', + table: '@', + tableField: ['cod_ies', 'nome_ies'], + resultField: ['university_id', 'university_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_ies' + } +}).addValue({ + name: 'universityLocalOffer', + table: '@', + tableField: ['cod_ies', 'nome_ies'], + resultField: ['university_id', 'university_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_ies' + } +}).addValue({ + name:'upper_adm_dependency', + table: '@', + tableField: 'par_categoria_administrativa', + resultField: 'upper_adm_dependency_id', + where: { + relation: '=', + type: 'integer', + field: 'par_categoria_administrativa' + } +}).addValue({ + name:'academic_organization', + table: '@', + tableField: 'cod_organizacao_academica', + resultField: 'academic_organization_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_organizacao_academica' + } +}).addValue({ + name:'ocde_specific', + table: '@', + tableField: ['par_cod_ocde_area_especifica'], + resultField: ['ocde_specific_id'], + where: { + relation: '=', + type: 'integer', + field: 'par_cod_ocde_area_especifica' + } +}).addValue({ + name:'ocde_geral', + table: '@', + tableField: ['par_cod_ocde_area_geral'], + resultField: ['ocde_geral_id'], + where: { + relation: '=', + type: 'integer', + field: 'par_cod_ocde_area_geral' + } +}).addValue({ + name:'ocde_detailed', + table: '@', + tableField: ['par_cod_ocde_area_detalhada'], + resultField: ['ocde_detailed_id'], + where: { + relation: '=', + type: 'integer', + field: 'par_cod_ocde_area_detalhada' + } +}).addValue({ + name:'cine_specific', + table: '@', + tableField: ['cod_cine_area_especifica', 'nome_cine_area_especifica'], + resultField: ['cine_specific_id', 'cine_specific_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_cine_area_especifica' + } +}).addValue({ + name:'cine_geral', + table: '@', + tableField: ['cod_cine_area_geral', 'nome_cine_area_geral'], + resultField: ['cine_geral_id', 'cine_geral_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_cine_area_geral' + } +}).addValue({ + name:'cine_detailed', + table: '@', + tableField: ['cod_cine_area_detalhada', 'nome_cine_area_detalhada'], + resultField: ['cine_detailed_id', 'cine_detailed_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_cine_area_detalhada' + } +}).addValue({ + name:'academic_level', + table: '@', + tableField: 'cod_grau_academico', + resultField: 'academic_level_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_grau_academico' + } +}).addValue({ + name:'upper_education_mod', + table: '@', + tableField: 'cod_modalidade_ensino', + resultField: 'upper_education_mod_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_modalidade_ensino' + } +}).addValue({ + name:'is_free', + table: '@', + tableField: 'gratuito', + resultField: 'is_free_id', + where: { + relation: '=', + type: 'boolean', + field: 'gratuito' + } +}).addValue({ + name:'night_time', + table: '@', + tableField: 'noturno_curso_t', + resultField: 'night_time_id', + where: { + relation: '=', + type: 'boolean', + field: 'noturno_curso_t' + } +}).addValue({ + name:'situation', + table: '@', + tableField: 'cod_situacao_curso', + resultField: 'situacao_curso_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_situacao_curso' + } +}).addValue({ + name:'finish', + table: '@', + tableField: 'concluinte', + resultField: 'finish_id', + where: { + relation: '=', + type: 'integer', + field: 'concluinte' + } +}).addValue({ + name:'year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '=', + type: 'integer', + field: 'ano_censo' + } +}).addValue({ + name: 'min_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'age_student_code', + table: '@', + tableField: 'idade_aluno_codigo', + resultField: 'age_student_code_id', + where: { + relation: '=', + type: 'integer', + field: 'idade_aluno_codigo' + } +}).addValue({ + name:'upper_turn', + table: '@', + tableField: 'cod_turno_aluno', + resultField: 'upper_turn_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_turno_aluno' + } +}).addValue({ + name:'ethnic_group_ies', + table: '@', + tableField: 'par_cod_cor_raca_aluno', + resultField: 'ethnic_group_ies_id', + where: { + relation: '=', + type: 'integer', + field: 'par_cod_cor_raca_aluno' + } +}).addValue({ + name:'student_deficiency', + table: '@', + tableField: 'par_aluno_deficiencia_transtorno_superdotacao', + resultField: 'student_deficiency_id', + where: { + relation: '=', + type: 'integer', + field: 'par_aluno_deficiencia_transtorno_superdotacao' + } +}).addValue({ + name:'school_type', + table: '@', + tableField: 'par_tipo_escola_ensino_medio', + resultField: 'school_type_id', + where: { + relation: '=', + type: 'integer', + field: 'par_tipo_escola_ensino_medio' + } +}).addValue({ + name: 'gender_ies', + table: '@', + tableField: 'par_genero_aluno', + resultField: 'gender_ies_id', + where: { + relation: '=', + type: 'integer', + field: 'par_genero_aluno' + } +}).addValue({ + name: 'mesoregion', + table: 'municipio', + tableField: ['nome_mesorregiao', 'mesorregiao_id'], + resultField: ['mesoregion_name', 'mesoregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'mesorregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'localoferta_cod_municipio', + foreignTable: 'localoferta_ens_superior_matricula' + } +}).addValue({ + name: 'microregion', + table: 'municipio', + tableField: ['nome_microrregiao', 'microrregiao_id'], + resultField: ['microregion_name', 'microregion_id'], + where: { + relation: '=', + type: 'integer', + field: 'microrregiao_id', + table: 'municipio' + }, + join: { + primary: 'id', + foreign: 'localoferta_cod_municipio', + foreignTable: 'localoferta_ens_superior_matricula' + } +}).addValue({ + name: 'course', + table: 'curso_ens_superior', + tableField: 'nome_curso', + resultField: 'course_name', + where:{ + relation: '=', + type: 'string', + table: 'curso_ens_superior', + field: 'nome_curso' + }, + join:{ + primary: ['ano_censo', 'cod_curso'], + foreign: ['ano_censo', 'cod_curso'], + foreignTable: 'localoferta_ens_superior_matricula' + } +}); + +universityEnrollmentApp.get('/', rqf.parse(), (req, res, next) => { + if ("localoffer" in req.dims) { + if ("university" in req.dims || "universityLocalOffer" in req.dims) { + req.sql.from('localoferta_ens_superior_matricula') + .field('curso_ens_superior.ano_censo', 'year') + .field('COUNT(localoferta_ens_superior.cod_local_oferta)', 'total') + .group('localoferta_ens_superior_matricula.ano_censo') + .where('localoferta_ens_superior_matricula.cod_aluno_situacao = 2 OR localoferta_ens_superior_matricula.cod_aluno_situacao = 6 OR localoferta_ens_superior_matricula.matriculado = 1') + .where('localoferta_ens_superior_matricula.cod_nivel_academico = 1') + .order('localoferta_ens_superior_matricula.ano_censo') + .order('localoferta_ens_superior.cod_local_oferta'); + } else { + req.sql.from('localoferta_ens_superior_matricula') + .field('localoferta_ens_superior_matricula.ano_censo', 'year') + .field('COUNT(*)', 'total') + .field('localoferta_ens_superior_matricula.cod_ies', 'university_id') + .field('localoferta_ens_superior_matricula.nome_ies', 'university_name') + .where('localoferta_ens_superior_matricula.cod_aluno_situacao = 2 OR localoferta_ens_superior_matricula.cod_aluno_situacao = 6 OR localoferta_ens_superior_matricula.matriculado = 1') + .where('localoferta_ens_superior_matricula.cod_nivel_academico = 1') + .group('localoferta_ens_superior_matricula.ano_censo') + .group('localoferta_ens_superior_matricula.cod_ies') + .group('localoferta_ens_superior_matricula.nome_ies') + .order('localoferta_ens_superior_matricula.ano_censo') + .order('localoferta_ens_superior_matricula.cod_local_oferta'); + } + } else if (("state" in req.dims) || ("city" in req.dims) || ("region" in req.dims) || ("mesoregion" in req.dims) || ("microregion" in req.dims) || + ("state" in req.filter) || ("city" in req.filter) || ("region" in req.filter) || ("mesoregion" in req.filter) || ("microregion" in req.filter)) { + req.sql.from('localoferta_ens_superior_matricula') + .field('DISTINCT COUNT(*)', 'total') + .field("'Brasil'", 'name') + .field('localoferta_ens_superior_matricula.ano_censo', 'year') + .where('localoferta_ens_superior_matricula.cod_aluno_situacao = 2 OR localoferta_ens_superior_matricula.cod_aluno_situacao = 6 OR localoferta_ens_superior_matricula.matriculado = 1') + .where('localoferta_ens_superior_matricula.cod_nivel_academico = 1') + .group('localoferta_ens_superior_matricula.ano_censo') + .order('localoferta_ens_superior_matricula.ano_censo') + } else if ("university" in req.dims || "universityLocalOffer" in req.dims) { + req.sql.from('aluno_ens_superior') + .field('COUNT(*)', 'total') + .field("'Brasil'", 'name') + .field('aluno_ens_superior.ano_censo', 'year') + .group('aluno_ens_superior.cod_ies') + .group('aluno_ens_superior.ano_censo') + .where('aluno_ens_superior.cod_aluno_situacao = 2 OR aluno_ens_superior.cod_aluno_situacao = 6 OR aluno_ens_superior.matriculado = 1') + .where('aluno_ens_superior.cod_nivel_academico = 1') + .order('aluno_ens_superior.cod_ies') + .order('aluno_ens_superior.ano_censo') + } else { + req.sql.from('localoferta_ens_superior_matricula') + .field('COUNT(*)', 'total') + .field("'Brasil'", 'name') + .field('localoferta_ens_superior_matricula.ano_censo', 'year') + .where('localoferta_ens_superior_matricula.cod_aluno_situacao = 2 OR localoferta_ens_superior_matricula.cod_aluno_situacao = 6 OR localoferta_ens_superior_matricula.matriculado = 1') + .where('localoferta_ens_superior_matricula.cod_nivel_academico = 1') + .group('localoferta_ens_superior_matricula.ano_censo') + .order('localoferta_ens_superior_matricula.ano_censo') + } + next(); +}, rqf.build(), query, (req, res, next) =>{ console.log(req.sql.toString()); next()}, id2str.transform(), addMissing(rqf), (req, res, next) => { + if ('course' in req.dims){ + var total_course = req.result.reduce((total, cur) => {return total += cur.total}, 0) + for (var course of req.result){ + course.percentage = Number((( course.total / total_course ) * 100).toFixed(2)) + } + } + next(); +}, response('universityEnrollment')); + +universityEnrollmentApp.get('/enter_situation', rqf.parse(), (req, res, next) => { + req.sql.from('localoferta_ens_superior_matricula') + .field('SUM(CASE WHEN localoferta_ens_superior_matricula.cod_aluno_situacao=2 AND localoferta_ens_superior_matricula.ingressante=1 THEN 1 ELSE 0 END)', 'cursando') + .field('SUM(CASE WHEN localoferta_ens_superior_matricula.cod_aluno_situacao=6 AND localoferta_ens_superior_matricula.ingressante=1 THEN 1 ELSE 0 END)', 'concluinte') + .field('SUM(CASE WHEN (localoferta_ens_superior_matricula.cod_aluno_situacao=4 OR localoferta_ens_superior_matricula.cod_aluno_situacao=5 OR localoferta_ens_superior_matricula.cod_aluno_situacao=7) AND localoferta_ens_superior_matricula.ingressante=1 THEN 1 ELSE 0 END)', 'evadido') + .field('SUM(CASE WHEN localoferta_ens_superior_matricula.cod_aluno_situacao=3 AND localoferta_ens_superior_matricula.ingressante=1 THEN 1 ELSE 0 END)', 'trancado') + .field('COUNT(*)', 'total') + .field("'Brasil'", 'name') + .field('localoferta_ens_superior_matricula.ano_censo', 'year') + .where('localoferta_ens_superior_matricula.cod_nivel_academico=1') + .where('localoferta_ens_superior_matricula.cod_grau_academico=2 OR localoferta_ens_superior_matricula.cod_grau_academico=4') + .group('localoferta_ens_superior_matricula.ano_censo') + .order('localoferta_ens_superior_matricula.ano_censo') + next() +}, rqf.build(), query, (req, res, next) => { + for (var res of req.result){ + res.cursando = Number(res.cursando); + res.concluinte = Number(res.concluinte); + res.evadido = Number(res.evadido); + res.trancado = Number(res.trancado); + res.total = res.cursando + res.concluinte + res.evadido + res.trancado + res.taxa_evasao = Number( ((res.evadido/res.total) * 100).toFixed(2) ) + } + next(); +}, id2str.transform(), response('enterSituation')); + +universityEnrollmentApp.get('/enrollment_situation', rqf.parse(), (req, res, next) => { + req.sql.from('localoferta_ens_superior_matricula') + .field('SUM(CASE WHEN localoferta_ens_superior_matricula.cod_aluno_situacao=2 THEN 1 ELSE 0 END)', 'cursando') + .field('SUM(CASE WHEN localoferta_ens_superior_matricula.cod_aluno_situacao=6 THEN 1 ELSE 0 END)', 'concluinte') + .field('SUM(CASE WHEN (localoferta_ens_superior_matricula.cod_aluno_situacao=4 OR localoferta_ens_superior_matricula.cod_aluno_situacao=5 OR localoferta_ens_superior_matricula.cod_aluno_situacao=7) THEN 1 ELSE 0 END)', 'evadido') + .field('SUM(CASE WHEN localoferta_ens_superior_matricula.cod_aluno_situacao=3 THEN 1 ELSE 0 END)', 'trancado') + .field('localoferta_ens_superior_matricula.ano_censo', 'year') + .field("'Brasil'", 'name') + .where('localoferta_ens_superior_matricula.cod_nivel_academico=1') + .where('localoferta_ens_superior_matricula.cod_grau_academico=2 OR localoferta_ens_superior_matricula.cod_grau_academico=4') + .group('localoferta_ens_superior_matricula.ano_censo') + .order('localoferta_ens_superior_matricula.ano_censo') + next() +}, rqf.build(),query, (req, res, next) => { + for (var res of req.result){ + res.cursando = Number(res.cursando); + res.concluinte = Number(res.concluinte); + res.evadido = Number(res.evadido); + res.trancado = Number(res.trancado); + res.total = res.cursando + res.concluinte + res.evadido + res.trancado + } + + next(); +}, id2str.transform(), response('enrollmentSituation')); + + + +module.exports = universityEnrollmentApp; diff --git a/src/libs/routes_v2/universityLocalOffer.js b/src/libs/routes_v2/universityLocalOffer.js new file mode 100644 index 0000000000000000000000000000000000000000..535094c492915b6b3d38a5e02a267a4196910c36 --- /dev/null +++ b/src/libs/routes_v2/universityLocalOffer.js @@ -0,0 +1,170 @@ +''/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const universityLocalOfferApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const request = require(`request`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +const addMissing = require(`${libs}/middlewares/addMissing`); + +let rqf = new ReqQueryFields(); + +universityLocalOfferApp.use(cache('15 day')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'cod_municipio', + table: 'localoferta_ens_superior' + }, + join: { + primary: 'id', + foreign: 'cod_municipio', + foreignTable: 'localoferta_ens_superior' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: 'LIKE', + type: 'string', + field: 'id' + }, + join: { + primary: 'nome', + foreign: 'nome_regiao_ies', + foreignTable: 'localoferta_ens_superior' + } + +}).addValue({ + name: 'min_year', + table: 'localoferta_ens_superior', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: 'localoferta_ens_superior', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'localoferta_ens_superior', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: 'localoferta_ens_superior', + field: 'ano_censo' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'cod_uf', + table: 'localoferta_ens_superior' + }, + join: { + primary: 'id', + foreign: 'cod_uf', + foreignTable: 'localoferta_ens_superior' + } +}).addValueToField({ + name: 'university', + table: 'localoferta_ens_superior', + tableField: 'cod_ies', + resultField: 'university_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_ies', + table: 'localoferta_ens_superior' + } +}, 'filter').addValue({ + name: 'year', + table: 'localoferta_ens_superior', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '=', + type: 'integer', + table: 'localoferta_ens_superior', + field: 'ano_censo' + } +}); + + +universityLocalOfferApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + req.sql.from('localoferta_ens_superior') + .field('distinct localoferta_ens_superior.cod_ies', 'id') + .field('localoferta_ens_superior.cod_local_oferta', 'localoffer_id') + .field('localoferta_ens_superior.ano_censo', 'year') + .field('ies_ens_superior.nome_ies', 'name') + .field('localoferta_ens_superior.nome', 'localoffer_name') + .field('localoferta_ens_superior.cod_uf', 'state_id') + .field('localoferta_ens_superior.cod_municipio', 'city_id') + .field('localoferta_ens_superior.cod_regiao', 'region_id') + .join('ies_ens_superior', null, 'localoferta_ens_superior.cod_ies=ies_ens_superior.cod_ies AND localoferta_ens_superior.ano_censo=ies_ens_superior.ano_censo') + .where('localoferta_ens_superior.nome IS NOT NULL AND ies_ens_superior.nome_ies IS NOT NULL'); + next(); + +}, query, response('universityLocalOfferApp')); + +module.exports = universityLocalOfferApp; diff --git a/src/libs/routes_v2/universityTeacher.js b/src/libs/routes_v2/universityTeacher.js new file mode 100644 index 0000000000000000000000000000000000000000..f65a29b2e7ce54a9b374873352a744809fc0a4f0 --- /dev/null +++ b/src/libs/routes_v2/universityTeacher.js @@ -0,0 +1,517 @@ +/* +Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + +This file is part of simcaq-node. + +simcaq-node is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +simcaq-node is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with simcaq-node. If not, see <https://www.gnu.org/licenses/>. +*/ + +const express = require('express'); + +const teacherEnrollmentApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +teacherEnrollmentApp.get('/years', (req, res, next) => { + req.sql.from('docente_ens_superior') + .field('DISTINCT docente_ens_superior.ano_censo', 'year'); + next(); +}, query, response('years')); + +teacherEnrollmentApp.get('/year_range', (req, res, next) => { + req.sql.from('docente_ens_superior') + .field('MIN(docente_ens_superior.ano_censo)', 'start_year') + .field('MAX(docente_ens_superior.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +teacherEnrollmentApp.get('/academic_organization', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 5; ++i) { + req.result.push({ + id: i, + name: id2str.academicOrganization(i) + }); + }; + next(); +}, response('academic_organization')); + +teacherEnrollmentApp.get('/upper_adm_dependency', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 7; ++i) { + req.result.push({ + id: i, + name: id2str.upperAdmDependency(i) + }); + }; + next(); +}, response('upper_adm_dependency')); + +teacherEnrollmentApp.get('/teacher_situation', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 6; ++i) { + req.result.push({ + id: i, + name: id2str.teacherSituation(i) + }); + }; + next(); +}, response('teacher_situation')); + +teacherEnrollmentApp.get('/work_regime', (req, res, next) => { + req.result = [{ + id: "null", + name: id2str.workRegime("null") + }]; + for(let i = 1; i <= 4; ++i) { + req.result.push({ + id: i, + name: id2str.workRegime(i) + }); + }; + next(); +}, response('work_regime')); + +teacherEnrollmentApp.get('/substitute', (req, res, next) => { + req.result = [{ + id: "null", + name: id2str.booleanVariable("null") + }]; + for(let i = 0; i <= 1; ++i) { + req.result.push({ + id: i, + name: id2str.booleanVariable(i) + }); + }; + next(); +}, response('substitute')); + +teacherEnrollmentApp.get('/visitor', (req, res, next) => { + req.result = [{ + id: "null", + name: id2str.booleanVariable("null") + }]; + for(let i = 0; i <= 1; ++i) { + req.result.push({ + id: i, + name: id2str.booleanVariable(i) + }); + }; + next(); +}, response('visitor')); + +teacherEnrollmentApp.get('/ead_teacher', (req, res, next) => { + req.result = [{ + id: "null", + name: id2str.booleanVariable("null") + }]; + for(let i = 0; i <= 1; ++i) { + req.result.push({ + id: i, + name: id2str.booleanVariable(i) + }); + }; + next(); +}, response('ead_teacher')); + +teacherEnrollmentApp.get('/graduation_presential', (req, res, next) => { + req.result = [{ + id: "null", + name: id2str.booleanVariable("null") + }]; + for(let i = 0; i <= 1; ++i) { + req.result.push({ + id: i, + name: id2str.booleanVariable(i) + }); + }; + next(); +}, response('graduation_presential')); + +teacherEnrollmentApp.get('/postgraduate_ead_teacher', (req, res, next) => { + req.result = [{ + id: "null", + name: id2str.booleanVariable("null") + }]; + for(let i = 0; i <= 1; ++i) { + req.result.push({ + id: i, + name: id2str.booleanVariable(i) + }); + }; + next(); +}, response('postgraduate_ead_teacher')); + +teacherEnrollmentApp.get('/postgraduate_presential_teacher', (req, res, next) => { + req.result = [{ + id: "null", + name: id2str.booleanVariable("null") + }]; + for(let i = 0; i <= 1; ++i) { + req.result.push({ + id: i, + name: id2str.booleanVariable(i) + }); + }; + next(); +}, response('postgraduate_presential_teacher')); + +teacherEnrollmentApp.get('/deficiency', (req, res, next) => { + req.result = [{ + id: 9, + name: id2str.studentDeficiency(9) + }]; + for(let i = 0; i <= 1; ++i) { + req.result.push({ + id: i, + name: id2str.studentDeficiency(i) + }); + }; + next(); +}, response('deficiency')); + +teacherEnrollmentApp.get('/ethnic_group_teacher_ies', (req, res, next) => { + req.result = [{ + id: 9, + name: id2str.ethnicGroupTeacherIES(9) + }]; + for(let i = 0; i <= 5; ++i) { + req.result.push({ + id: i, + name: id2str.ethnicGroupTeacherIES(i) + }); + }; + next(); +}, response('ethnic_group_teacher_ies')); + +teacherEnrollmentApp.get('/teacher_schooling', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 5; ++i) { + req.result.push({ + id: i, + name: id2str.teacherSchooling(i) + }); + }; + next(); +}, response('teacher_schooling')); + +teacherEnrollmentApp.get('/gender_ies', (req, res, next) => { + req.result = []; + for(let i = 1; i <= 2; ++i) { + req.result.push({ + id: i, + name: id2str.genderIES(i) + }); + }; + next(); +}, response('gender_ies')); + + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'min_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['nome', 'id'], + resultField: ['state_name', 'state_id'], + where: { + relation: '=', + type: 'integer', + field: 'cod_uf_ies', + table: '@' + }, + join: { + primary: 'id', + foreign: 'cod_uf_ies', + foreignTable: '@' + } +}).addValue({ + name: 'city', + table: 'municipio', + tableField: ['nome', 'id'], + resultField: ['city_name', 'city_id'], + where: { + relation: '=', + type: 'integer', + field: 'cod_municipio_ies', + table: '@' + }, + join: { + primary: 'id', + foreign: 'cod_municipio_ies', + foreignTable: '@' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: ['nome', 'id'], + resultField: ['region_name', 'region_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'cod_regiao_ies', + foreignTable: 'docente_ens_superior' + } +}).addValue({ + name: 'university', + table: 'docente_ens_superior', + tableField: ['cod_ies', 'nome_ies'], + resultField: ['university_id', 'university_name'], + where: { + relation: '=', + type: 'integer', + field: 'cod_ies' + } +}).addValue({ + name: 'upper_adm_dependency', + table: 'docente_ens_superior', + tableField: 'par_categoria_administrativa', + resultField: 'upper_adm_dependency_id', + where: { + relation: '=', + type: 'integer', + table: 'docente_ens_superior', + field: 'par_categoria_administrativa' + } +}).addValue({ + name: 'academic_organization', + table: 'docente_ens_superior', + tableField: 'cod_organizacao_academica', + resultField: 'academic_organization_id', + where: { + relation: '=', + type: 'integer', + table: 'docente_ens_superior', + field: 'cod_organizacao_academica' + } +}).addValue({ + name:'academic_level', + table: 'docente_ens_superior', + tableField: 'cod_grau_academico', + resultField: 'academic_level_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_grau_academico' + } +}).addValue({ + name:'upper_education_mod', + table: 'docente_ens_superior', + tableField: 'cod_modalidade_ensino', + resultField: 'upper_education_mod_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_modalidade_ensino' + } +}).addValue({ + name:'teacher_situation', + table: 'docente_ens_superior', + tableField: 'par_situacao_docente', + resultField: 'teacher_situation_id', + where: { + relation: '=', + type: 'integer', + field: 'par_situacao_docente' + } +}).addValue({ + name:'work_regime', + table: 'docente_ens_superior', + tableField: 'cod_regime_trabalho', + resultField: 'work_regime_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_regime_trabalho' + } +}).addValue({ + name:'substitute', + table: 'docente_ens_superior', + tableField: 'docente_substituto', + resultField: 'substitute_id', + where: { + relation: '=', + type: 'boolean', + field: 'docente_substituto' + } +}).addValue({ + name:'visitor', + table: 'docente_ens_superior', + tableField: 'docente_visitante', + resultField: 'visitor_id', + where: { + relation: '=', + type: 'boolean', + field: 'docente_visitante' + } +}).addValue({ + name:'ead_teacher', + table: 'docente_ens_superior', + tableField: 'ministra_aula_ead', + resultField: 'ead_teacher_id', + where: { + relation: '=', + type: 'boolean', + field: 'ministra_aula_ead' + } +}).addValue({ + name:'graduation_presential', + table: 'docente_ens_superior', + tableField: 'atua_atividade_graduacao_presencial', + resultField: 'graduation_presential_id', + where: { + relation: '=', + type: 'boolean', + field: 'atua_atividade_graduacao_presencial' + } +}).addValue({ + name:'postgraduate_ead_teacher', + table: 'docente_ens_superior', + tableField: 'atua_atividade_posgraduacao_distancia', + resultField: 'postgraduate_ead_teacher_id', + where: { + relation: '=', + type: 'boolean', + field: 'atua_atividade_posgraduacao_distancia' + } +}).addValue({ + name:'postgraduate_presential_teacher', + table: 'docente_ens_superior', + tableField: 'atua_atividade_posgraduacao_presencial', + resultField: 'postgraduate_presential_teacher_id', + where: { + relation: '=', + type: 'boolean', + field: 'atua_atividade_posgraduacao_presencial' + } +}).addValue({ + name:'teacher_schooling', + table: 'docente_ens_superior', + tableField: 'cod_escolaridade_docente', + resultField: 'teacher_schooling_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_escolaridade_docente' + } +}).addValue({ + name:'ethnic_group_teacher_ies', + table: 'docente_ens_superior', + tableField: 'cod_cor_raca_docente', + resultField: 'ethnic_group_teacher_ies_id', + where: { + relation: '=', + type: 'integer', + field: 'cod_cor_raca_docente' + } +}).addValue({ + name:'gender_ies', + table: 'docente_ens_superior', + tableField: 'sexo_docente', + resultField: 'gender_ies_id', + where: { + relation: '=', + type: 'integer', + field: 'sexo_docente' + } +}).addValue({ + name:'deficiency', + table: 'docente_ens_superior', + tableField: 'par_docente_deficiencia', + resultField: 'deficiency_id', + where: { + relation: '=', + type: 'integer', + field: 'par_docente_deficiencia' + } +}); + +teacherEnrollmentApp.get('/', rqf.parse(), (req, res, next) => { + + if ("university" in req.dims) { + req.sql.field('COUNT(*)', 'total') + .field("'Brasil'", 'name') + .field('docente_ens_superior.ano_censo', 'year') + .from('docente_ens_superior') + .group('docente_ens_superior.cod_ies') + .group('docente_ens_superior.ano_censo') + .order('docente_ens_superior.cod_ies') + .order('docente_ens_superior.ano_censo') + } + else { + req.sql.field('COUNT(*)', 'total') + .field("'Brasil'", 'name') + .field('docente_ens_superior.ano_censo', 'year') + .from('docente_ens_superior') + .group('docente_ens_superior.ano_censo') + .order('docente_ens_superior.ano_censo') + } + + next(); +}, rqf.build(), query, addMissing(rqf), id2str.transform(false), response('teacherEnrollment')); + +module.exports = teacherEnrollmentApp; diff --git a/src/libs/routes/user.js b/src/libs/routes_v2/user.js similarity index 98% rename from src/libs/routes/user.js rename to src/libs/routes_v2/user.js index 7ff088eea62f34ffd3b66de4a28ae42807a97e8d..a2ab63a5dd0c8c24bf3d18dbc39a9e0b3e739b72 100644 --- a/src/libs/routes/user.js +++ b/src/libs/routes_v2/user.js @@ -100,7 +100,7 @@ userApp.get('/me', passport.authenticate('bearer', { session: false }), (req, re }, response('user')); userApp.get('/:id', (req, res, next) => { - User.findById(req.params.id, (err, user) => { + User.findOne({id:req.params.id}, (err, user) => { if(err) { log.error(err); return next(err); @@ -195,7 +195,7 @@ userApp.post('/', (req, res, next) => { }); userApp.put('/:id', passport.authenticate('bearer', { session: false }), (req, res, next) => { - User.findById(req.params.id, (err, user) => { + User.findOne({id:req.params.id}, (err, user) => { if (err) { log.error(err); return next({err}); diff --git a/src/libs/routes/verifyToken.js b/src/libs/routes_v2/verifyToken.js similarity index 96% rename from src/libs/routes/verifyToken.js rename to src/libs/routes_v2/verifyToken.js index d54f64aa162c767c765784398dbcab455a9d666e..8978cd4bb84d75b48a060799a1ab846aa627180a 100644 --- a/src/libs/routes/verifyToken.js +++ b/src/libs/routes_v2/verifyToken.js @@ -22,7 +22,7 @@ verifyTokenApp.get('/:token', (req, res, next) => { res.statusCode = 404; return next({msg: 'Token not found', status:404}); } - User.findById(vToken.userId, (err, user) => { + User.findOne({id:vToken.userId}, (err, user) => { if(err) { log.error(err); next(err);