diff --git a/.eslintrc.json b/.eslintrc.json index 14152dfcb9ae24e77005322efbbfbe811504ae58..bac0de40f23bdc06babf20e5c715f05b3f8b6c41 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -7,6 +7,8 @@ "import" ], "rules": { + "jsx-a11y/heading-has-content": [ "off" ], + "jsx-a11y/anchor-has-content": [ "off" ], "indent": [ "error", 4 ], "no-unused-vars": [ "error", { "args": "none" }], "no-param-reassign": [ "off" ] diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bc0c1575b968932e3a14cb588c029cf1cd795f4..9fd4af3db07b78bb5fe5b03f50e8cc84af1ad67a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +- Change parseParams default value from `null` to `true` +- Query middleware throws a 404 when the result is empty +- Change filters and dimensions names! No more `_id`. **Breaks compability** +- Add a basic sanitize function ## 0.1.0 - 2016-10-10 ### Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6e7b10c10b205cca5712e6ef1542ba5c99b5c13a..39149f5870bd6f98d5644bedae5dbfe23038692a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,6 +17,7 @@ Bugs are reported and tracked at [simcaq/SCRUM](https://gitlab.c3sl.ufpr.br/simc * **development**: default branch * **issue/??**: issue branch - a branch created to solve a issue * **feature_????**: feature branch - a branch created to add a feature +* **hotfix_????**: hotfix branch - a branch created to fix a problem or error * **release_vM.m.f**: release branch - a branch created to merge with master and set a release. The verion follows the [semantic versioning](http://semver.org) ## Styleguide diff --git a/config.json.example b/config.json.example index fa9c64ea2e2fb5eeddcce58e4746b1bc456d03b4..3e586b5684bc2749e8eee38f4c4630f10fa62a8b 100644 --- a/config.json.example +++ b/config.json.example @@ -10,7 +10,7 @@ "dbname": "simcaq_dev", "user": "monetdb", "password":"monetdb", - "nrConnections": "16" + "nrConnections": "4" }, "mongodb" : { "uri": "mongodb://localhost/users", @@ -33,7 +33,7 @@ "dbname": "simcaq_dev", "user": "monetdb", "password":"monetdb", - "nrConnections": "16" + "nrConnections": "4" }, "mongodb" : { "uri": "mongodb://localhost/test_users", @@ -49,14 +49,14 @@ { "port": 3000, "ip": "127.0.0.1", - "debug" : true, + "debug" : false, "monetdb": { "host": "simcaqdb1", "port": 50000, "dbname": "simcaq_dev", "user": "monetdb", "password":"monetdb", - "nrConnections": "16" + "nrConnections": "4" }, "mongodb" : { "uri": "mongodb://localhost/users", diff --git a/gulpfile.babel.js b/gulpfile.babel.js index 7b74ae0e7676e31e2c5a6862e86608962fa34a9b..de2702965c4c57c283098d9e87a517d6e0bbe00f 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -47,16 +47,17 @@ gulp.task('compile', ['lint'], () => { .pipe(babel()) // compile only modified files // .pipe(cache.cache()) // cache compiled files .pipe(gulp.dest('build')); // move compiled files to build directory +}); +gulp.task('build', ['compile'], () => { + var filesToCopy = [ 'config.json', 'package.json' ]; // copy configuration file to build directory - gulp.src('config.json') + gulp.src(filesToCopy) .pipe(gulp.dest('build')); createLogDir(); }); -gulp.task('build', ['compile']); - gulp.task('docco', () => { gulp.src('./src/**/*.js') .pipe(docco()) @@ -74,7 +75,7 @@ gulp.task('pre-test', () => { gulp.task('test', ['pre-test'], () => { process.chdir('build'); gulp.src('test/test.js', {read: false}) - .pipe(mocha()) + .pipe(mocha({timeout: 15000})) .pipe(istanbul.writeReports()) .pipe(istanbul.enforceThresholds({ thresholds: { @@ -114,4 +115,4 @@ gulp.task('run', () => { }); }); -gulp.task('default', ['run']); +gulp.task('default', ['run']); \ No newline at end of file diff --git a/package.json b/package.json index a7056dc915f19875538b5f4de96bda8d4fa764d9..d923ed1f1a30bd1b7753d665a08407233a5bb3e0 100644 --- a/package.json +++ b/package.json @@ -4,32 +4,37 @@ "author": "C3SL", "description": "Simulador custo aluno-qualidade", "private": true, + "engines": { + "node": ">= 6.8.1" + }, + "engineStrict": true, "scripts": { "start": "cd build && forever start server.js || node server.js", "test": "cd build && mocha" }, "dependencies": { - "apicache": "0.0.14", - "bcrypt": "^0.8.7", + "apicache": "0.7.0", + "bcrypt-nodejs": "0.0.3", "body-parser": "^1.13.1", "chai": "^3.5.0", "chai-http": "^3.0.0", + "chalk": "^1.1.3", "compression": "^1.6.2", "cookie-parser": "^1.3.5", "cors": "^2.7.1", "csv-express": "^1.1.0", - "debug": "~2.0.x", + "debug": "~2.3.x", "dirty-chai": "^1.2.2", "express": "^4.13.0", - "faker": "^2.1.5", + "faker": "^3.1.0", "forever": "^0.15.2", - "js2xmlparser": "^1.0.0", + "js2xmlparser": "^2.0.2", "jwt-simple": "^0.5.0", "method-override": "^2.3.3", - "mocha": "^2.5.3", + "mocha": "^3.1.2", "monetdb-pool": "0.0.8", "mongoose": "^4.6.0", - "nconf": "^0.6.x", + "nconf": "^0.8.x", "passport": "^0.3.2", "squel": "^5.4.2", "winston": "^2.2.0" @@ -45,9 +50,9 @@ "chai-xml": "^0.3.1", "docdash": "^0.4.0", "eslint": "^3.3.1", - "eslint-config-airbnb": "^10.0.1", - "eslint-plugin-import": "^1.13.0", - "eslint-plugin-jsx-a11y": "^2.1.0", + "eslint-config-airbnb": "^13.0.0", + "eslint-plugin-import": "^2.2.0", + "eslint-plugin-jsx-a11y": "^2.2.3", "eslint-plugin-react": "^6.1.1", "gulp": "^3.9.1", "gulp-babel": "^6.1.2", @@ -55,9 +60,9 @@ "gulp-docco": "0.0.4", "gulp-eslint": "^3.0.1", "gulp-file-cache": "0.0.1", - "gulp-function": "^1.3.6", + "gulp-function": "^2.2.0", "gulp-istanbul": "^1.1.1", - "gulp-jsdoc3": "^0.3.0", + "gulp-jsdoc3": "^1.0.1", "gulp-mocha": "^3.0.1", "gulp-nodemon": "^2.1.0", "gulp-plumber": "^1.1.0", diff --git a/src/libs/app.js b/src/libs/app.js index fa685039b525ff430eca6841908666b40d8b0300..d0f452ab3b188297471416019e478b5d64c1d2b6 100644 --- a/src/libs/app.js +++ b/src/libs/app.js @@ -37,16 +37,17 @@ app.use((req, res, next) => { req.sql = squel.select(); next(); }); +// Mounts all API routes under /api/v1 app.use('/api/v1', api); // Catch 404 and forward to error handler app.use((req, res, next) => { res.status(404); - log.debug('%s %d %s', req.method, res.statusCode, req.url); - res.json({ error: 'Not found' }).end(); + log.error('%s %d %s', req.method, res.statusCode, req.url); + res.json({ error: 'Error 404: Page not found' }).end(); }); -// Error handlers +// Express' default error handler app.use((err, req, res, next) => { res.status(err.status || 500); log.error('%s %d %s', req.method, res.statusCode, err.message); diff --git a/src/libs/db/query_exec.js b/src/libs/db/query_exec.js index 71ae6d9824ac304eb5fd4e4d0e122b16d8d159a2..1a2f7387574bc2f886550ef39f86f221c6a98e49 100644 --- a/src/libs/db/query_exec.js +++ b/src/libs/db/query_exec.js @@ -19,26 +19,25 @@ function execSqlQuery(sqlQuery, sqlQueryParams = []) { log.debug(`Executing SQL query '${sqlQuery}' with params '${sqlQueryParams}'`); return new Promise((resolve, reject) => { // Prepare statement - conn.prepare(sqlQuery, true).then( - (dbQuery) => { - // Execute query - dbQuery.exec(sqlQueryParams).then( - // Success - (dbResult) => { - log.debug(`Query result: ${dbResult.data}`); - log.debug(dbResult.data); - resolve(dbResult.data); - }, - // Error - (dbError) => { - log.error(`SQL query execution error: ${dbError.message}`); - reject(new Error(dbError.message)); - } - ); - // Release resources allocated for prepared statement - conn.release(); - } - ); + conn.prepare(sqlQuery, true).then((dbQuery) => { + // Execute query + dbQuery.exec(sqlQueryParams).then((dbResult) => { + log.debug(`Query result: ${dbResult.data}`); + // release resources allocated for the prepared statement + dbQuery.release(); + resolve(dbResult.data); + }).catch((queryError) => { + log.error(`SQL query execution error: ${queryError.message}`); + log.error(`SQL query: ${sqlQuery} with params: ${sqlQueryParams}`); + // release resources allocated for the prepared statement + dbQuery.release(); + reject(new Error(queryError.message)); + }); + }).catch((prepError) => { + log.error(`SQL prepared statement error: ${prepError.message}`); + log.error(`SQL query: ${sqlQuery} with params: ${sqlQueryParams}`); + reject(new Error(prepError.message)); + }); }); } diff --git a/src/libs/middlewares/checkVersion.js b/src/libs/middlewares/checkVersion.js new file mode 100644 index 0000000000000000000000000000000000000000..c3187adba9081e2a992d09df36e839efc23dfca0 --- /dev/null +++ b/src/libs/middlewares/checkVersion.js @@ -0,0 +1,22 @@ +const curPath = process.cwd(); +const libs = `${process.cwd()}/libs`; +const log = require(`${libs}/log`)(module); +const chalk = require('chalk'); +const packageConf = require(`${curPath}/package.json`); + +module.exports = () => { + // Parse version number from strings such as 'v4.2.0' or `>=4.0.0' + function parseVersionNumber(versionString) { + return parseFloat(versionString.replace(/[^\d\.]/g, '')); + } + // Ensure minimum supported node version is used + const minNodeVersion = parseVersionNumber(packageConf.engines.node); + const currentNodeVersion = parseVersionNumber(process.version); + if (minNodeVersion > currentNodeVersion) { + log.error(chalk.red(`You must upgrade node to >=${minNodeVersion}.x to use simcaq-node!`)); + return false; + } else { + log.info('Node version should work!'); + return true; + } +}; diff --git a/src/libs/middlewares/parseParams.js b/src/libs/middlewares/parseParams.js index c74b6b491bc445b22cd480c85d9f232494a139de..36361f274b13ebeaeff709bc2b48e4869682a47c 100644 --- a/src/libs/middlewares/parseParams.js +++ b/src/libs/middlewares/parseParams.js @@ -36,7 +36,7 @@ function parseParams(queryParam, arr) { // Get the key and the value - state:41 is key 'state' whith value 41 const kv = param.split(':'); // Check if there is a value. If there isn't, assign null - obj[kv[0]] = (typeof kv[1] === 'undefined') ? null : kv[1]; + obj[kv[0]] = (typeof kv[1] === 'undefined') ? true : kv[1]; } // If the array exists and is not empty we intersect diff --git a/src/libs/middlewares/query.js b/src/libs/middlewares/query.js index a4f20e3ba5bdd31cf7dab85a44121b8e8e456fc0..42b7b7df784de6f35e18c2fed7047ee56a5b4949 100644 --- a/src/libs/middlewares/query.js +++ b/src/libs/middlewares/query.js @@ -9,9 +9,13 @@ function query(req, res, next) { execQuery(sql.text, sql.values).then((result) => { log.debug(result); req.result = result; + if (result.length === 0) { + next({status: 404, message: 'Not Found'}); + } next(); }, (error) => { - next(error); + log.error(error.stack); + next(new Error('Request could not be satisfied due to a database error.')); }); } diff --git a/src/libs/middlewares/response.js b/src/libs/middlewares/response.js index 580c16f5bd7470d20c622565954234f873f56b54..cb2f4ca3a14bf9b2240ce1ebeeec3e89c05746c4 100644 --- a/src/libs/middlewares/response.js +++ b/src/libs/middlewares/response.js @@ -12,7 +12,7 @@ function response(value) { res.attachment(`${value}.csv`); res.csv(req.result); } else if (req.query.format === 'xml') { - res.send(xml('result', JSON.stringify({ [value]: req.result }))); + res.send(xml.parse('result', { [value]: req.result })); } else { res.json({ result: req.result }); } diff --git a/src/libs/models/user.js b/src/libs/models/user.js index 572e5239e3c1a8cd4eedf755edf12a13625a89de..59786097b80ee35193ca2e187caabe28151f1ba0 100644 --- a/src/libs/models/user.js +++ b/src/libs/models/user.js @@ -1,5 +1,5 @@ const mongoose = require('mongoose'); -const bcrypt = require('bcrypt'); +const bcrypt = require('bcrypt-nodejs'); const libs = `${process.cwd()}/libs`; const log = require(`${libs}/log`)(module); const Schema = mongoose.Schema; diff --git a/src/libs/routes/city.js b/src/libs/routes/city.js index 733da6f341cc37a7b6b792b8f5383076eae75067..d963287567363544f145ecef506dcf934f669767 100644 --- a/src/libs/routes/city.js +++ b/src/libs/routes/city.js @@ -12,27 +12,27 @@ const response = require(`${libs}/middlewares/response`); // Return all cities cityApp.get('/', (req, res, next) => { - req.sql.from('municipios'); + req.sql.from('municipio'); next(); }, query, response('city')); // Return a specific city by it's id cityApp.get('/:id', (req, res, next) => { - req.sql.from('municipios') - .where('pk_municipio_id = ?', parseInt(req.params.id, 10)); + req.sql.from('municipio') + .where('pk_cod_ibge = ?', parseInt(req.params.id, 10)); next(); }, query, response('city')); // Return a specific city by it's IBGE code cityApp.get('/ibge/:id', (req, res, next) => { - req.sql.from('municipios') - .where('codigo_ibge = ?', req.params.id); + req.sql.from('municipio') + .where('pk_cod_ibge = ?', parseInt(req.params.id, 10)); next(); }, query, response('city')); // Return all the cities from a specific state cityApp.get('/state/:id', (req, res, next) => { - req.sql.from('municipios') + req.sql.from('municipio') .where('fk_estado_id = ?', parseInt(req.params.id, 10)); next(); }, query, response('city')); diff --git a/src/libs/routes/enrollment.js b/src/libs/routes/enrollment.js index 9fe6e903bdbe9bc10b89181866a920792b832533..3e878e7f23b2d038cf217147f19c28d34a246e4e 100644 --- a/src/libs/routes/enrollment.js +++ b/src/libs/routes/enrollment.js @@ -20,18 +20,16 @@ const parseParams = require(`${libs}/middlewares/parseParams`); // 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 = squel.select() - .from('turmas') - .field('MIN(turmas.ano_censo)', 'start_year') - .field('MAX(turmas.ano_censo)', 'end_year'); + req.sql.from('turma') + .field('MIN(turma.ano_censo)', 'start_year') + .field('MAX(turma.ano_censo)', 'end_year'); next(); }, query, response('range')); // Returns all educational levels avaible enrollmentApp.get('/education_level', (req, res, next) => { - req.sql = squel.select() - .from('etapa_ensino') + req.sql.from('etapa_ensino') .field('pk_etapa_ensino_id', 'id') .field('desc_etapa', 'name'); @@ -40,8 +38,7 @@ enrollmentApp.get('/education_level', (req, res, next) => { // Returns all adm dependencies enrollmentApp.get('/adm_dependency', (req, res, next) => { - req.sql = squel.select() - .from('dependencia_adms') + req.sql.from('dependencia_adm') .field('pk_dependencia_adm_id', 'id') .field('nome', 'name'); @@ -52,17 +49,17 @@ enrollmentApp.get('/adm_dependency', (req, res, next) => { enrollmentApp.use('/', parseParams('filter', [ 'min_year', 'max_year', - 'adm_dependency_id', - 'location_id', - 'education_level_id', + 'adm_dependency', + 'location', + 'education_level', 'region', 'state', 'city', 'school' ]), parseParams('dims', [ - 'adm_dependency_id', - 'location_id', - 'education_level_id', + 'adm_dependency', + 'location', + 'education_level', 'region', 'state', 'city', @@ -72,86 +69,81 @@ enrollmentApp.use('/', parseParams('filter', [ log.debug(req.dims); // Do the joins - if(typeof req.filter.adm_dependency_id !== 'undefined' - || typeof req.dims.adm_dependency_id !== 'undefined') { - req.sql.join('dependencia_adms', null, 'fk_dependencia_adm_id=dependencia_adms.pk_dependencia_adm_id'); + if(typeof req.filter.adm_dependency !== 'undefined' + || typeof req.dims.adm_dependency !== 'undefined') { + req.sql.join('dependencia_adm', null, 'fk_dependencia_adm_id=dependencia_adm.pk_dependencia_adm_id'); } - if(typeof req.filter.education_level_id !== 'undefined' - || typeof req.dims.education_level_id !== 'undefined') { + if(typeof req.filter.education_level !== 'undefined' + || typeof req.dims.education_level !== 'undefined') { req.sql.join('etapa_ensino', null, 'fk_etapa_ensino_id=etapa_ensino.pk_etapa_ensino_id'); } if(typeof req.filter.region !== 'undefined' || typeof req.dims.region !== 'undefined') { - req.sql.join('municipios', null, 'fk_municipio_id=municipios.pk_municipio_id') - .join('estados', null, 'municipios.fk_estado_id=estados.pk_estado_id') - .join('regioes', null, 'estados.fk_regiao_id=regioes.pk_regiao_id'); + req.sql.join('regiao', null, 'fk_regiao_id=regiao.pk_regiao_id'); } - if((typeof req.filter.state !== 'undefined' - || typeof req.dims.state !== 'undefined') - && (typeof req.filter.region === 'undefined' - && typeof req.dims.region === 'undefined')) { - req.sql.join('municipios', null, 'fk_municipio_id=municipios.pk_municipio_id') - .join('estados', null, 'municipios.fk_estado_id=estados.pk_estado_id'); + if(typeof req.filter.state !== 'undefined' + || typeof req.dims.state !== 'undefined') { + req.sql.join('estado', null, 'fk_estado_id=estado.pk_estado_id'); } - if((typeof req.filter.city !== 'undefined' - || typeof req.dims.city !== 'undefined') - && (typeof req.filter.state === 'undefined' - && typeof req.dims.state === 'undefined') - && (typeof req.filter.region === 'undefined' - && typeof req.dims.region === 'undefined')) { - req.sql.join('municipios', null, 'fk_municipio_id=municipios.pk_municipio_id'); + if(typeof req.filter.city !== 'undefined' + || typeof req.dims.city !== 'undefined') { + req.sql.join('municipio', null, 'fk_municipio_id=municipio.pk_cod_ibge'); } if(typeof req.dims.school !== 'undefined') { - req.sql.join('escolas', null, 'fk_escola_id=escolas.pk_escola_id'); + req.sql.join('escola', null, 'turma.cod_entidade=escola.cod_entidade'); + } + + if(typeof req.dims.location !== 'undefined') { + req.sql.join('localizacao', null, 'turma.id_localizacao=localizacao.pk_localizacao_id') } // Dimensions (add fields) - if(typeof req.dims.education_level_id !== 'undefined') { + if(typeof req.dims.education_level !== 'undefined') { req.sql.field('desc_etapa', 'education_level') .group('desc_etapa') .order('desc_etapa'); } if(typeof req.dims.region !== 'undefined') { - req.sql.field('regioes.nome', 'region_name') - .group('regioes.nome') - .order('regioes.nome'); + req.sql.field('regiao.nome', 'region_name') + .group('regiao.nome') + .order('regiao.nome'); } if(typeof req.dims.state !== 'undefined') { - req.sql.field('estados.nome', 'state_name') - .group('estados.nome') - .order('estados.nome'); + req.sql.field('estado.nome', 'state_name') + .group('estado.nome') + .order('estado.nome'); } if(typeof req.dims.city !== 'undefined') { - req.sql.field('municipios.nome', 'city_name') - .group('municipios.nome') - .order('municipios.nome'); + req.sql.field('municipio.nome', 'city_name') + .group('municipio.nome') + .order('municipio.nome'); } if(typeof req.dims.school !== 'undefined') { - req.sql.field('escolas.nome_entidade', 'school_name') - .group('escolas.nome_entidade') - .order('escolas.nome_entidade'); + req.sql.field('escola.cod_entidade', 'school_name') + .group('escola.cod_entidade') + .order('escola.cod_entidade'); } - if(typeof req.dims.adm_dependency_id !== 'undefined') { - req.sql.field('dependencia_adms.nome', 'adm_dependency_name') - .group('dependencia_adms.nome') - .order('dependencia_adms.nome'); + if(typeof req.dims.adm_dependency !== 'undefined') { + req.sql.field('dependencia_adm.nome', 'adm_dependency_name') + .group('dependencia_adm.nome') + .order('dependencia_adm.nome'); } - if(typeof req.dims.location_id !== 'undefined') { - req.sql.field('turmas.id_localizacao', 'location') - .group('turmas.id_localizacao') - .order('turmas.id_localizacao'); + if(typeof req.dims.location !== 'undefined') { + req.sql.field('localizacao.descricao', 'location_name') + .group('localizacao.descricao') + .order('localizacao.descricao'); } if(typeof req.dims.region === 'undefined' @@ -164,23 +156,23 @@ enrollmentApp.use('/', parseParams('filter', [ // Filter (add where) if (typeof req.filter.min_year !== 'undefined') { - req.sql.where('turmas.ano_censo>=?', parseInt(req.filter.min_year, 10)); + req.sql.where('turma.ano_censo>=?', parseInt(req.filter.min_year, 10)); } if (typeof req.filter.max_year !== 'undefined') { - req.sql.where('turmas.ano_censo<=?', parseInt(req.filter.max_year, 10)); + req.sql.where('turma.ano_censo<=?', parseInt(req.filter.max_year, 10)); } - if (typeof req.filter.adm_dependency_id !== 'undefined') { - req.sql.where('pk_dependencia_adm_id=?', parseInt(req.filter.adm_dependency_id, 10)); + if (typeof req.filter.adm_dependency !== 'undefined') { + req.sql.where('pk_dependencia_adm_id=?', parseInt(req.filter.adm_dependency, 10)); } - if (typeof req.filter.location_id !== 'undefined') { - req.sql.where('turmas.id_localizacao=?', parseInt(req.filter.location_id, 10)); + if (typeof req.filter.location !== 'undefined') { + req.sql.where('turma.id_localizacao=?', parseInt(req.filter.location, 10)); } - if (typeof req.filter.education_level_id !== 'undefined') { - req.sql.where('pk_etapa_ensino_id=?', parseInt(req.filter.education_level_id, 10)); + if (typeof req.filter.education_level !== 'undefined') { + req.sql.where('pk_etapa_ensino_id=?', parseInt(req.filter.education_level, 10)); } if (typeof req.filter.region !== 'undefined') { @@ -192,11 +184,11 @@ enrollmentApp.use('/', parseParams('filter', [ } if (typeof req.filter.city !== 'undefined') { - req.sql.where('turmas.fk_municipio_id=?', parseInt(req.filter.city, 10)); + req.sql.where('turma.fk_municipio_id=?', parseInt(req.filter.city, 10)); } if (typeof req.filter.school !== 'undefined') { - req.sql.where('turmas.fk_escola_id=?', parseInt(req.filter.school, 10)); + req.sql.where('turma.fk_escola_id=?', parseInt(req.filter.school, 10)); } log.debug(req.sql.toParam()); next(); @@ -204,11 +196,11 @@ enrollmentApp.use('/', parseParams('filter', [ enrollmentApp.get('/', (req, res, next) => { req.sql.field('COALESCE(SUM(num_matriculas), 0)', 'total') - .field('turmas.ano_censo', 'year') - .from('turmas') - .group('turmas.ano_censo') - .order('turmas.ano_censo'); + .field('turma.ano_censo', 'year') + .from('turma') + .group('turma.ano_censo') + .order('turma.ano_censo'); next(); -}, query, response('test')); +}, query, response('enrollment')); module.exports = enrollmentApp; diff --git a/src/libs/routes/region.js b/src/libs/routes/region.js index 773ad347959049dd2137d96abb255a3bc809a2d4..0a8b65f860655e71e7aaf4f1b6211a37d481199c 100644 --- a/src/libs/routes/region.js +++ b/src/libs/routes/region.js @@ -12,13 +12,13 @@ const response = require(`${libs}/middlewares/response`); // Get all regions regionApp.get('/', (req, res, next) => { - req.sql.from('regioes'); + req.sql.from('regiao'); next(); }, query, response('region')); // Get a region by it's id regionApp.get('/:id', (req, res, next) => { - req.sql.from('regioes') + req.sql.from('regiao') .where('pk_regiao_id = ?', parseInt(req.params.id, 10)); next(); }, query, response('region')); diff --git a/src/libs/routes/school.js b/src/libs/routes/school.js index 6c92430b425d3b9fde8c682216c8f6a10f07b75f..4ae980e2a1715f4170c3881c76d2af49d7ecb8d3 100644 --- a/src/libs/routes/school.js +++ b/src/libs/routes/school.js @@ -17,43 +17,40 @@ const response = require(`${libs}/middlewares/response`); * Pense na cena do elevador de driver mas o elevador é uma bomba de fusão e demora mais que uma luta do DBz */ // schoolApp.get('/', (req, res, next) => { -// req.sql = squel.select().from('escolas') -// .field('pk_escola_id') -// .field('nome_entidade', 'name') +// req.sql = squel.select().from('escola') +// .field('cod_entidade') // .field('ano_censo', 'year') -// .field('fk_cod_estado') -// .field('fk_cod_municipio'); +// .field('fk_estado_id') +// .field('fk_municipio_id'); // next(); // }, query, response('school')); // Get a school by it's id schoolApp.get('/:id', (req, res, next) => { - req.sql.from('escolas') - .where('pk_escola_id = ?', parseInt(req.params.id, 10)); + req.sql.from('escola') + .where('escola.cod_entidade = ?', parseInt(req.params.id, 10)); next(); }, query, response('school')); // Get all schools from a state schoolApp.get('/state/:id', (req, res, next) => { - req.sql.from('escolas') - .field('pk_escola_id') - .field('nome_entidade') + req.sql.from('escola') + .field('escola.cod_entidade') .field('ano_censo') - .field('fk_cod_estado') - .field('fk_cod_municipio') - .where('fk_cod_estado = ?', parseInt(req.params.id, 10)); + .field('fk_estado_id') + .field('fk_municipio_id') + .where('fk_estado_id = ?', parseInt(req.params.id, 10)); next(); }, query, response('school')); // Get all schools from a city schoolApp.get('/city/:id', (req, res, next) => { - req.sql.from('escolas') - .field('pk_escola_id') - .field('nome_entidade') + req.sql.from('escola') + .field('escola.cod_entidade') .field('ano_censo') - .field('fk_cod_estado') - .field('fk_cod_municipio') - .where('fk_cod_municipio = ?', parseInt(req.params.id, 10)); + .field('fk_estado_id') + .field('fk_municipio_id') + .where('fk_municipio_id = ?', parseInt(req.params.id, 10)); next(); }, query, response('school')); diff --git a/src/libs/routes/state.js b/src/libs/routes/state.js index 75e1c0b7835901804ea78e459b1fe0050ec03631..8567ec05f7448fcbf3ebe00fefbc9d5e6e48de27 100644 --- a/src/libs/routes/state.js +++ b/src/libs/routes/state.js @@ -12,20 +12,20 @@ const response = require(`${libs}/middlewares/response`); // Get all states stateApp.get('/', (req, res, next) => { - req.sql.from('estados'); + req.sql.from('estado'); next(); }, query, response('state')); // Get a state stateApp.get('/:id', (req, res, next) => { - req.sql.from('estados') + req.sql.from('estado') .where('pk_estado_id = ?', parseInt(req.params.id, 10)); next(); }, query, response('state')); // Get all states from a region stateApp.get('/region/:id', (req, res, next) => { - req.sql.from('estados') + req.sql.from('estado') .where('fk_regiao_id = ?', parseInt(req.params.id, 10)); next(); }, query, response('state')); diff --git a/src/server.js b/src/server.js index 4e097f28a4053050757c6329e19e225e0424b961..aaf9309ef94b0e30a9683cc9fcc854e4205b8e7b 100644 --- a/src/server.js +++ b/src/server.js @@ -8,6 +8,13 @@ const log = require(`${libs}/log`)(module); const app = require(`${libs}/app`); +const compatVersion = require(`${libs}/middlewares/checkVersion`); + +// Check if Node version is compatible +if (!compatVersion()) { + process.exit(1); +} + // Set default port: first environment variable PORT, then configuration and last 3000 app.set('port', process.env.PORT || config.port || 3000); process.env.NODE_ENV = process.env.NODE_ENV || 'development'; diff --git a/src/test/test.js b/src/test/test.js index 71f9227c3da50525dd056eb3f4be989c79d90e22..8b55179e1556030ce9a90644bfbdac57624caef8 100644 --- a/src/test/test.js +++ b/src/test/test.js @@ -128,7 +128,7 @@ describe('request enrollments', () => { it('should list enrollments with valid dimensions', (done) => { chai.request(server) - .get('/api/v1/enrollment?dims=region,state,adm_dependency_id,location_id&filter=min_year:2014,region:4') + .get('/api/v1/enrollment?dims=region,state,adm_dependency,location&filter=min_year:2014,region:4') .end((err, res) => { res.should.have.status(200); res.should.be.json; @@ -137,6 +137,7 @@ describe('request enrollments', () => { res.body.result[0].should.have.property('region_name'); res.body.result[0].should.have.property('state_name'); res.body.result[0].should.have.property('adm_dependency_name'); + res.body.result[0].should.have.property('location_name'); res.body.result[0].should.have.property('total'); done(); }); @@ -158,7 +159,7 @@ describe('request enrollments', () => { it('should list enrollments with valid dimensions and filters', (done) => { chai.request(server) - .get('/api/v1/enrollment?dims=region,state,education_level_id,school&filter=min_year:2013,max_year:2014,city:3287') + .get('/api/v1/enrollment?dims=region,state,education_level,school&filter=min_year:2013,max_year:2014,city:4106902') .end((err, res) => { res.should.have.status(200); res.should.be.json; @@ -174,6 +175,26 @@ describe('request enrollments', () => { }); }); + it('should list enrollments using all dimensions and filters', (done) => { + chai.request(server) + .get('/api/v1/enrollment?dims=region,state,city,education_level,school,adm_dependency,location&filter=min_year:2013,max_year:2014,city:4106902,adm_dependency:3,location:1,education_level:99') + .end((err, res) => { + res.should.have.status(200); + res.should.be.json; + res.body.should.have.property('result'); + res.body.result.should.be.a('array'); + res.body.result[0].should.have.property('region_name'); + res.body.result[0].should.have.property('state_name'); + res.body.result[0].should.have.property('school_name'); + res.body.result[0].should.have.property('education_level'); + res.body.result[0].should.have.property('location_name'); + res.body.result[0].should.have.property('adm_dependency_name'); + res.body.result[0].should.have.property('total'); + res.body.result[0].should.have.property('year'); + done(); + }); + }); + }); @@ -265,42 +286,39 @@ describe('request cities', () => { res.should.be.json; res.body.should.have.property('result'); res.body.result.should.be.a('array'); - res.body.result[0].should.have.property('pk_municipio_id'); - res.body.result[0].should.have.property('fk_estado_id'); + res.body.result[0].should.have.property('pk_cod_ibge'); res.body.result[0].should.have.property('nome'); - res.body.result[0].should.have.property('codigo_ibge'); + res.body.result[0].should.have.property('fk_estado_id'); done(); }); }); it('should list a city by id', (done) => { chai.request(server) - .get('/api/v1/city/1') + .get('/api/v1/city/4106902') .end((err, res) => { res.should.have.status(200); res.should.be.json; res.body.should.have.property('result'); res.body.result.should.be.a('array'); - res.body.result[0].should.have.property('pk_municipio_id'); + res.body.result[0].should.have.property('pk_cod_ibge'); res.body.result[0].should.have.property('fk_estado_id'); res.body.result[0].should.have.property('nome'); - res.body.result[0].should.have.property('codigo_ibge'); done(); }); }); it('should list a city by codigo_ibge', (done) => { chai.request(server) - .get('/api/v1/city/ibge/1200013') + .get('/api/v1/city/ibge/4106902') .end((err, res) => { res.should.have.status(200); res.should.be.json; res.body.should.have.property('result'); res.body.result.should.be.a('array'); - res.body.result[0].should.have.property('pk_municipio_id'); + res.body.result[0].should.have.property('pk_cod_ibge'); res.body.result[0].should.have.property('fk_estado_id'); res.body.result[0].should.have.property('nome'); - res.body.result[0].should.have.property('codigo_ibge'); done(); }); }); @@ -313,10 +331,9 @@ describe('request cities', () => { res.should.be.json; res.body.should.have.property('result'); res.body.result.should.be.a('array'); - res.body.result[0].should.have.property('pk_municipio_id'); + res.body.result[0].should.have.property('pk_cod_ibge'); res.body.result[0].should.have.property('fk_estado_id'); res.body.result[0].should.have.property('nome'); - res.body.result[0].should.have.property('codigo_ibge'); done(); }) }) @@ -325,16 +342,14 @@ describe('request cities', () => { describe('request schools', () => { it('should list a school by id', (done) => { chai.request(server) - .get('/api/v1/school/185588') + .get('/api/v1/school/41000021') .end((err, res) => { res.should.have.status(200); res.should.be.json; res.body.should.have.property('result'); res.body.result.should.be.a('array'); - res.body.result[0].should.have.property('pk_escola_id'); res.body.result[0].should.have.property('ano_censo'); res.body.result[0].should.have.property('cod_entidade'); - res.body.result[0].should.have.property('nome_entidade'); done(); }); }); @@ -347,24 +362,22 @@ describe('request schools', () => { res.should.be.json; res.body.should.have.property('result'); res.body.result.should.be.a('array'); - res.body.result[0].should.have.property('pk_escola_id'); + res.body.result[0].should.have.property('cod_entidade'); res.body.result[0].should.have.property('ano_censo'); - res.body.result[0].should.have.property('nome_entidade'); done(); }); }); it('should list all schools from a city', (done) => { chai.request(server) - .get('/api/v1/school/city/3287') + .get('/api/v1/school/city/4106902') .end((err, res) => { res.should.have.status(200); res.should.be.json; res.body.should.have.property('result'); res.body.result.should.be.a('array'); - res.body.result[0].should.have.property('pk_escola_id'); + res.body.result[0].should.have.property('cod_entidade'); res.body.result[0].should.have.property('ano_censo'); - res.body.result[0].should.have.property('nome_entidade'); done(); }) }) @@ -784,6 +797,9 @@ describe('Saves a user', () => { beforeEach(() => { User.remove({}, (err) => { + if(err) { + console.log('Error while purging: ' + err); + } console.log('Test collection purged'); }); });