Skip to content

Commit

Permalink
Merge pull request #9 from analytics-ufcg/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
JoaquimCMH authored Jun 29, 2020
2 parents b0fa138 + acf7717 commit 8bd8bf4
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 43 deletions.
43 changes: 28 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,40 @@
# Monitor Cidadão (back-end)

# monitor-cidadao-backend
O Monitor Cidadão é um sistema desenvolvido através da parceria entre a CampinaTec e o laboratório Analytics da Universidade Federal de Campina Grande-PB com finalidade possibilitar aos cidadãos o acompanhamento dos contratos realizados pelos municípios do estado da Paraíba.



## Executando back-end
## Motivação

O projeto surge a partir da urgente necessidade de acompanhamento e fiscalização dos gastos públicos em licitações e contratos, com o intúito de facilitar o acesso da comunidade aos dados e o que eles representam.

A execução do back-end pode ser feita de duas maneiras: via **docker** ou executando diretamente com o **nodemon**.

Antes de tudo, para executar tanto manualmente quanto com o docker, adicione as informações do SQLServer SAGRES 2019 no .env (essas informações estão no arquivo '07 - Instruções e Acessos Monitor Cidadão') .
## Back-end

Aqui encontra-se o back-end da aplicação, que foi desenvolvido em Node JS. Funciona em conjunto com o front-end localizado nesse [repositório](https://github.com/analytics-ufcg/monitor-cidadao-frontend).


## Tecnologias/frameworks usados

- SQLSERVER_SAGRES19_HOST
<b>Desenvolvido com</b>

- SQLSERVER_SAGRES19_Database
- [JavaScript](https://www.javascript.com/)
- [Node JS](https://nodejs.org/en/about/)
- [Docker](https://www.docker.com/)

- SQLSERVER_SAGRES19_USER

- SQLSERVER_SAGRES19_PASS
## Executando o back-end

- SQLSERVER_SAGRES19_PORT
A execução do back-end pode ser feita de duas maneiras: via **docker** ou executando diretamente com o **nodemon**.

Antes de tudo, para executar tanto manualmente quanto com o docker, adicione as informações do SQLServer SAGRES 2019 no .env (essas informações estão no arquivo '07 - Instruções e Acessos Monitor Cidadão') .


### Executando back-end manualmente
- POSTGRES_HOST
- POSTGRES_DB
- POSTGRES_USER
- POSTGRES_PASSWORD
- POSTGRES_PORT

### Executando back-end manualmente

Caso queira executar o back-end sem o docker, garanta que você tenha instalado em sua máquina o **nodejs**, **npm** e o **nodemon**.

Expand All @@ -34,5 +46,6 @@ Você pode testar se tudo deu certo com o link abaixo:

> [http://localhost:3000/api/licitacoes](http://localhost:3000/api/licitacoes)
### Executando back-end via docker
O docker-compose está configurado para executar tanto o back-end quanto o front-end. Sendo assim, as instruções para executar ambos projetos foram adicionadas no **monitor-cidadao-frontend**.
### Executando back-end via docker
O docker-compose está configurado para executar tanto o back-end quanto o front-end. Sendo assim, as instruções para executar ambos projetos foram adicionadas no **Monitor Cidadão (front-end)**.

2 changes: 2 additions & 0 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const app = express();
// ==> Rotas da API:
const licitacoesRoute = require('./routes/licitacoes.routes');
const regioesRoute = require('./routes/regioes.routes');
const contratosRoute = require('./routes/contratos.routes');

app.use(express.urlencoded({ extended: true }));
app.use(express.json());
Expand All @@ -20,6 +21,7 @@ app.use(cors());
// Adicione novas rotas abaixo
app.use('/api/', licitacoesRoute);
app.use('/api/', regioesRoute);
app.use('/api/', contratosRoute);

module.exports = app;

Expand Down
16 changes: 7 additions & 9 deletions src/config/credentials.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@ require('dotenv').config({ path: path.resolve(__dirname, '../../.env') });

// configurações dos bancos de dados
module.exports = {
SAGRES: {
username: process.env.SQLSERVER_SAGRES19_USER,
host: process.env.SQLSERVER_SAGRES19_HOST,
database: process.env.SQLSERVER_SAGRES19_Database,
password: process.env.SQLSERVER_SAGRES19_PASS,
port: parseInt(process.env.SQLSERVER_SAGRES19_PORT),
driver: 'tedious',
stream: false,
dialect: 'mssql',
AL_DB: {
username: process.env.POSTGRES_USER,
host: process.env.POSTGRES_HOST,
database: process.env.POSTGRES_DB,
password: process.env.POSTGRES_PASSWORD,
port: process.env.POSTGRES_PORT,
dialect: 'postgres',
options: {
trustedConnection: true,
encrypt: false,
Expand Down
6 changes: 3 additions & 3 deletions src/config/db.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@
*/

const { Sequelize } = require('sequelize');
const { SAGRES } = require("./credentials");
const { AL_DB } = require("./credentials");

/** Adiciona as configurações específicas de um banco. Caso seja necessário mudar
o BD basta alterar o parâmetro do Sequelize.
*/
const sequelize = new Sequelize(SAGRES)
const sequelize = new Sequelize(AL_DB)

// Testa se a conexão foi estabelecida
run().catch(error => console.log(error.stack));
async function run() {
try {
await sequelize.authenticate();
console.log('Conexão estabelecida com o banco de dados ', SAGRES.database);
console.log('Conexão estabelecida com o banco de dados ', AL_DB.database);
} catch (error) {
console.error('Não foi possível conectar-se ao banco de dados:', error);
}
Expand Down
49 changes: 49 additions & 0 deletions src/controllers/contratos.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Arquivo: controllers/contratos.controller.js
* Descrição: arquivo responsável por recuperar informações relacionadas aos
* contratos.
*/

const models = require("../models/index.model");
const Contrato = models.contrato;
const Op = models.Sequelize.Op;

const BAD_REQUEST = 400;
const SUCCESS = 200;

// Retorna todas os contratos de um município
exports.getContratosPorMunicipio = (req, res) => {
const cd_municipio = req.query.cd_municipio

Contrato.findAll({ where: {
cd_municipio: cd_municipio
}})
.then(contratos => res.status(SUCCESS).json(contratos))
.catch(err => res.status(BAD_REQUEST).json({ err }));
};

// Recupera o contrato pelo ID
exports.getContratoById = (req, res) => {
const id = req.params.id

Contrato.findOne({
where: {
id_contrato: id
}
})
.then(contratos => res.json(contratos))
.catch(err => res.status(BAD_REQUEST).json({ err }));
}

// Recupera todos os contratos de uma licitação
exports.getContratosByLicitacao = (req, res) => {
const id_licitacao = req.params.id_licitacao

Contrato.findAll({
where: {
id_licitacao: id_licitacao
}
})
.then(contratos => res.json(contratos))
.catch(err => res.status(BAD_REQUEST).json({ err }));
}
32 changes: 28 additions & 4 deletions src/controllers/licitacoes.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,42 @@
*/

const models = require("../models/index.model");
const Contrato = models.contrato;
const Licitacao = models.licitacao;
const Op = models.Sequelize.Op;

const BAD_REQUEST = 400;
const SUCCESS = 200;

// Retorna as 10 primeiras licitações (terá mudanças)
exports.getLicitacoes = async (req, res) => {
Licitacao.findAll({limit: 100, where: { de_Obs: { [Op.ne]: null } }})
// Retorna todas as licitações não vazias de um município
exports.getLicitacoesPorMunicipio = (req, res) => {
const cd_municipio = req.query.cd_municipio

Licitacao.findAll({ where: {
cd_municipio: cd_municipio,
nu_licitacao: { [Op.ne]: '000000000'}
},

})
.then(licitacoes => res.status(SUCCESS).json(licitacoes))
.catch(err => res.status(BAD_REQUEST).json({ err }));
};

// Recupera a licitação pelo ID
exports.getLicitacaoById = (req, res) => {
const id = req.params.id


Licitacao.findOne({
include: [
{
model: Contrato,
as: "contratosLicitacao"
}
],
where: {
id_licitacao: id,
}
})
.then(licitacoes => res.json(licitacoes))
.catch(err => res.status(BAD_REQUEST).json({ err }));
}
41 changes: 41 additions & 0 deletions src/models/contrato.model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Arquivo: models/contrato.model.js
* Descrição: arquivo com o modelo do contrato.
*/

module.exports = (sequelize, type) => {
Contrato = sequelize.define(
"contrato",
{
id_contrato: {
type: type.STRING,
primaryKey: true
},
id_licitacao: type.STRING,
cd_municipio: type.STRING,
cd_u_gestora: type.INTEGER,
dt_ano: type.INTEGER,
nu_contrato: type.STRING,
dt_assinatura: type.DATE,
pr_vigencia: type.DATE,
nu_cpfcnpj: type.STRING,
nu_licitacao: type.STRING,
tp_licitacao: type.INTEGER,
vl_total_contrato: type.INTEGER,
de_obs: type.STRING,
dt_mes_ano: type.STRING,
registro_cge: type.STRING,
cd_siafi: type.STRING,
dt_recebimento: type.DATE,
foto: type.STRING,
planilha: type.STRING,
ordem_servico : type.STRING
},
{
freezeTableName: true,
timestamps: false
}

);
return Contrato;
};
8 changes: 8 additions & 0 deletions src/models/index.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@ const { sequelize } = require("../config/db.config");

const LicitacaoModel = "./licitacao.model.js";
const MunicipioModel = "./municipio.model.js";
const ContratoModel = "./contrato.model.js";

global.models = {
Sequelize: Sequelize,
sequelize: sequelize,
// Adicione os módulos abaixo
licitacao: sequelize.import(LicitacaoModel),
municipio: sequelize.import(MunicipioModel),
contrato: sequelize.import(ContratoModel)
};

Object.keys(global.models).forEach(modelName => {
if (global.models[modelName].associate !== undefined) {
global.models[modelName].associate(global.models);
}
});

module.exports = global.models;
26 changes: 21 additions & 5 deletions src/models/licitacao.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,37 @@

module.exports = (sequelize, type) => {
Licitacao = sequelize.define(
"Licitacao",
"licitacao",
{
nu_licitacao: { // deixei este como PK por enquanto
id_licitacao: {
type: type.STRING,
primaryKey: true
},
cd_UGestora: type.INTEGER,
cd_municipio: type.STRING,
cd_u_gestora: type.INTEGER,
dt_ano: type.INTEGER,
nu_licitacao: type.STRING,
tp_licitacao: type.INTEGER,
dt_homologacao: type.DATE,
nu_propostas: type.INTEGER,
vl_licitacao: type.INTEGER,
de_Obs: type.STRING,
tp_objeto: type.INTEGER,
de_obs: type.STRING,
dt_mes_ano: type.STRING,
registro_cge: type.STRING,
tp_regime_execucao: type.INTEGER
},
{
freezeTableName: true,
timestamps: false
}
);

Licitacao.associate = function (models) {
Licitacao.hasMany(models.contrato, {
foreignKey: "id_licitacao",
sourceKey: "id_licitacao",
as: "contratosLicitacao"
});
}
return Licitacao;
};
13 changes: 9 additions & 4 deletions src/models/municipio.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@

module.exports = (sequelize, type) => {
Municipio = sequelize.define(
"Codigo_Municipios",
"municipio",
{
cd_Municipio: {
cd_municipio: {
type: type.STRING,
primaryKey: true
},
cd_Ibge: type.STRING,
no_Municipio: type.STRING,
cd_ibge: type.INTEGER,
no_municipio: type.STRING,
dt_ano_criacao: type.DATE,
cd_regiao_administrativa: type.STRING,
cd_micro_regiao: type.STRING,
cd_meso_regiao: type.STRING

},
{
freezeTableName: true,
Expand Down
21 changes: 21 additions & 0 deletions src/routes/contratos.routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Arquivo: src/routes/contratos.routes.js
* Descrição: arquivo responsável pelas rotas da api relacionadas a classe 'Contratos'.
*/

const router = require('express-promise-router')();
const contratosController = require('../controllers/contratos.controller');

// Busca todos os contratos de um município
// Exemplo: http://localhost:3000/api/contratos/municipio?cd_municipio=012
router.get('/contratos/municipio', contratosController.getContratosPorMunicipio)

// Busca um contrato pelo seu ID
// Exemplo: http://localhost:3000/api/contratos/e233520a006288d0caaf70f5bea2f64b
router.get('/contratos/:id', contratosController.getContratoById)

// Busca todos os contratos de uma licitação
// Exemplo: http://localhost:3000/api/licitacoes/b06aa4ae558ddaaaeecac2ca4aa2e186/contratos
router.get('/licitacoes/:id_licitacao/contratos', contratosController.getContratosByLicitacao)

module.exports = router;
10 changes: 7 additions & 3 deletions src/routes/licitacoes.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
const router = require('express-promise-router')();
const licitacoesController = require('../controllers/licitacoes.controller');

// Retorna todas as licitacoes
// Exemplo: http://localhost:3000/api/licitacoes
router.get('/licitacoes', licitacoesController.getLicitacoes)
// Retorna todas as licitacoes de um município
// Exemplo: http://localhost:3000/api/licitacoes/municipio?cd_municipio=012
router.get('/licitacoes/municipio', licitacoesController.getLicitacoesPorMunicipio)

// Busca a licitação pelo seu ID
// Exemplo: http://localhost:3000/api/licitacoes/03f8384d87a7f7c7c8eea7670366d670
router.get('/licitacoes/:id', licitacoesController.getLicitacaoById)

module.exports = router;

0 comments on commit 8bd8bf4

Please sign in to comment.