├── server ├── config │ ├── .Rhistory │ ├── keys.js │ └── passport.js ├── utils │ ├── middlewares │ │ └── casa.validator.js │ └── token.utils.js ├── models │ └── postgres │ │ ├── resposta.js │ │ ├── comissoes.js │ │ ├── perfil-mais.js │ │ ├── empresas.js │ │ ├── voto.js │ │ ├── orientacao.js │ │ ├── proposicao_temas.js │ │ ├── votacao.js │ │ ├── liderancas.js │ │ ├── pergunta.js │ │ ├── tema.js │ │ ├── investimento-partidario.js │ │ ├── atividades-economicas.js │ │ ├── empresas-parlamentares.js │ │ ├── proposicao.js │ │ ├── atividades-economicas-empresas.js │ │ ├── ligacoes-economicas.js │ │ ├── composicao-comissoes.js │ │ ├── votacaou.js │ │ ├── candidato.js │ │ ├── aderencia.js │ │ ├── respostasU.js │ │ ├── investimento-partidario-parlamentar.js │ │ └── partidos.js └── routes │ └── api │ ├── temas.js │ └── swagger.js ├── client ├── src │ ├── assets │ │ ├── .gitkeep │ │ ├── imgs │ │ │ ├── logo.png │ │ │ ├── g-logo.png │ │ │ ├── howto01.jpg │ │ │ ├── howto02.jpg │ │ │ ├── logo_ufcg.jpg │ │ │ ├── nophoto.png │ │ │ ├── okbr-logo.png │ │ │ ├── parlametria.png │ │ │ └── logo_dadocapital.jpg │ │ ├── icons │ │ │ ├── 32x32.png │ │ │ ├── 48x48.png │ │ │ ├── 96x96.png │ │ │ ├── 128x128.png │ │ │ ├── 144x144.png │ │ │ ├── 152x152.png │ │ │ ├── 168x168.png │ │ │ ├── 180x180.png │ │ │ ├── 192x192.png │ │ │ └── 512x512.png │ │ ├── fonts │ │ │ ├── icomoon.eot │ │ │ ├── icomoon.ttf │ │ │ └── icomoon.woff │ │ └── styles │ │ │ └── animations.scss │ ├── robots.txt │ ├── app │ │ ├── parlamentar │ │ │ ├── cargos │ │ │ │ ├── cargos.component.scss │ │ │ │ ├── cargos.component.spec.ts │ │ │ │ └── cargos.component.html │ │ │ ├── patrimonio │ │ │ │ ├── patrimonio.component.scss │ │ │ │ ├── patrimonio.component.spec.ts │ │ │ │ └── patrimonio.component.html │ │ │ ├── trajetoria │ │ │ │ ├── trajetoria.component.scss │ │ │ │ ├── trajetoria.component.spec.ts │ │ │ │ └── trajetoria.component.html │ │ │ ├── posicoes │ │ │ │ ├── posicoes.component.scss │ │ │ │ ├── posicoes.component.spec.ts │ │ │ │ └── posicoes.component.html │ │ │ ├── capital │ │ │ │ ├── capital.component.scss │ │ │ │ └── capital.component.spec.ts │ │ │ ├── cargo │ │ │ │ ├── cargo.component.scss │ │ │ │ ├── cargo.component.html │ │ │ │ ├── cargo.component.spec.ts │ │ │ │ └── cargo.component.ts │ │ │ ├── aderencia │ │ │ │ ├── aderencia.component.scss │ │ │ │ └── aderencia.component.spec.ts │ │ │ ├── votacoes │ │ │ │ ├── votacoes.component.scss │ │ │ │ └── votacoes.component.spec.ts │ │ │ ├── vinculos-chart │ │ │ │ ├── vinculos-chart.component.scss │ │ │ │ └── vinculos-chart.component.spec.ts │ │ │ ├── parlamentar.component.scss │ │ │ ├── posicao │ │ │ │ ├── posicao.component.scss │ │ │ │ ├── posicao.component.ts │ │ │ │ └── posicao.component.spec.ts │ │ │ ├── despesas-cota-parlamentar │ │ │ │ ├── despesas-cota-parlamentar.component.scss │ │ │ │ └── despesas-cota-parlamentar.component.spec.ts │ │ │ ├── votacao │ │ │ │ ├── votacao.component.spec.ts │ │ │ │ └── votacao.component.scss │ │ │ ├── vinculos │ │ │ │ ├── vinculos.component.spec.ts │ │ │ │ └── vinculos.component.scss │ │ │ ├── parlamentar.component.spec.ts │ │ │ ├── card-empresa │ │ │ │ ├── card-empresa.component.spec.ts │ │ │ │ ├── card-empresa.component.ts │ │ │ │ └── card-empresa.component.html │ │ │ ├── capital-chart │ │ │ │ └── capital-chart.component.spec.ts │ │ │ ├── card-reembolso │ │ │ │ ├── card-reembolso.component.spec.ts │ │ │ │ └── card-reembolso.component.ts │ │ │ ├── patrimonio-chart │ │ │ │ ├── patrimonio-chart.component.spec.ts │ │ │ │ └── patrimonio-chart.component.scss │ │ │ └── trajetoria-timeline │ │ │ │ └── trajetoria-timeline.component.spec.ts │ │ ├── questionario │ │ │ ├── questionario.component.scss │ │ │ ├── questionario.component.html │ │ │ ├── temas │ │ │ │ ├── temas.component.scss │ │ │ │ ├── temas.component.spec.ts │ │ │ │ └── temas.component.html │ │ │ ├── pergunta │ │ │ │ ├── pergunta.component.ts │ │ │ │ ├── pergunta.component.scss │ │ │ │ ├── pergunta.component.html │ │ │ │ └── pergunta.component.spec.ts │ │ │ ├── questionario-routing.module.ts │ │ │ ├── questionario.component.spec.ts │ │ │ ├── perguntas-container │ │ │ │ ├── perguntas-container.component.spec.ts │ │ │ │ └── perguntas-container.component.scss │ │ │ └── questionario.module.ts │ │ ├── shared │ │ │ ├── models │ │ │ │ ├── lideranca.model.ts │ │ │ │ ├── countVotacao.model.ts │ │ │ │ ├── partido.model.ts │ │ │ │ ├── resposta.model.ts │ │ │ │ ├── tema.model.ts │ │ │ │ ├── comissao.model.ts │ │ │ │ ├── temasUsuario.model.ts │ │ │ │ ├── orientacao.model.ts │ │ │ │ ├── parlamentarVotos.model.ts │ │ │ │ ├── pergunta.model.ts │ │ │ │ ├── parlamentarPosicao.model.ts │ │ │ │ ├── partidoInvestimento.model.ts │ │ │ │ ├── parlamentarComissoes.model.ts │ │ │ │ ├── composicaoComissao.model.ts │ │ │ │ ├── parlamentarLiderancas.model.ts │ │ │ │ ├── proposicao.model.ts │ │ │ │ ├── aderencia.model.ts │ │ │ │ ├── parlamentarInvestimento.model.ts │ │ │ │ ├── parlamentar.model.ts │ │ │ │ └── parlamentarInfo.model.ts │ │ │ ├── components │ │ │ │ ├── legend │ │ │ │ │ ├── legend.component.html │ │ │ │ │ ├── legend.component.scss │ │ │ │ │ ├── legend.component.spec.ts │ │ │ │ │ └── legend.component.ts │ │ │ │ ├── loading │ │ │ │ │ ├── loading.component.scss │ │ │ │ │ ├── loading.component.ts │ │ │ │ │ └── loading.component.spec.ts │ │ │ │ ├── footer │ │ │ │ │ ├── footer.component.scss │ │ │ │ │ ├── footer.component.ts │ │ │ │ │ ├── footer.component.html │ │ │ │ │ └── footer.component.spec.ts │ │ │ │ ├── progress │ │ │ │ │ ├── progress.component.scss │ │ │ │ │ ├── progress.component.html │ │ │ │ │ ├── progress.component.ts │ │ │ │ │ └── progress.component.spec.ts │ │ │ │ ├── progress-stacked │ │ │ │ │ ├── progress-stacked.component.scss │ │ │ │ │ ├── progress-stacked.component.ts │ │ │ │ │ ├── progress-stacked.component.spec.ts │ │ │ │ │ └── progress-stacked.component.html │ │ │ │ ├── sticky-footer-navbar │ │ │ │ │ ├── sticky-footer-navbar.component.scss │ │ │ │ │ ├── sticky-footer-navbar.component.html │ │ │ │ │ ├── sticky-footer-navbar.component.ts │ │ │ │ │ └── sticky-footer-navbar.component.spec.ts │ │ │ │ ├── navbar │ │ │ │ │ ├── navbar.component.spec.ts │ │ │ │ │ ├── navbar.component.scss │ │ │ │ │ └── navbar.component.ts │ │ │ │ └── shared.module.ts │ │ │ ├── functions │ │ │ │ └── comissao.ts │ │ │ ├── services │ │ │ │ ├── tema.service.spec.ts │ │ │ │ ├── user.service.spec.ts │ │ │ │ ├── casa.service.spec.ts │ │ │ │ ├── login.service.spec.ts │ │ │ │ ├── jarbas.service.spec.ts │ │ │ │ ├── update.service.spec.ts │ │ │ │ ├── votacao.service.spec.ts │ │ │ │ ├── comissao.service.spec.ts │ │ │ │ ├── pergunta.service.spec.ts │ │ │ │ ├── aderencia.service.spec.ts │ │ │ │ ├── auth-guard.service.spec.ts │ │ │ │ ├── lideranca.service.spec.ts │ │ │ │ ├── orientacao.service.spec.ts │ │ │ │ ├── alinhamento.service.spec.ts │ │ │ │ ├── parlamentar.service.spec.ts │ │ │ │ ├── perfil-politico.service.spec.ts │ │ │ │ ├── busca-parlamentar.service.spec.ts │ │ │ │ ├── auth-guard.service.ts │ │ │ │ ├── lideranca.service.ts │ │ │ │ ├── pergunta.service.ts │ │ │ │ ├── update.service.ts │ │ │ │ ├── votacao.service.ts │ │ │ │ ├── orientacao.service.ts │ │ │ │ ├── comissao.service.ts │ │ │ │ ├── perfil-politico.service.ts │ │ │ │ ├── casa.service.ts │ │ │ │ ├── tema.service.ts │ │ │ │ └── jarbas.service.ts │ │ │ ├── constants │ │ │ │ └── estados.js │ │ │ ├── config │ │ │ │ └── socialLoginConfig.ts │ │ │ └── auth │ │ │ │ └── token.interceptor.ts │ │ ├── aderencia │ │ │ ├── congresso-chart-legenda │ │ │ │ ├── congresso-chart-legenda.component.scss │ │ │ │ ├── congresso-chart-legenda.component.ts │ │ │ │ ├── congresso-chart-legenda.component.spec.ts │ │ │ │ └── congresso-chart-legenda.component.html │ │ │ ├── aderencia-routing.module.ts │ │ │ ├── aderencia-parlamentares │ │ │ │ ├── aderencia-parlamentares.component.scss │ │ │ │ ├── aderencia-parlamentares.component.spec.ts │ │ │ │ └── aderencia-parlamentares.component.ts │ │ │ ├── aderencia.component.spec.ts │ │ │ ├── congresso-chart │ │ │ │ ├── congresso-chart.component.spec.ts │ │ │ │ └── congresso-chart.component.scss │ │ │ ├── card-parlamentar │ │ │ │ └── card-parlamentar.component.spec.ts │ │ │ ├── aderencia.component.scss │ │ │ └── aderencia.module.ts │ │ ├── busca-parlamentar │ │ │ ├── lista-parlamentares │ │ │ │ ├── lista-parlamentares.component.scss │ │ │ │ ├── lista-parlamentares.component.spec.ts │ │ │ │ └── lista-parlamentares.component.ts │ │ │ ├── busca-parlamentar.component.scss │ │ │ ├── busca-parlamentar-routing.module.ts │ │ │ ├── card-busca-parlamentar │ │ │ │ ├── card-busca-parlamentar.component.ts │ │ │ │ ├── card-busca-parlamentar.component.spec.ts │ │ │ │ └── card-busca-parlamentar.component.html │ │ │ ├── busca-parlamentar.component.spec.ts │ │ │ └── busca-parlamentar.module.ts │ │ ├── app.component.scss │ │ ├── main │ │ │ ├── home │ │ │ │ ├── home.component.scss │ │ │ │ ├── home.component.spec.ts │ │ │ │ ├── home.component.ts │ │ │ │ └── home.component.html │ │ │ ├── sobre │ │ │ │ ├── sobre.component.ts │ │ │ │ └── sobre.component.spec.ts │ │ │ ├── main-routing.module.ts │ │ │ └── main.module.ts │ │ ├── app.component.html │ │ ├── alinhamento │ │ │ ├── alinhamento.component.scss │ │ │ ├── alinhamento-routing.module.ts │ │ │ ├── congresso-alinhamento │ │ │ │ ├── congresso-alinhamento.component.scss │ │ │ │ └── congresso-alinhamento.component.spec.ts │ │ │ ├── alinhamento.component.spec.ts │ │ │ ├── card-parlamentar │ │ │ │ └── card-parlamentar.component.spec.ts │ │ │ └── alinhamento.module.ts │ │ ├── filter │ │ │ ├── filter.component.scss │ │ │ ├── filter.module.ts │ │ │ └── filter.component.spec.ts │ │ ├── user │ │ │ ├── user.module.ts │ │ │ ├── user-routing.module.ts │ │ │ └── login │ │ │ │ ├── login.component.spec.ts │ │ │ │ ├── login.component.ts │ │ │ │ └── login.component.scss │ │ ├── app-routing-animation.ts │ │ ├── app.component.spec.ts │ │ ├── app-routing.module.ts │ │ └── app.component.ts │ ├── favicon.ico │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ ├── tslint.json │ ├── main.ts │ ├── test.ts │ ├── karma.conf.js │ ├── ngsw-config.json │ └── manifest.json ├── .dockerignore ├── Dockerfile ├── e2e │ ├── tsconfig.e2e.json │ ├── src │ │ ├── app.po.ts │ │ └── app.e2e-spec.ts │ └── protractor.conf.js ├── .editorconfig ├── browserslist ├── tsconfig.json ├── .gitignore └── README.md ├── .dockerignore ├── Dockerfile ├── .gitignore ├── .travis.yml ├── variables.env.sample ├── docker-compose.yml ├── .github └── workflows │ └── perfil-workflow.yml └── docs └── README.md /server/config/.Rhistory: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log -------------------------------------------------------------------------------- /client/src/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / 3 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | client/ 3 | npm-debug.log -------------------------------------------------------------------------------- /client/src/app/parlamentar/cargos/cargos.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/app/questionario/questionario.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/patrimonio/patrimonio.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/trajetoria/trajetoria.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/posicoes/posicoes.component.scss: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /client/src/app/shared/models/lideranca.model.ts: -------------------------------------------------------------------------------- 1 | export interface Lideranca { 2 | cargo: string; 3 | } 4 | -------------------------------------------------------------------------------- /client/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/favicon.ico -------------------------------------------------------------------------------- /client/src/app/shared/models/countVotacao.model.ts: -------------------------------------------------------------------------------- 1 | export interface CountVotacao { 2 | numeroVotacoes: number; 3 | } 4 | -------------------------------------------------------------------------------- /client/src/app/shared/models/partido.model.ts: -------------------------------------------------------------------------------- 1 | export interface Partido { 2 | idPartido: number; 3 | sigla: string; 4 | } 5 | -------------------------------------------------------------------------------- /client/src/assets/imgs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/imgs/logo.png -------------------------------------------------------------------------------- /client/src/app/shared/models/resposta.model.ts: -------------------------------------------------------------------------------- 1 | export interface Resposta { 2 | vozAtiva: object; 3 | votacoes: object; 4 | } 5 | -------------------------------------------------------------------------------- /client/src/assets/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/icons/32x32.png -------------------------------------------------------------------------------- /client/src/assets/icons/48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/icons/48x48.png -------------------------------------------------------------------------------- /client/src/assets/icons/96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/icons/96x96.png -------------------------------------------------------------------------------- /client/src/assets/imgs/g-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/imgs/g-logo.png -------------------------------------------------------------------------------- /client/src/app/parlamentar/capital/capital.component.scss: -------------------------------------------------------------------------------- 1 | .capital-chart-wrapper { 2 | margin: auto; 3 | max-width: 300px; 4 | } 5 | -------------------------------------------------------------------------------- /client/src/app/shared/models/tema.model.ts: -------------------------------------------------------------------------------- 1 | export interface Tema { 2 | idTema: number; 3 | tema: string; 4 | slug: string; 5 | } 6 | -------------------------------------------------------------------------------- /client/src/assets/fonts/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/fonts/icomoon.eot -------------------------------------------------------------------------------- /client/src/assets/fonts/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/fonts/icomoon.ttf -------------------------------------------------------------------------------- /client/src/assets/fonts/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/fonts/icomoon.woff -------------------------------------------------------------------------------- /client/src/assets/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/icons/128x128.png -------------------------------------------------------------------------------- /client/src/assets/icons/144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/icons/144x144.png -------------------------------------------------------------------------------- /client/src/assets/icons/152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/icons/152x152.png -------------------------------------------------------------------------------- /client/src/assets/icons/168x168.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/icons/168x168.png -------------------------------------------------------------------------------- /client/src/assets/icons/180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/icons/180x180.png -------------------------------------------------------------------------------- /client/src/assets/icons/192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/icons/192x192.png -------------------------------------------------------------------------------- /client/src/assets/icons/512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/icons/512x512.png -------------------------------------------------------------------------------- /client/src/assets/imgs/howto01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/imgs/howto01.jpg -------------------------------------------------------------------------------- /client/src/assets/imgs/howto02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/imgs/howto02.jpg -------------------------------------------------------------------------------- /client/src/assets/imgs/logo_ufcg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/imgs/logo_ufcg.jpg -------------------------------------------------------------------------------- /client/src/assets/imgs/nophoto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/imgs/nophoto.png -------------------------------------------------------------------------------- /client/src/assets/imgs/okbr-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/imgs/okbr-logo.png -------------------------------------------------------------------------------- /client/src/assets/imgs/parlametria.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/imgs/parlametria.png -------------------------------------------------------------------------------- /client/src/assets/imgs/logo_dadocapital.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parlametria/perfil-parlamentar/HEAD/client/src/assets/imgs/logo_dadocapital.jpg -------------------------------------------------------------------------------- /client/src/app/shared/models/comissao.model.ts: -------------------------------------------------------------------------------- 1 | export interface Comissao { 2 | idComissaoVoz: string; 3 | sigla: string; 4 | nome: string; 5 | } 6 | -------------------------------------------------------------------------------- /client/src/app/shared/models/temasUsuario.model.ts: -------------------------------------------------------------------------------- 1 | export interface TemasUsuario { 2 | usuario_id: number; 3 | temas_preferidos: Array; 4 | } 5 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10-alpine 2 | 3 | WORKDIR /app 4 | 5 | COPY package* ./ 6 | 7 | RUN npm install 8 | 9 | EXPOSE 5000 10 | 11 | CMD npm run server -------------------------------------------------------------------------------- /client/src/app/shared/models/orientacao.model.ts: -------------------------------------------------------------------------------- 1 | export interface Orientacao { 2 | idPartido: number; 3 | sigla: string; 4 | orientacoes: any; 5 | } 6 | -------------------------------------------------------------------------------- /client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10-alpine 2 | 3 | WORKDIR /app/client 4 | 5 | COPY package* ./ 6 | 7 | RUN npm install 8 | 9 | EXPOSE 4200 10 | 11 | CMD npm run start -------------------------------------------------------------------------------- /client/src/app/shared/models/parlamentarVotos.model.ts: -------------------------------------------------------------------------------- 1 | export interface ParlamentarVotos { 2 | idParlamentarVoz: string; 3 | genero: string; 4 | votos: any; 5 | } 6 | -------------------------------------------------------------------------------- /client/src/app/aderencia/congresso-chart-legenda/congresso-chart-legenda.component.scss: -------------------------------------------------------------------------------- 1 | .subtitle-wrapper { 2 | height: 50px; 3 | } 4 | 5 | .subtitle { 6 | flex-wrap: wrap; 7 | } 8 | -------------------------------------------------------------------------------- /client/src/app/shared/components/legend/legend.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
{{ title }}
4 |
5 | -------------------------------------------------------------------------------- /client/src/app/shared/models/pergunta.model.ts: -------------------------------------------------------------------------------- 1 | import { Tema } from './tema.model'; 2 | 3 | export interface Pergunta { 4 | id: number; 5 | texto: number; 6 | tema_perg: Tema; 7 | } 8 | -------------------------------------------------------------------------------- /client/src/app/shared/models/parlamentarPosicao.model.ts: -------------------------------------------------------------------------------- 1 | export interface ParlamentarPosicao { 2 | idParlamentarVoz: string; 3 | genero: string; 4 | votacoes: any; 5 | votos: any; 6 | } 7 | -------------------------------------------------------------------------------- /client/src/app/busca-parlamentar/lista-parlamentares/lista-parlamentares.component.scss: -------------------------------------------------------------------------------- 1 | .parlamentar-lista { 2 | @media (min-width: 992px) { 3 | width: 760px; 4 | margin: auto; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /client/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | #page-container { 2 | position: relative; 3 | min-height: 100vh; 4 | background-color: #fff; 5 | } 6 | 7 | #content-wrap { 8 | padding-bottom: 150px; 9 | } 10 | -------------------------------------------------------------------------------- /client/src/app/main/home/home.component.scss: -------------------------------------------------------------------------------- 1 | .home { 2 | height: 50vh; 3 | display: flex; 4 | align-items: center; 5 | 6 | @media (max-width: 575.98px) { 7 | height: 80vh; 8 | } 9 | } -------------------------------------------------------------------------------- /client/src/app/shared/models/partidoInvestimento.model.ts: -------------------------------------------------------------------------------- 1 | export interface PartidoInvestimento { 2 | idPartido: number; 3 | uf: string; 4 | esfera: string; 5 | valor: number; 6 | numero_candidatos: number; 7 | } 8 | -------------------------------------------------------------------------------- /client/src/app/shared/models/parlamentarComissoes.model.ts: -------------------------------------------------------------------------------- 1 | import { ComposicaoComissao } from './composicaoComissao.model'; 2 | 3 | export interface ParlamentarComissoes { 4 | idParlamentarVoz: string; 5 | parlamentarComissoes: ComposicaoComissao[]; 6 | } 7 | -------------------------------------------------------------------------------- /client/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | apiUrl: './api/', 4 | facebookAppID: '2339282366084079', 5 | googleAppID: '791030988243-msi1r67ltvd5v1fjtajj3un1f0c0d7ds.apps.googleusercontent.com' 6 | }; 7 | -------------------------------------------------------------------------------- /client/src/app/shared/models/composicaoComissao.model.ts: -------------------------------------------------------------------------------- 1 | interface ComissaoInfo { 2 | sigla: string; 3 | nome?: string; 4 | } 5 | 6 | export interface ComposicaoComissao { 7 | idComissaoVoz: string; 8 | cargo: string; 9 | infoComissao: ComissaoInfo; 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | config/keys_dev.js 3 | variables.env 4 | 5 | # IDE 6 | .idea 7 | .vscode/ 8 | *.iml 9 | 10 | # Vim 11 | [._]*.s[a-v][a-z] 12 | [._]*.sw[a-p] 13 | [._]s[a-rt-v][a-z] 14 | [._]ss[a-gi-z] 15 | [._]sw[a-p] 16 | 17 | Session.vim 18 | Sessionx.vim 19 | -------------------------------------------------------------------------------- /client/src/app/shared/models/parlamentarLiderancas.model.ts: -------------------------------------------------------------------------------- 1 | interface CargoLideranca { 2 | cargo: string; 3 | blocoPartido: string; 4 | } 5 | 6 | export interface ParlamentarLiderancas { 7 | idParlamentarVoz: string; 8 | parlamentarLiderancas: CargoLideranca[]; 9 | } 10 | -------------------------------------------------------------------------------- /client/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /client/src/app/parlamentar/cargo/cargo.component.scss: -------------------------------------------------------------------------------- 1 | .parlamentar-cargos { 2 | font-size: 0.9rem; 3 | } 4 | 5 | .cargos { 6 | border-left: solid 2px #20201E; 7 | } 8 | 9 | .badge-cargos { 10 | font-size: 0.8rem; 11 | } 12 | 13 | .cargos-title { 14 | font-size: 0.8rem; 15 | } 16 | -------------------------------------------------------------------------------- /client/src/app/shared/components/loading/loading.component.scss: -------------------------------------------------------------------------------- 1 | .app-loading-wrapper { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | } 6 | 7 | .app-loading-wrapper-lg { 8 | height: 80vh; 9 | } 10 | 11 | .app-logo-wrapper { 12 | width: 125px; 13 | } 14 | -------------------------------------------------------------------------------- /client/src/app/shared/models/proposicao.model.ts: -------------------------------------------------------------------------------- 1 | import { Tema } from './tema.model'; 2 | 3 | export interface Proposicao { 4 | projetoLei: string; 5 | idProposicao: number; 6 | casa: string; 7 | titulo: string; 8 | descricao: string; 9 | temas: Tema[]; 10 | proposicaoVotacoes: any[]; 11 | } 12 | -------------------------------------------------------------------------------- /client/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "main.ts", 9 | "polyfills.ts" 10 | ], 11 | "exclude": [ 12 | "test.ts", 13 | "**/*.spec.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /client/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /client/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/aderencia/aderencia.component.scss: -------------------------------------------------------------------------------- 1 | .subtitle { 2 | flex-wrap: wrap; 3 | } 4 | 5 | .progress-bar-aderencia { 6 | width: 100%; 7 | } 8 | 9 | .aderencia-value { 10 | font-size: 2rem; 11 | font-weight: 700; 12 | } 13 | 14 | .aderencia-value-text { 15 | line-height: 2.7rem; 16 | } 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "10" 4 | dist: trusty 5 | sudo: required 6 | branches: 7 | only: 8 | - master 9 | - /^sprint-.*$/ 10 | before_install: 11 | - cd client/ 12 | install: 13 | - npm install 14 | before_script: 15 | - npm install -g @angular/cli 16 | script: 17 | - ng lint 18 | - ng build --prod -------------------------------------------------------------------------------- /variables.env.sample: -------------------------------------------------------------------------------- 1 | NODE_ENV=development 2 | SECRET_OR_KEY=secret 3 | POSTGRESURI=postgres://postgres:secret@postgres:5432/vozativa 4 | FACEBOOK_APP_ID=9999999999999999 5 | FACEBOOK_APP_SECRET=12345678912345678912345678912345 6 | GOOGLE_APP_ID=123456789123-abcdefghijklmnopkrstuvxyzabcdefg.apps.googleusercontent.com 7 | GOOGLE_APP_SECRET=123456789123456789123456 -------------------------------------------------------------------------------- /client/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "test.ts", 12 | "polyfills.ts" 13 | ], 14 | "include": [ 15 | "**/*.spec.ts", 16 | "**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /client/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 9 |
10 |
11 | 12 |
13 | -------------------------------------------------------------------------------- /client/src/app/main/sobre/sobre.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-sobre', 5 | templateUrl: './sobre.component.html', 6 | styleUrls: ['./sobre.component.scss'] 7 | }) 8 | export class SobreComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /client/src/app/shared/components/footer/footer.component.scss: -------------------------------------------------------------------------------- 1 | .footer { 2 | position: absolute; 3 | bottom: 0; 4 | width: 100%; 5 | height: 120px; 6 | display: flex; 7 | align-items: center; 8 | background-color: #f5f5f5; 9 | 10 | @media (min-width: 576px) { 11 | height: 150px; 12 | } 13 | } 14 | 15 | .footer-imgs { 16 | max-width: 135px; 17 | } 18 | -------------------------------------------------------------------------------- /client/src/app/shared/components/footer/footer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-footer', 5 | templateUrl: './footer.component.html', 6 | styleUrls: ['./footer.component.scss'] 7 | }) 8 | export class FooterComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /client/src/app/questionario/questionario.component.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /client/src/app/shared/functions/comissao.ts: -------------------------------------------------------------------------------- 1 | export function getClassCargo(cargo: string) { 2 | if (cargo !== undefined && cargo !== '') { 3 | if (cargo === 'Titular') { 4 | return 'badge-gray'; 5 | } else if (cargo === 'Suplente') { 6 | return 'badge-white'; 7 | } else { 8 | return 'badge-dark-gray'; 9 | } 10 | } else { 11 | return ''; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /client/src/app/alinhamento/alinhamento.component.scss: -------------------------------------------------------------------------------- 1 | .parlamentar-count { 2 | line-height: 2; 3 | } 4 | 5 | .parlamentar-lista { 6 | @media (min-width: 992px) { 7 | width: 760px; 8 | margin: auto; 9 | } 10 | } 11 | 12 | .btn-toolbar { 13 | line-height: 2.2rem; 14 | justify-content: flex-end; 15 | 16 | @media (min-width: 992px) { 17 | justify-content: center; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /client/src/app/filter/filter.component.scss: -------------------------------------------------------------------------------- 1 | .filter-body { 2 | display: flex; 3 | flex-direction: column; 4 | justify-content: space-between; 5 | } 6 | 7 | .temas-wrapper { 8 | display: flex; 9 | justify-content: center; 10 | } 11 | 12 | .temas-container { 13 | display: flex; 14 | overflow-x: auto; 15 | } 16 | 17 | .btn-tema-sm { 18 | min-height: 86px; 19 | width: 118px; 20 | } 21 | -------------------------------------------------------------------------------- /client/src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "app", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "app", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /client/src/app/aderencia/congresso-chart-legenda/congresso-chart-legenda.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-congresso-chart-legenda', 5 | templateUrl: './congresso-chart-legenda.component.html', 6 | styleUrls: ['./congresso-chart-legenda.component.scss'] 7 | }) 8 | export class CongressoChartLegendaComponent { 9 | 10 | constructor() { } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /client/src/app/shared/services/tema.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { TemaService } from './tema.service'; 4 | 5 | describe('TemaService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: TemaService = TestBed.get(TemaService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/app/shared/services/user.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { UserService } from './user.service'; 4 | 5 | describe('UserService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: UserService = TestBed.get(UserService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/app/shared/constants/estados.js: -------------------------------------------------------------------------------- 1 | export const estados = [ 2 | 'Estados', 3 | 'AC', 4 | 'AL', 5 | 'AM', 6 | 'AP', 7 | 'BA', 8 | 'CE', 9 | 'DF', 10 | 'ES', 11 | 'GO', 12 | 'MA', 13 | 'MT', 14 | 'MS', 15 | 'MG', 16 | 'PA', 17 | 'PB', 18 | 'PR', 19 | 'PE', 20 | 'PI', 21 | 'RJ', 22 | 'RN', 23 | 'RO', 24 | 'RS', 25 | 'RR', 26 | 'SC', 27 | 'SE', 28 | 'SP', 29 | 'TO' 30 | ]; -------------------------------------------------------------------------------- /client/src/app/shared/services/casa.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { CasaService } from './casa.service'; 4 | 5 | describe('AuthGuardService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: CasaService = TestBed.get(CasaService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/app/shared/services/login.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginService } from './login.service'; 4 | 5 | describe('LoginService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: LoginService = TestBed.get(LoginService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/app/shared/services/jarbas.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import {JarbasService} from './jarbas.service'; 4 | 5 | describe('JarbasService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: JarbasService = TestBed.get(JarbasService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/app/shared/services/update.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { UpdateService } from './update.service'; 4 | 5 | describe('UpdateService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: UpdateService = TestBed.get(UpdateService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /server/utils/middlewares/casa.validator.js: -------------------------------------------------------------------------------- 1 | const { check } = require('express-validator'); 2 | 3 | module.exports = { 4 | validate: [ 5 | check('casa').custom(casa => { 6 | if (casa !== undefined && casa !== "" && casa !== "camara" && casa !== "senado") { 7 | throw new Error("Parâmetro casa precisa ser 'camara' ou 'senado'."); 8 | } 9 | return true; 10 | }) 11 | ] 12 | }; -------------------------------------------------------------------------------- /client/src/app/shared/components/loading/loading.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-loading', 5 | templateUrl: './loading.component.html', 6 | styleUrls: ['./loading.component.scss'] 7 | }) 8 | export class LoadingComponent implements OnInit { 9 | 10 | @Input() lg = false; 11 | 12 | constructor() { } 13 | 14 | ngOnInit() { 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /client/src/app/shared/services/votacao.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { VotacaoService } from './votacao.service'; 4 | 5 | describe('VotacaoService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: VotacaoService = TestBed.get(VotacaoService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /client/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # 5 | # For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed 6 | 7 | > 0.5% 8 | last 2 versions 9 | Firefox ESR 10 | not dead 11 | not IE 9-11 -------------------------------------------------------------------------------- /client/src/app/shared/components/legend/legend.component.scss: -------------------------------------------------------------------------------- 1 | .legend-info { 2 | width: 15px; 3 | height: 15px; 4 | margin-top: 5px; 5 | margin-right: 0.5rem; 6 | border: solid 1px #20201e; 7 | } 8 | 9 | .legend-title { 10 | font-size: 0.8rem; 11 | line-height: 23px; 12 | margin-right: 1rem; 13 | word-wrap: break-word; 14 | } 15 | 16 | .legend-rounded { 17 | border-radius: 50%; 18 | border: solid 1px #adb5bd; 19 | } 20 | -------------------------------------------------------------------------------- /client/src/app/shared/services/comissao.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ComissaoService } from './comissao.service'; 4 | 5 | describe('ComissaoService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: ComissaoService = TestBed.get(ComissaoService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/app/shared/services/pergunta.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { PerguntaService } from './pergunta.service'; 4 | 5 | describe('PerguntaService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: PerguntaService = TestBed.get(PerguntaService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/app/shared/services/aderencia.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { AderenciaService } from './aderencia.service'; 4 | 5 | describe('AderenciaService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: AderenciaService = TestBed.get(AderenciaService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/app/shared/services/auth-guard.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { AuthGuardService } from './auth-guard.service'; 4 | 5 | describe('AuthGuardService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: AuthGuardService = TestBed.get(AuthGuardService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/app/shared/services/lideranca.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { LiderancaService } from './lideranca.service'; 4 | 5 | describe('LiderancaService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: LiderancaService = TestBed.get(LiderancaService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/app/shared/services/orientacao.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { OrientacaoService } from './orientacao.service'; 4 | 5 | describe('OrientacaoService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: OrientacaoService = TestBed.get(OrientacaoService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/app/user/user.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | import { UserRoutingModule } from './user-routing.module'; 5 | 6 | import { LoginComponent } from './login/login.component'; 7 | 8 | @NgModule({ 9 | declarations: [ 10 | LoginComponent 11 | ], 12 | imports: [ 13 | CommonModule, 14 | UserRoutingModule 15 | ] 16 | }) 17 | export class UserModule { } 18 | -------------------------------------------------------------------------------- /client/src/app/shared/services/alinhamento.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { AlinhamentoService } from './alinhamento.service'; 4 | 5 | describe('AlinhamentoService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: AlinhamentoService = TestBed.get(AlinhamentoService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/app/shared/services/parlamentar.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ParlamentarService } from './parlamentar.service'; 4 | 5 | describe('ParlamentarService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: ParlamentarService = TestBed.get(ParlamentarService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/app/shared/services/perfil-politico.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { PerfilPoliticoService } from './perfil-politico.service'; 4 | 5 | describe('PerfilPoliticoService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: PerfilPoliticoService = TestBed.get(PerfilPoliticoService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/app/filter/filter.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { FormsModule } from '@angular/forms'; 4 | 5 | import { FilterComponent } from './filter.component'; 6 | 7 | @NgModule({ 8 | declarations: [ 9 | FilterComponent 10 | ], 11 | imports: [ 12 | CommonModule, 13 | FormsModule 14 | ], 15 | exports: [ 16 | FilterComponent 17 | ] 18 | }) 19 | export class FilterModule { } 20 | -------------------------------------------------------------------------------- /client/src/app/shared/services/busca-parlamentar.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { BuscaParlamentarService } from './busca-parlamentar.service'; 4 | 5 | describe('BuscaParlamentarService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: BuscaParlamentarService = TestBed.get(BuscaParlamentarService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/app/shared/components/progress/progress.component.scss: -------------------------------------------------------------------------------- 1 | .progress-bordered { 2 | border-left: solid 1px; 3 | border-right: solid 1px; 4 | border-bottom: solid 1px; 5 | border-top: none; 6 | } 7 | 8 | .progress-axis { 9 | border-left: solid 1px; 10 | border-right: solid 1px; 11 | height: 0.5rem; 12 | } 13 | 14 | .progress-axis-values { 15 | display: flex; 16 | font-size: 0.6rem; 17 | justify-content: space-between; 18 | } 19 | 20 | .progress-bar { 21 | text-align: right; 22 | } 23 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/votacoes/votacoes.component.scss: -------------------------------------------------------------------------------- 1 | .votacoes-legend { 2 | display: flex; 3 | flex-wrap: wrap; 4 | margin-top: 3rem; 5 | } 6 | 7 | .progress-bar-aderencia { 8 | width: 100%; 9 | } 10 | 11 | .aderencia-value { 12 | font-size: 1.5rem; 13 | font-weight: 700; 14 | 15 | @media (min-width: 768px) { 16 | font-size: 2rem; 17 | } 18 | } 19 | 20 | .aderencia-value-text { 21 | line-height: 2.4rem; 22 | 23 | @media (min-width: 768px) { 24 | line-height: 2.7rem; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/vinculos-chart/vinculos-chart.component.scss: -------------------------------------------------------------------------------- 1 | ul#legend { 2 | list-style-type: none; 3 | } 4 | 5 | li.legendItem { 6 | display:inline-block; 7 | margin-right: 16px; 8 | 9 | &:hover { 10 | cursor: pointer; 11 | } 12 | } 13 | 14 | @media (max-width: 767px) { 15 | ul#legend { 16 | padding: 0; 17 | margin-left: 16px; 18 | margin-right: 16px; 19 | margin-bottom: 10px; 20 | } 21 | 22 | li.legendItem { 23 | font-size: 0.7rem; 24 | display: inline; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/src/app/questionario/temas/temas.component.scss: -------------------------------------------------------------------------------- 1 | .btn-tema { 2 | min-height: 140px; 3 | } 4 | 5 | .btn-tema-text { 6 | text-transform: uppercase; 7 | font-size: 0.75rem; 8 | margin: 0; 9 | padding: 0; 10 | } 11 | 12 | .container-tema { 13 | padding-top: 1.5rem; 14 | padding-bottom: 1.5rem; 15 | padding-left: 0; 16 | padding-right: 0; 17 | max-width: 535px; 18 | margin: auto; 19 | 20 | @media (min-width: 375px) { 21 | padding-left: 1.5rem; 22 | padding-right: 1.5rem; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/footer/footer.component.html: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /client/src/app/shared/components/progress/progress.component.html: -------------------------------------------------------------------------------- 1 |
2 |
10 |
11 |
12 |
13 |
14 |
{{min}}
15 |
{{max}}
16 |
17 |
18 | -------------------------------------------------------------------------------- /client/src/app/alinhamento/alinhamento-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { AlinhamentoComponent } from './alinhamento.component'; 5 | 6 | const routes: Routes = [ 7 | { 8 | path: '', 9 | component: AlinhamentoComponent, 10 | data: { animation: 'AlinhamentoComponent' } 11 | } 12 | ]; 13 | 14 | @NgModule({ 15 | imports: [RouterModule.forChild(routes)], 16 | exports: [RouterModule] 17 | }) 18 | export class AlinhamentoRoutingModule { } 19 | -------------------------------------------------------------------------------- /client/src/app/busca-parlamentar/busca-parlamentar.component.scss: -------------------------------------------------------------------------------- 1 | .controls { 2 | 3 | @media (max-width: 575.98px) { 4 | display: flex; 5 | justify-content: space-between; 6 | 7 | position: -webkit-sticky; 8 | position: sticky; 9 | top: 93px; 10 | background-color: #ffffff; 11 | z-index: 1050; 12 | } 13 | } 14 | 15 | .parlamentar-count { 16 | line-height: 40px; 17 | } 18 | 19 | .controls-toolbar { 20 | line-height: 36px; 21 | 22 | @media (min-width: 576px) { 23 | display: flex; 24 | justify-content: center; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/cargo/cargo.component.html: -------------------------------------------------------------------------------- 1 |
5 |
6 | 10 | {{ cargo.key }} 11 | 12 |
13 |
14 |
18 |
{{ c.sigla }}
19 |
{{ c.nome }}
20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /server/models/postgres/resposta.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | resposta = sequelize.define( 3 | "respostas", 4 | { 5 | resposta: type.INTEGER 6 | }, 7 | { 8 | timestamps: false 9 | } 10 | ); 11 | resposta.associate = function(models) { 12 | resposta.belongsTo(models.pergunta, { 13 | foreignKey: "pergunta_id", 14 | as: "perg_resp" 15 | }), 16 | resposta.belongsTo(models.candidato, { 17 | foreignKey: "cpf", 18 | as: "cpf_resp" 19 | }); 20 | }; 21 | return resposta; 22 | }; 23 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.5' 2 | 3 | services: 4 | 5 | backend: 6 | build: . 7 | env_file: 8 | - variables.env 9 | volumes: 10 | - ./server:/app/server 11 | - ./server.js:/app/server.js 12 | ports: 13 | - "5000:5000" 14 | networks: 15 | - my-proxy-net 16 | 17 | frontend: 18 | build: ./client 19 | volumes: 20 | - ./client:/app/client 21 | - /app/client/node_modules/ 22 | ports: 23 | - "4200:4200" 24 | 25 | networks: 26 | my-proxy-net: 27 | external: 28 | name: voz_ativa_network -------------------------------------------------------------------------------- /client/src/app/shared/models/aderencia.model.ts: -------------------------------------------------------------------------------- 1 | import { Partido } from './partido.model'; 2 | import { Tema } from './tema.model'; 3 | 4 | export interface AderenciaDados { 5 | faltou: number; 6 | partidoLiberou: number; 7 | naoSeguiu: number; 8 | seguiu: number; 9 | aderencia: number; 10 | partido: Partido; 11 | aderenciaTema: Tema; 12 | } 13 | 14 | export interface Aderencia { 15 | idParlamentarVoz: string; 16 | casa: string; 17 | nomeEleitoral: string; 18 | parlamentarPartido: Partido; 19 | parlamentarAderencia: Array; 20 | } 21 | -------------------------------------------------------------------------------- /client/src/app/busca-parlamentar/busca-parlamentar-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { BuscaParlamentarComponent } from './busca-parlamentar.component'; 5 | 6 | const routes: Routes = [ 7 | { 8 | path: '', 9 | redirectTo: 'camara' 10 | }, 11 | { 12 | path: ':casa', 13 | component: BuscaParlamentarComponent 14 | } 15 | ]; 16 | 17 | @NgModule({ 18 | imports: [RouterModule.forChild(routes)], 19 | exports: [RouterModule] 20 | }) 21 | export class BuscaParlamentarRoutingModule { } 22 | -------------------------------------------------------------------------------- /client/src/app/questionario/pergunta/pergunta.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-pergunta', 5 | templateUrl: './pergunta.component.html', 6 | styleUrls: ['./pergunta.component.scss'] 7 | }) 8 | export class PerguntaComponent implements OnInit { 9 | 10 | @Input() projLei = ''; 11 | @Input() title = ''; 12 | @Input() description = ''; 13 | @Input() id = ''; 14 | 15 | isCollapsed: boolean; 16 | 17 | constructor() { 18 | this.isCollapsed = true; 19 | } 20 | 21 | ngOnInit() { 22 | 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /client/src/app/aderencia/aderencia-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { AderenciaComponent } from './aderencia.component'; 5 | 6 | const routes: Routes = [ 7 | { 8 | path: '', 9 | redirectTo: 'camara' 10 | }, 11 | { 12 | path: ':casa', 13 | component: AderenciaComponent, 14 | data: { animation: 'AderenciaComponent' } 15 | } 16 | ]; 17 | 18 | @NgModule({ 19 | imports: [RouterModule.forChild(routes)], 20 | exports: [RouterModule] 21 | }) 22 | export class AderenciaRoutingModule { } 23 | -------------------------------------------------------------------------------- /client/src/app/shared/models/parlamentarInvestimento.model.ts: -------------------------------------------------------------------------------- 1 | import { Partido } from './partido.model'; 2 | import { PartidoInvestimento } from './partidoInvestimento.model'; 3 | 4 | interface DadosParlamentar { 5 | casa: string; 6 | nomeEleitoral: string; 7 | uf: string; 8 | } 9 | 10 | export interface ParlamentarInvestimento { 11 | totalReceitaPartido: number; 12 | totalReceitaCandidato: number; 13 | indiceInvestimentoPartido: number; 14 | partidoAtual: Partido; 15 | partidoEleicao: Partido; 16 | parlamentarInvestimento: DadosParlamentar; 17 | partidoInvestimento: PartidoInvestimento; 18 | } 19 | -------------------------------------------------------------------------------- /client/src/app/user/user-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { LoginComponent } from './login/login.component'; 5 | 6 | const routes: Routes = [ 7 | { 8 | path: 'login', 9 | component: LoginComponent, 10 | data: { animation: 'LoginComponent' } 11 | }, 12 | { 13 | path: '', 14 | redirectTo: 'login', 15 | pathMatch: 'full' 16 | } 17 | ]; 18 | 19 | @NgModule({ 20 | imports: [RouterModule.forChild(routes)], 21 | exports: [RouterModule] 22 | }) 23 | export class UserRoutingModule { } 24 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/parlamentar.component.scss: -------------------------------------------------------------------------------- 1 | .parlamentar { 2 | margin-top: 15px; 3 | display: flex; 4 | justify-content: center; 5 | margin-bottom: 15px; 6 | } 7 | 8 | .parlamentar-title { 9 | font-weight: 700; 10 | } 11 | 12 | .nav-link-parlamentar { 13 | font-size: 0.8rem; 14 | padding: 0.5rem 0.5rem; 15 | 16 | &:link { 17 | text-decoration: none; 18 | } 19 | } 20 | 21 | .parlementar-subnav { 22 | @media (max-width: 400px) { 23 | display: flex; 24 | flex-wrap: nowrap; 25 | overflow-x: auto; 26 | 27 | > .nav { 28 | flex: 0 0 auto; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/posicao/posicao.component.scss: -------------------------------------------------------------------------------- 1 | .posicao { 2 | border: solid 2px #20201e; 3 | margin-bottom: 1rem; 4 | } 5 | 6 | .posicao-body { 7 | padding: 1rem; 8 | 9 | @media (min-width: 576px) { 10 | padding: 2rem; 11 | } 12 | } 13 | 14 | .posicao-title { 15 | font-size: 0.9rem; 16 | } 17 | 18 | .opiniao { 19 | padding: 0.25rem 0.75rem; 20 | color: #ffffff; 21 | } 22 | 23 | .opiniao-positiva { 24 | background-color: #43a467; 25 | } 26 | 27 | .opiniao-negativa { 28 | background-color: #7f3c8b; 29 | } 30 | 31 | .opiniao-neutra { 32 | background-color: #ebe9e9; 33 | color: #20201e; 34 | } 35 | -------------------------------------------------------------------------------- /client/src/app/shared/config/socialLoginConfig.ts: -------------------------------------------------------------------------------- 1 | import { SocialLoginModule, AuthServiceConfig, GoogleLoginProvider, FacebookLoginProvider } from 'angularx-social-login'; 2 | import { environment } from '../../../environments/environment'; 3 | 4 | export function getAuthServiceConfigs() { 5 | const config = new AuthServiceConfig([{ 6 | id: GoogleLoginProvider.PROVIDER_ID, 7 | provider: new GoogleLoginProvider(environment.googleAppID) 8 | }, 9 | { 10 | id: FacebookLoginProvider.PROVIDER_ID, 11 | provider: new FacebookLoginProvider(environment.facebookAppID) 12 | }]); 13 | 14 | return config; 15 | } 16 | -------------------------------------------------------------------------------- /client/src/app/busca-parlamentar/card-busca-parlamentar/card-busca-parlamentar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | 3 | import { Parlamentar } from 'src/app/shared/models/parlamentar.model'; 4 | 5 | @Component({ 6 | selector: 'app-card-busca-parlamentar', 7 | templateUrl: './card-busca-parlamentar.component.html', 8 | styleUrls: ['./card-busca-parlamentar.component.scss'] 9 | }) 10 | export class CardBuscaParlamentarComponent { 11 | 12 | readonly VIEW_SM = 'sm'; 13 | readonly VIEW_MD = 'md'; 14 | 15 | @Input() parlamentar: Parlamentar; 16 | @Input() view: string; 17 | 18 | constructor() { } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /client/src/app/shared/services/auth-guard.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Router, CanActivate } from '@angular/router'; 3 | import { LoginService } from './login.service'; 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class AuthGuardService implements CanActivate { 9 | 10 | constructor( 11 | private router: Router, 12 | private loginService: LoginService 13 | ) { } 14 | 15 | canActivate() { 16 | if (this.loginService.isUserLogged()) { 17 | return true; 18 | } else { 19 | this.router.navigate(['/usuario/login']); 20 | return false; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /client/src/app/questionario/pergunta/pergunta.component.scss: -------------------------------------------------------------------------------- 1 | $viewport-negative-height: 365px; 2 | 3 | .pergunta-wrapper { 4 | @media (min-width: 340px) { 5 | height: calc(100vh - #{$viewport-negative-height}); 6 | overflow-y: auto; 7 | display: flex; 8 | flex-direction: column; 9 | justify-content: center; 10 | } 11 | 12 | @media (min-width: 992px) { 13 | height: 40vh; 14 | } 15 | } 16 | 17 | .pergunta-texto { 18 | font-size: 1.2rem; 19 | 20 | @media (min-width: 340px) { 21 | font-size: 1.5rem; 22 | } 23 | @media (min-width: 768px) { 24 | font-size: 1.8rem; 25 | } 26 | @media (min-width: 992px) { 27 | font-size: 2rem; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /client/src/app/shared/components/progress-stacked/progress-stacked.component.scss: -------------------------------------------------------------------------------- 1 | .progress-stacked-bar { 2 | padding-right: 0.25rem; 3 | text-align: right; 4 | color: #20201e; 5 | border-right: solid 1px #20201e; 6 | } 7 | 8 | .progress-stacked-title { 9 | font-size: 0.8rem; 10 | } 11 | 12 | .progress-light { 13 | color: #20201e; 14 | border-top: solid 1px #20201e; 15 | border-right: solid 1px #20201e; 16 | border-bottom: solid 1px #20201e; 17 | } 18 | 19 | .with-border { 20 | border-left: solid 1px #20201e; 21 | } 22 | 23 | .progress-bordered { 24 | border-left: solid 1px #20201e; 25 | border-bottom: solid 1px #20201e; 26 | border-top: solid 1px #20201e; 27 | } 28 | -------------------------------------------------------------------------------- /client/src/app/main/main-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { HomeComponent } from './home/home.component'; 5 | import { SobreComponent } from './sobre/sobre.component'; 6 | 7 | const routes: Routes = [ 8 | { 9 | path: '', 10 | component: HomeComponent, 11 | data: { animation: 'HomeComponent' } 12 | }, 13 | { 14 | path: 'sobre', 15 | component: SobreComponent, 16 | data: { animation: 'SobreComponent' } 17 | } 18 | ]; 19 | 20 | @NgModule({ 21 | imports: [RouterModule.forChild(routes)], 22 | exports: [RouterModule] 23 | }) 24 | export class MainRoutingModule { } 25 | -------------------------------------------------------------------------------- /client/src/app/questionario/questionario-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { QuestionarioComponent } from './questionario.component'; 5 | 6 | const routes: Routes = [ 7 | { 8 | path: '', 9 | component: QuestionarioComponent, 10 | data: { animation: 'QuestionarioComponent' } 11 | }, 12 | { 13 | path: ':id', 14 | component: QuestionarioComponent, 15 | data: { animation: 'QuestionarioComponent' } 16 | } 17 | ]; 18 | 19 | @NgModule({ 20 | imports: [RouterModule.forChild(routes)], 21 | exports: [RouterModule] 22 | }) 23 | export class QuestionarioRoutingModule { } 24 | -------------------------------------------------------------------------------- /client/src/app/main/main.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { RouterModule } from '@angular/router'; 4 | 5 | import { MainRoutingModule } from './main-routing.module'; 6 | import { SharedModule } from '../shared/components/shared.module'; 7 | 8 | import { HomeComponent } from './home/home.component'; 9 | import { SobreComponent } from './sobre/sobre.component'; 10 | 11 | @NgModule({ 12 | declarations: [ 13 | HomeComponent, 14 | SobreComponent 15 | ], 16 | imports: [ 17 | CommonModule, 18 | RouterModule, 19 | SharedModule, 20 | MainRoutingModule 21 | ] 22 | }) 23 | export class MainModule { } 24 | -------------------------------------------------------------------------------- /client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "downlevelIteration": true, 6 | "outDir": "./dist/out-tsc", 7 | "sourceMap": true, 8 | "declaration": false, 9 | "module": "esnext", 10 | "moduleResolution": "node", 11 | "emitDecoratorMetadata": true, 12 | "experimentalDecorators": true, 13 | "importHelpers": true, 14 | "target": "es2015", 15 | "typeRoots": [ 16 | "node_modules/@types" 17 | ], 18 | "lib": [ 19 | "es2018", 20 | "dom" 21 | ] 22 | }, 23 | "angularCompilerOptions": { 24 | "fullTemplateTypeCheck": true, 25 | "strictInjectionParameters": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /server/models/postgres/comissoes.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | comissao = sequelize.define( 3 | "comissoe", 4 | { 5 | id_comissao_voz: { 6 | type: type.STRING, 7 | primaryKey: true 8 | }, 9 | id: type.INTEGER, 10 | casa: type.STRING, 11 | sigla: type.STRING, 12 | nome: type.STRING 13 | }, 14 | { 15 | timestamps: false 16 | } 17 | ); 18 | comissao.associate = function(models) { 19 | comissao.hasMany(models.composicaoComissoes, { 20 | foreignKey: "id_comissao_voz", 21 | targetKey: "id_comissao_voz", 22 | as: "comissaoComp" 23 | }) 24 | }; 25 | return comissao; 26 | }; 27 | -------------------------------------------------------------------------------- /.github/workflows/perfil-workflow.yml: -------------------------------------------------------------------------------- 1 | name: Build Perfil Parlamentar 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | - deploy-validacao 9 | 10 | jobs: 11 | build: 12 | name: Build 13 | runs-on: ubuntu-18.04 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - uses: actions/setup-node@v1 18 | with: 19 | node-version: 10.x 20 | - name: Instala dependências 21 | working-directory: ./client 22 | run: npm install 23 | - name: Executa lint 24 | working-directory: ./client 25 | run: npm run lint 26 | - name: Executa build 27 | working-directory: ./client 28 | run: npm run build -------------------------------------------------------------------------------- /client/src/app/parlamentar/posicao/posicao.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | 3 | import { Parlamentar } from 'src/app/shared/models/parlamentar.model'; 4 | 5 | @Component({ 6 | selector: 'app-posicao', 7 | templateUrl: './posicao.component.html', 8 | styleUrls: ['./posicao.component.scss'] 9 | }) 10 | export class PosicaoComponent implements OnInit { 11 | readonly FAVOR = 1; 12 | readonly CONTRA = -1; 13 | 14 | @Input() parlamentar: Parlamentar; 15 | @Input() proposicao: any; 16 | @Input() resposta: any; 17 | @Input() votacao: any; 18 | 19 | isCollapsed: boolean; 20 | 21 | constructor() {} 22 | 23 | ngOnInit() { 24 | this.isCollapsed = true; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /client/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to vozativa!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | })); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /client/src/app/shared/components/sticky-footer-navbar/sticky-footer-navbar.component.scss: -------------------------------------------------------------------------------- 1 | .sticky-footer-navbar { 2 | position: fixed; 3 | top: 42px; 4 | width: 100%; 5 | z-index: 999; 6 | padding-top: 0.5rem; 7 | padding-bottom: 0.5rem; 8 | background-color: #20201e; 9 | color: #fff; 10 | 11 | @media (min-width: 992px) { 12 | display: none; 13 | } 14 | } 15 | 16 | .sticky-footer-navbar-link { 17 | text-decoration: none; 18 | text-transform: uppercase; 19 | font-size: 0.8rem; 20 | color: #fff; 21 | 22 | &.active { 23 | font-weight: 700; 24 | background-color: #20201e; 25 | color: #fff; 26 | } 27 | } 28 | 29 | .sticky-footer-navbar-item { 30 | padding-left: 0; 31 | padding-right: 0; 32 | } 33 | -------------------------------------------------------------------------------- /client/src/app/alinhamento/congresso-alinhamento/congresso-alinhamento.component.scss: -------------------------------------------------------------------------------- 1 | .subtitle-wrapper { 2 | height: 50px; 3 | } 4 | 5 | .subtitle { 6 | flex-wrap: wrap; 7 | } 8 | 9 | .btn-toolbar { 10 | line-height: 3.2rem; 11 | justify-content: flex-end; 12 | 13 | @media (min-width: 992px) { 14 | justify-content: center; 15 | } 16 | 17 | } 18 | 19 | .btn-light-icon { 20 | font-size: 1.7rem; 21 | } 22 | 23 | .chart-controls-info { 24 | order: 0; 25 | line-height: 3.2rem; 26 | } 27 | 28 | .chart-controls-info2 { 29 | order: 2; 30 | @media (min-width: 992px) { 31 | order: 1; 32 | } 33 | } 34 | 35 | .chart-controls-btns { 36 | order: 1; 37 | @media (min-width: 992px) { 38 | order: 2; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /client/src/app/questionario/pergunta/pergunta.component.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | {{ projLei }} 4 |
5 | {{ title }} 6 |

7 |
8 |
9 | 18 |
19 |
24 | {{ description }} 25 |
26 |
27 |
28 | -------------------------------------------------------------------------------- /client/src/app/shared/services/lideranca.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient, HttpParams } from '@angular/common/http'; 3 | 4 | import { Observable } from 'rxjs'; 5 | 6 | import { Lideranca } from '../models/lideranca.model'; 7 | import { environment } from 'src/environments/environment'; 8 | 9 | @Injectable({ 10 | providedIn: 'root' 11 | }) 12 | export class LiderancaService { 13 | 14 | private url = environment.apiUrl + 'liderancas'; 15 | 16 | constructor(private http: HttpClient) { } 17 | 18 | getLiderancas(casa: string): Observable { 19 | const params = new HttpParams() 20 | .set('casa', casa); 21 | return this.http.get(this.url, { params }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /client/src/app/main/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HomeComponent } from './home.component'; 4 | 5 | describe('HomeComponent', () => { 6 | let component: HomeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ HomeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HomeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/aderencia/aderencia-parlamentares/aderencia-parlamentares.component.scss: -------------------------------------------------------------------------------- 1 | .parlamentar-count { 2 | line-height: 3; 3 | font-size: 0.8rem; 4 | 5 | @media (min-width: 992px) { 6 | line-height: 2; 7 | font-size: 1rem; 8 | } 9 | } 10 | 11 | .parlamentar-lista { 12 | @media (min-width: 992px) { 13 | width: 760px; 14 | margin: auto; 15 | } 16 | } 17 | 18 | .btn-toolbar { 19 | line-height: 2.2rem; 20 | justify-content: flex-end; 21 | 22 | @media (min-width: 992px) { 23 | justify-content: center; 24 | } 25 | } 26 | 27 | .controls { 28 | @media (max-width: 575.98px) { 29 | position: -webkit-sticky; 30 | position: sticky; 31 | top: 93px; 32 | background-color: #ffffff; 33 | z-index: 1050; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /client/src/app/main/sobre/sobre.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SobreComponent } from './sobre.component'; 4 | 5 | describe('SobreComponent', () => { 6 | let component: SobreComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ SobreComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SobreComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/user/login/login.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginComponent } from './login.component'; 4 | 5 | describe('LoginComponent', () => { 6 | let component: LoginComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LoginComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LoginComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/filter/filter.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FilterComponent } from './filter.component'; 4 | 5 | describe('FilterComponent', () => { 6 | let component: FilterComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ FilterComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FilterComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/cargo/cargo.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CargoComponent } from './cargo.component'; 4 | 5 | describe('CargoComponent', () => { 6 | let component: CargoComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CargoComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CargoComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /server/utils/token.utils.js: -------------------------------------------------------------------------------- 1 | const jwt = require("jsonwebtoken"); 2 | const keys = require("../config/keys"); 3 | 4 | const createToken = function(auth) { 5 | return jwt.sign( 6 | { 7 | id: auth.id, 8 | firstName: auth.firstName, 9 | photo: auth.photo, 10 | respostas: auth.respostas 11 | }, 12 | keys.secretOrKey, 13 | { 14 | expiresIn: 60 * 43200 // 30 dias 15 | } 16 | ); 17 | }; 18 | 19 | module.exports = { 20 | generateToken: function(req, res, next) { 21 | req.token = createToken(req.auth); 22 | return next(); 23 | }, 24 | sendToken: function(req, res) { 25 | res.setHeader("authorization", req.token); 26 | return res.status(200).send(JSON.stringify(req.user)); 27 | }, 28 | createToken 29 | }; 30 | -------------------------------------------------------------------------------- /client/src/app/questionario/temas/temas.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TemasComponent } from './temas.component'; 4 | 5 | describe('TemasComponent', () => { 6 | let component: TemasComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ TemasComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(TemasComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/cargo/cargo.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, SimpleChanges, OnChanges } from '@angular/core'; 2 | 3 | import { getClassCargo } from '../../shared/functions/comissao'; 4 | 5 | @Component({ 6 | selector: 'app-cargo', 7 | templateUrl: './cargo.component.html', 8 | styleUrls: ['./cargo.component.scss'] 9 | }) 10 | export class CargoComponent implements OnChanges { 11 | 12 | @Input() cargos: {}; 13 | 14 | constructor() { } 15 | 16 | ngOnChanges(changes: SimpleChanges) { 17 | if ( 18 | typeof changes.cargos !== 'undefined' && 19 | typeof changes.cargos.currentValue !== 'undefined' 20 | ) { 21 | Object.keys(this.cargos).map(cargo => { this.cargos[cargo].classe = getClassCargo(cargo); }); 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/cargos/cargos.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CargosComponent } from './cargos.component'; 4 | 5 | describe('CargosComponent', () => { 6 | let component: CargosComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CargosComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CargosComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/despesas-cota-parlamentar/despesas-cota-parlamentar.component.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | margin: 16px 0; 3 | align-self: center; 4 | } 5 | 6 | .content { 7 | max-width: 900px; 8 | margin: 0 auto; 9 | } 10 | 11 | .filters-container { 12 | margin-bottom: 20px; 13 | } 14 | 15 | .count { 16 | margin-bottom: 20px; 17 | font-size: 1.1rem; 18 | } 19 | 20 | .page-centered { 21 | margin: 0 auto; 22 | } 23 | 24 | .fetch-button { 25 | display: flex; 26 | justify-content: center; 27 | align-items: center; 28 | 29 | &.btn-primary{ 30 | text-transform: uppercase; 31 | } 32 | 33 | > span { 34 | position: relative; 35 | text-align: center; 36 | } 37 | > i { 38 | position: absolute; 39 | font-size: 1.5rem; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /client/src/app/shared/components/footer/footer.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FooterComponent } from './footer.component'; 4 | 5 | describe('FooterComponent', () => { 6 | let component: FooterComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ FooterComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FooterComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/legend/legend.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LegendComponent } from './legend.component'; 4 | 5 | describe('LegendComponent', () => { 6 | let component: LegendComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LegendComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LegendComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/navbar/navbar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { NavbarComponent } from './navbar.component'; 4 | 5 | describe('NavbarComponent', () => { 6 | let component: NavbarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ NavbarComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(NavbarComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/aderencia/aderencia.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PlenarioComponent } from './plenario.component'; 4 | 5 | describe('PlenarioComponent', () => { 6 | let component: PlenarioComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PlenarioComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PlenarioComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/capital/capital.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CapitalComponent } from './capital.component'; 4 | 5 | describe('CapitalComponent', () => { 6 | let component: CapitalComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CapitalComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CapitalComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/posicao/posicao.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PosicaoComponent } from './posicao.component'; 4 | 5 | describe('PosicaoComponent', () => { 6 | let component: PosicaoComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PosicaoComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PosicaoComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/votacao/votacao.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { VotacaoComponent } from './votacao.component'; 4 | 5 | describe('VotacaoComponent', () => { 6 | let component: VotacaoComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ VotacaoComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(VotacaoComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /build 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # profiling files 12 | chrome-profiler-events.json 13 | speed-measure-plugin.json 14 | 15 | # IDEs and editors 16 | /.idea 17 | .project 18 | .classpath 19 | .c9/ 20 | *.launch 21 | .settings/ 22 | *.sublime-workspace 23 | 24 | # IDE - VSCode 25 | .vscode/* 26 | !.vscode/settings.json 27 | !.vscode/tasks.json 28 | !.vscode/launch.json 29 | !.vscode/extensions.json 30 | .history/* 31 | 32 | # misc 33 | /.sass-cache 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | npm-debug.log 38 | yarn-error.log 39 | testem.log 40 | /typings 41 | 42 | # System Files 43 | .DS_Store 44 | Thumbs.db 45 | -------------------------------------------------------------------------------- /client/src/app/shared/components/loading/loading.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoadingComponent } from './loading.component'; 4 | 5 | describe('LoadingComponent', () => { 6 | let component: LoadingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LoadingComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LoadingComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/sticky-footer-navbar/sticky-footer-navbar.component.html: -------------------------------------------------------------------------------- 1 | 25 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/posicoes/posicoes.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PosicoesComponent } from './posicoes.component'; 4 | 5 | describe('PosicoesComponent', () => { 6 | let component: PosicoesComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PosicoesComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PosicoesComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/vinculos/vinculos.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { VinculosComponent } from './vinculos.component'; 4 | 5 | describe('VinculosComponent', () => { 6 | let component: VinculosComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ VinculosComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(VinculosComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/votacoes/votacoes.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { VotacoesComponent } from './votacoes.component'; 4 | 5 | describe('VotacoesComponent', () => { 6 | let component: VotacoesComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ VotacoesComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(VotacoesComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/questionario/pergunta/pergunta.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PerguntaComponent } from './pergunta.component'; 4 | 5 | describe('PerguntaComponent', () => { 6 | let component: PerguntaComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PerguntaComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PerguntaComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/progress/progress.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input, OnChanges } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-progress', 5 | templateUrl: './progress.component.html', 6 | styleUrls: ['./progress.component.scss'] 7 | }) 8 | export class ProgressComponent implements OnInit, OnChanges { 9 | @Input() value: number; 10 | @Input() min: number; 11 | @Input() max: number; 12 | @Input() showAxis: boolean; 13 | @Input() class: string; 14 | 15 | constructor() {} 16 | 17 | ngOnInit() {} 18 | 19 | ngOnChanges() { 20 | if (this.value < 0) { 21 | this.value = 0; 22 | } 23 | } 24 | 25 | getClass(): string[] { 26 | const classes = ['progress-bar', this.class]; 27 | 28 | return classes; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /client/src/app/shared/components/progress/progress.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ProgressComponent } from './progress.component'; 4 | 5 | describe('ProgressComponent', () => { 6 | let component: ProgressComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ProgressComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ProgressComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/aderencia/aderencia.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AderenciaComponent } from './aderencia.component'; 4 | 5 | describe('AderenciaComponent', () => { 6 | let component: AderenciaComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ AderenciaComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(AderenciaComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/alinhamento/alinhamento.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AlinhamentoComponent } from './alinhamento.component'; 4 | 5 | describe('AlinhamentoComponent', () => { 6 | let component: AlinhamentoComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ AlinhamentoComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(AlinhamentoComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/parlamentar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ParlamentarComponent } from './parlamentar.component'; 4 | 5 | describe('ParlamentarComponent', () => { 6 | let component: ParlamentarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ParlamentarComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ParlamentarComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/patrimonio/patrimonio.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PatrimonioComponent } from './patrimonio.component'; 4 | 5 | describe('PatrimonioComponent', () => { 6 | let component: PatrimonioComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PatrimonioComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PatrimonioComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/trajetoria/trajetoria.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TrajetoriaComponent } from './trajetoria.component'; 4 | 5 | describe('TrajetoriaComponent', () => { 6 | let component: TrajetoriaComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ TrajetoriaComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(TrajetoriaComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/legend/legend.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-legend', 5 | templateUrl: './legend.component.html', 6 | styleUrls: ['./legend.component.scss'] 7 | }) 8 | export class LegendComponent implements OnInit { 9 | @Input() title: string; 10 | @Input() class: string; 11 | @Input() striped: boolean; 12 | @Input() rounded: boolean; 13 | 14 | constructor() { } 15 | 16 | ngOnInit() { 17 | } 18 | 19 | getClass(): string[] { 20 | const classes = ['legend-info', this.class]; 21 | if (this.striped) { 22 | classes.push('progress-bar-striped'); 23 | } 24 | if (this.rounded) { 25 | classes.push('legend-rounded'); 26 | } 27 | 28 | return classes; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /server/models/postgres/perfil-mais.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | perfilMais = sequelize.define( 3 | "perfil_mais", 4 | { 5 | id_parlamentar_voz: { 6 | type: type.STRING, 7 | primaryKey: true 8 | }, 9 | indice_vinculo_economico_agro: type.REAL, 10 | indice_ativismo_ambiental: type.REAL, 11 | peso_politico: type.REAL 12 | }, 13 | { 14 | timestamps: false, 15 | freezeTableName: true 16 | } 17 | ); 18 | perfilMais.associate = function (models) { 19 | perfilMais.belongsTo(models.parlamentar, { 20 | foreignKey: "id_parlamentar_voz", 21 | sourceKey: "id_parlamentar_voz", 22 | as: "perfilMaisParlamentar" 23 | }) 24 | }; 25 | return perfilMais; 26 | }; 27 | -------------------------------------------------------------------------------- /client/src/app/shared/components/progress-stacked/progress-stacked.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-progress-stacked', 5 | templateUrl: './progress-stacked.component.html', 6 | styleUrls: ['./progress-stacked.component.scss'] 7 | }) 8 | export class ProgressStackedComponent { 9 | @Input() titulo: string; 10 | @Input() categorias: any[]; 11 | @Input() passo: number; 12 | 13 | min: number; 14 | max: number; 15 | 16 | constructor() { 17 | this.min = 0; 18 | this.max = 100; 19 | } 20 | 21 | getClass(classe): string[] { 22 | const classes = ['progress-bar progress-stacked-bar progress-bordered', classe]; 23 | return classes; 24 | } 25 | 26 | getValor(valor) { 27 | return valor * this.passo; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /server/models/postgres/empresas.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | empresas = sequelize.define( 3 | "empresas", 4 | { 5 | cnpj: { 6 | type: type.STRING, 7 | primaryKey: true 8 | }, 9 | razao_social: type.STRING, 10 | }, 11 | { 12 | timestamps: false, 13 | freezeTableName: true 14 | } 15 | ); 16 | 17 | empresas.associate = function (models) { 18 | empresas.hasMany(models.empresasParlamentares, { 19 | foreignKey: "cnpj", 20 | targetKey: "cnpj", 21 | as: "empresasParlamentares" 22 | }), 23 | empresas.hasMany(models.atividadesEconomicasEmpresas, { 24 | foreignKey: "cnpj", 25 | targetKey: "cnpj", 26 | as: "empresasAtividadesEconomicas" 27 | }) 28 | }; 29 | return empresas; 30 | }; 31 | -------------------------------------------------------------------------------- /client/src/app/questionario/questionario.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { QuestionarioComponent } from './questionario.component'; 4 | 5 | describe('QuestionarioComponent', () => { 6 | let component: QuestionarioComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ QuestionarioComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(QuestionarioComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/card-empresa/card-empresa.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CardEmpresaComponent } from './card-empresa.component'; 4 | 5 | describe('CardEmpresaComponent', () => { 6 | let component: CardEmpresaComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CardEmpresaComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CardEmpresaComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/capital-chart/capital-chart.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CapitalChartComponent } from './capital-chart.component'; 4 | 5 | describe('CapitalChartComponent', () => { 6 | let component: CapitalChartComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CapitalChartComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CapitalChartComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/card-reembolso/card-reembolso.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CardReembolsoComponent } from './card-reembolso.component'; 4 | 5 | describe('CardReembolsoComponent', () => { 6 | let component: CardReembolsoComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CardReembolsoComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CardReembolsoComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/vinculos-chart/vinculos-chart.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { VinculosChartComponent } from './vinculos-chart.component'; 4 | 5 | describe('VinculosChartComponent', () => { 6 | let component: VinculosChartComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ VinculosChartComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(VinculosChartComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /server/models/postgres/voto.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | const voto = sequelize.define( 3 | "voto", 4 | { 5 | id_votacao: { 6 | type: type.STRING, 7 | primaryKey: true 8 | }, 9 | id_parlamentar_voz: { 10 | type: type.STRING, 11 | primaryKey: true 12 | }, 13 | voto: type.INTEGER 14 | }, 15 | { 16 | timestamps: false 17 | } 18 | ); 19 | voto.associate = function(models) { 20 | voto.belongsTo(models.votacao, { 21 | foreignKey: "id_votacao", 22 | sourceKey: "id_votacao", 23 | as: "votacoesVoto" 24 | }), 25 | voto.belongsTo(models.parlamentar, { 26 | foreignKey: "id_parlamentar_voz", 27 | sourceKey: "id_parlamentar_voz", 28 | as: "votos" 29 | }); 30 | }; 31 | return voto; 32 | }; 33 | -------------------------------------------------------------------------------- /client/src/app/aderencia/congresso-chart/congresso-chart.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CongressoChartComponent } from './congresso-chart.component'; 4 | 5 | describe('CongressoChartComponent', () => { 6 | let component: CongressoChartComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CongressoChartComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CongressoChartComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/busca-parlamentar/busca-parlamentar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { BuscaParlamentarComponent } from './busca-parlamentar.component'; 4 | 5 | describe('BuscaParlamentarComponent', () => { 6 | let component: BuscaParlamentarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ BuscaParlamentarComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(BuscaParlamentarComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/aderencia/card-parlamentar/card-parlamentar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CardParlamentarComponent } from './card-parlamentar.component'; 4 | 5 | describe('CardParlamentarComponent', () => { 6 | let component: CardParlamentarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CardParlamentarComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CardParlamentarComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/alinhamento/card-parlamentar/card-parlamentar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CardParlamentarComponent } from './card-parlamentar.component'; 4 | 5 | describe('CardParlamentarComponent', () => { 6 | let component: CardParlamentarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CardParlamentarComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CardParlamentarComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/app-routing-animation.ts: -------------------------------------------------------------------------------- 1 | import { trigger, animate, style, query, transition } from '@angular/animations'; 2 | 3 | export const routeAnimation = 4 | trigger('routeAnimation', [ 5 | transition('* => *', [ 6 | query( 7 | ':enter', 8 | [style({ opacity: 0, position: 'absolute', width: '100%', height: '100%' })], 9 | { optional: true } 10 | ), 11 | query( 12 | ':leave', 13 | [style({ opacity: 1, position: 'absolute', width: '100%', height: '100%'}), animate('0.25s ease-out', style({ opacity: 0 }))], 14 | { optional: true } 15 | ), 16 | query( 17 | ':enter', 18 | [animate('0.25s ease-in', style({ opacity: 1, position: 'absolute', width: '100%', height: '100%' }))], 19 | { optional: true } 20 | ) 21 | ]) 22 | ]); 23 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/patrimonio-chart/patrimonio-chart.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PatrimonioChartComponent } from './patrimonio-chart.component'; 4 | 5 | describe('PatrimonioChartComponent', () => { 6 | let component: PatrimonioChartComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PatrimonioChartComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PatrimonioChartComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /server/models/postgres/orientacao.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | const orientacao = sequelize.define( 3 | "orientacoe", 4 | { 5 | id_votacao: { 6 | type: type.STRING, 7 | primaryKey: true 8 | }, 9 | id_partido: { 10 | type: type.STRING, 11 | primaryKey: true 12 | }, 13 | voto: type.INTEGER 14 | }, 15 | { 16 | timestamps: false 17 | } 18 | ); 19 | orientacao.associate = function (models) { 20 | orientacao.belongsTo(models.votacao, { 21 | foreignKey: "id_votacao", 22 | sourceKey: "id_votacao", 23 | as: "votacoesVoto" 24 | }), 25 | orientacao.belongsTo(models.partido, { 26 | foreignKey: "id_partido", 27 | sourceKey: "id_partido", 28 | as: "orientacoes" 29 | }); 30 | }; 31 | return orientacao; 32 | }; 33 | -------------------------------------------------------------------------------- /server/models/postgres/proposicao_temas.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | proposicao_tema = sequelize.define( 3 | "proposicoes_tema", 4 | { 5 | id_proposicao: { 6 | type: type.INTEGER, 7 | primaryKey: true 8 | }, 9 | id_tema: { 10 | type: type.INTEGER, 11 | primaryKey: true 12 | }, 13 | }, 14 | { 15 | timestamps: false 16 | }, 17 | ); 18 | proposicao_tema.associate = function(models) { 19 | proposicao_tema.belongsTo(models.proposicao, { 20 | foreignKey: "id_proposicao", 21 | sourceKey: "id_proposicao", 22 | as: "tema_prop" 23 | }), 24 | proposicao_tema.belongsTo(models.tema, { 25 | foreignKey: "id_tema", 26 | sourceKey: "id_tema", 27 | as: "temas_tema" 28 | }) 29 | }; 30 | 31 | return proposicao_tema; 32 | }; 33 | -------------------------------------------------------------------------------- /server/models/postgres/votacao.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | const votacao = sequelize.define( 3 | "votacoe", 4 | { 5 | id_votacao: { 6 | type: type.STRING, 7 | primaryKey: true 8 | }, 9 | id_proposicao: type.STRING, 10 | objeto_votacao: type.STRING, 11 | horario: type.DATE, 12 | codigo_sessao: type.INTEGER 13 | }, 14 | { 15 | timestamps: false 16 | } 17 | ); 18 | votacao.associate = function(models) { 19 | votacao.belongsTo(models.proposicao, { 20 | foreignKey: "id_proposicao", 21 | sourceKey: "id_proposicao", 22 | as: "proposicaoVotacoes" 23 | }), 24 | votacao.hasMany(models.voto, { 25 | foreignKey: "id_votacao", 26 | sourceKey: "id_votacao", 27 | as: "votacoesVoto" 28 | }) 29 | }; 30 | return votacao; 31 | }; 32 | -------------------------------------------------------------------------------- /client/src/app/shared/components/progress-stacked/progress-stacked.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ProgressStackedComponent } from './progress-stacked.component'; 4 | 5 | describe('ProgressStackedComponent', () => { 6 | let component: ProgressStackedComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ProgressStackedComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ProgressStackedComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './src/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: require('path').join(__dirname, './tsconfig.e2e.json') 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; -------------------------------------------------------------------------------- /client/src/app/questionario/perguntas-container/perguntas-container.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PerguntasContainerComponent } from './perguntas-container.component'; 4 | 5 | describe('PerguntasComponent', () => { 6 | let component: PerguntasContainerComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PerguntasContainerComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PerguntasContainerComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/trajetoria-timeline/trajetoria-timeline.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TrajetoriaTimelineComponent } from './trajetoria-timeline.component'; 4 | 5 | describe('TrajetoriaTimelineComponent', () => { 6 | let component: TrajetoriaTimelineComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ TrajetoriaTimelineComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(TrajetoriaTimelineComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/votacao/votacao.component.scss: -------------------------------------------------------------------------------- 1 | .votacao { 2 | border: solid 2px #20201e; 3 | margin-bottom: 1rem; 4 | padding: 0.5rem; 5 | } 6 | 7 | .votacao-body { 8 | } 9 | 10 | .votacao-title { 11 | font-size: 1.2rem; 12 | padding-bottom: 0.5rem; 13 | } 14 | 15 | .votos { 16 | display: flex; 17 | flex-wrap: wrap; 18 | } 19 | 20 | .votos-header { 21 | width: 50px; 22 | text-align: right; 23 | font-size: 0.75rem; 24 | line-height: 21px; 25 | 26 | @media (min-width: 576px) { 27 | width: 105px; 28 | } 29 | } 30 | 31 | .votos-box { 32 | display: flex; 33 | flex-direction: column; 34 | padding-right: 2px; 35 | margin-bottom: 20px; 36 | } 37 | 38 | .tooltip-votacao { 39 | min-width: 300px; 40 | 41 | .text-votante { 42 | font-size: 0.75rem; 43 | } 44 | } 45 | 46 | .text-date { 47 | font-size: 0.8rem; 48 | color: #6c757d; 49 | } 50 | -------------------------------------------------------------------------------- /client/src/app/shared/components/sticky-footer-navbar/sticky-footer-navbar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | import { Subject } from 'rxjs'; 4 | import { takeUntil } from 'rxjs/operators'; 5 | 6 | import { CasaService } from '../../services/casa.service'; 7 | 8 | @Component({ 9 | selector: 'app-sticky-footer-navbar', 10 | templateUrl: './sticky-footer-navbar.component.html', 11 | styleUrls: ['./sticky-footer-navbar.component.scss'] 12 | }) 13 | export class StickyFooterNavbarComponent implements OnInit { 14 | 15 | private unsubscribe = new Subject(); 16 | 17 | casa: string; 18 | 19 | constructor(private casaService: CasaService) { } 20 | 21 | ngOnInit() { 22 | this.casaService.get().pipe(takeUntil(this.unsubscribe)).subscribe(casa => this.casa = casa); 23 | } 24 | 25 | getCasa() { 26 | return this.casa; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /client/src/app/shared/services/pergunta.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | 4 | import { Observable } from 'rxjs'; 5 | 6 | import { environment } from '../../../environments/environment'; 7 | 8 | import { Proposicao } from '../models/proposicao.model'; 9 | import { Pergunta } from '../models/pergunta.model'; 10 | 11 | 12 | @Injectable({ 13 | providedIn: 'root' 14 | }) 15 | export class PerguntaService { 16 | 17 | private url = environment.apiUrl + 'perguntas'; 18 | 19 | constructor(private http: HttpClient) { } 20 | 21 | getProposicoes(): Observable { 22 | return this.http.get(this.url + '/proposicoes'); 23 | } 24 | 25 | getProposicao(id: string): Observable { 26 | return this.http.get (this.url + '/proposicoes/' + id); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /client/src/app/busca-parlamentar/lista-parlamentares/lista-parlamentares.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ListaParlamentaresComponent } from './lista-parlamentares.component'; 4 | 5 | describe('ListaParlamentaresComponent', () => { 6 | let component: ListaParlamentaresComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ListaParlamentaresComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ListaParlamentaresComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/sticky-footer-navbar/sticky-footer-navbar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { StickyFooterNavbarComponent } from './sticky-footer-navbar.component'; 4 | 5 | describe('StickyFooterNavbarComponent', () => { 6 | let component: StickyFooterNavbarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ StickyFooterNavbarComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(StickyFooterNavbarComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/alinhamento/congresso-alinhamento/congresso-alinhamento.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CongressoAlinhamentoComponent } from './congresso-alinhamento.component'; 4 | 5 | describe('CongressoAlinhamentoComponent', () => { 6 | let component: CongressoAlinhamentoComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CongressoAlinhamentoComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CongressoAlinhamentoComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/main/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, OnDestroy } from '@angular/core'; 2 | 3 | import { Subject } from 'rxjs'; 4 | import { takeUntil } from 'rxjs/operators'; 5 | 6 | import { LoginService } from 'src/app/shared/services/login.service'; 7 | 8 | @Component({ 9 | selector: 'app-home', 10 | templateUrl: './home.component.html', 11 | styleUrls: ['./home.component.scss'] 12 | }) 13 | export class HomeComponent implements OnInit, OnDestroy { 14 | 15 | isLoggedIn: boolean; 16 | 17 | private unsubscribe = new Subject(); 18 | 19 | constructor(private loginService: LoginService) { } 20 | 21 | ngOnInit() { 22 | this.loginService.isLoggedIn().pipe(takeUntil(this.unsubscribe)).subscribe(res => 23 | this.isLoggedIn = res 24 | ); 25 | } 26 | 27 | ngOnDestroy() { 28 | this.unsubscribe.next(); 29 | this.unsubscribe.complete(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /server/models/postgres/liderancas.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | lideranca = sequelize.define( 3 | "lideranca", 4 | { 5 | id_parlamentar_voz: { 6 | type: type.STRING, 7 | primaryKey: true 8 | }, 9 | id_partido: { 10 | type: type.STRING, 11 | primaryKey: true 12 | }, 13 | cargo: type.STRING, 14 | casa: type.STRING 15 | }, 16 | { 17 | timestamps: false 18 | } 19 | ); 20 | lideranca.associate = function (models) { 21 | lideranca.belongsTo(models.parlamentar, { 22 | foreignKey: "id_parlamentar_voz", 23 | sourceKey: "id_parlamentar_voz", 24 | as: "liderancaParlamentar" 25 | }), 26 | lideranca.belongsTo(models.partido, { 27 | foreignKey: "id_partido", 28 | sourceKey: "id_partido", 29 | as: "liderancaPartido" 30 | }) 31 | }; 32 | return lideranca; 33 | }; 34 | -------------------------------------------------------------------------------- /client/src/app/aderencia/congresso-chart-legenda/congresso-chart-legenda.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CongressoChartLegendaComponent } from './congresso-chart-legenda.component'; 4 | 5 | describe('CongressoChartLegendaComponent', () => { 6 | let component: CongressoChartLegendaComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CongressoChartLegendaComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CongressoChartLegendaComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/busca-parlamentar/card-busca-parlamentar/card-busca-parlamentar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CardBuscaParlamentarComponent } from './card-busca-parlamentar.component'; 4 | 5 | describe('CardBuscaParlamentarComponent', () => { 6 | let component: CardBuscaParlamentarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CardBuscaParlamentarComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CardBuscaParlamentarComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/aderencia/aderencia-parlamentares/aderencia-parlamentares.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AderenciaParlamentaresComponent } from './aderencia-parlamentares.component'; 4 | 5 | describe('AderenciaParlamentaresComponent', () => { 6 | let component: AderenciaParlamentaresComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [AderenciaParlamentaresComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(AderenciaParlamentaresComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /server/config/keys.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | mongoURI: process.env.MONGODB_URI, 3 | secretOrKey: process.env.SECRET_OR_KEY, 4 | postgresURI: process.env.POSTGRESURI, 5 | 6 | facebookAppID: process.env.FACEBOOK_APP_ID, 7 | facebookAppSecret: process.env.FACEBOOK_APP_SECRET, 8 | facebookCallbackURL: "https://localhost:5000/api/auth/facebook/callback", 9 | facebookProfileURL: 10 | "https://graph.facebook.com/v2.5/me?fields=first_name,last_name,email", 11 | facebookRedirectURI: process.env.FACEBOOK_REDIRECT_URI, 12 | 13 | googleAppID: process.env.GOOGLE_APP_ID, 14 | googleAppSecret: process.env.GOOGLE_APP_SECRET, 15 | googleCallbackURL: "https://localhost:5000/api//auth/google/callback", 16 | 17 | twitterConsumerKey: process.env.TWITTER_CONSUMER_KEY, 18 | twitterConsumerSecret: process.env.TWITTER_CONSUMER_SECRET, 19 | twitterCallbackURL: "https://localhost:5000/api/auth/twitter/callback" 20 | }; 21 | -------------------------------------------------------------------------------- /client/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false, 7 | apiUrl: 'http://localhost:5000/api/', 8 | facebookAppID: '286005595424109', 9 | googleAppID: '791030988243-msi1r67ltvd5v1fjtajj3un1f0c0d7ds.apps.googleusercontent.com' 10 | }; 11 | 12 | /* 13 | * For easier debugging in development mode, you can import the following file 14 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 15 | * 16 | * This import should be commented out in production mode because it will have a negative impact 17 | * on performance if an error is thrown. 18 | */ 19 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 20 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/despesas-cota-parlamentar/despesas-cota-parlamentar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DespesasCotaParlamentarComponent } from './despesas-cota-parlamentar.component'; 4 | 5 | describe('DespesasCotaParlamentarComponent', () => { 6 | let component: DespesasCotaParlamentarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ DespesasCotaParlamentarComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DespesasCotaParlamentarComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /server/models/postgres/pergunta.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | const pergunta = sequelize.define( 3 | "perguntas", 4 | { 5 | texto: type.STRING(500), 6 | id: { 7 | type: type.INTEGER, 8 | primaryKey: true 9 | } 10 | }, 11 | { 12 | timestamps: false 13 | } 14 | ); 15 | 16 | pergunta.associate = function (models) { 17 | pergunta.belongsTo(models.tema, { 18 | foreignKey: "tema_id", 19 | as: "tema_perg", 20 | targetKey: "id_tema" 21 | }), 22 | pergunta.hasMany(models.resposta, { 23 | foreignKey: "pergunta_id", 24 | as: "perg_resp" 25 | }), 26 | pergunta.hasMany(models.respostau, { 27 | foreignKey: "pergunta_id", 28 | as: "uperg_resp" 29 | }), 30 | pergunta.hasMany(models.votacao, { 31 | foreignKey: "id_proposicao", 32 | as: "votProp" 33 | }) 34 | }; 35 | return pergunta; 36 | }; 37 | -------------------------------------------------------------------------------- /server/models/postgres/tema.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | const tema = sequelize.define( 3 | "tema", 4 | { 5 | tema: type.STRING, 6 | id_tema: { 7 | type: type.INTEGER, 8 | primaryKey: true 9 | }, 10 | slug: type.STRING, 11 | ativo: type.BOOLEAN 12 | }, 13 | { 14 | timestamps: false 15 | }, 16 | ); 17 | 18 | tema.associate = function(models) { 19 | tema.hasMany(models.pergunta, { 20 | foreignKey: "tema_id", 21 | as: "tema_perg" 22 | }), 23 | tema.belongsToMany(models.proposicao, { 24 | through: { 25 | model: models.proposicaoTemas, 26 | unique: false 27 | }, 28 | foreignKey: 'id_tema' 29 | }), 30 | tema.belongsTo(models.aderencia, { 31 | foreignKey: "id_tema", 32 | sourceKey: "id_tema", 33 | as: "aderenciaTema" 34 | }); 35 | }; 36 | return tema; 37 | }; 38 | -------------------------------------------------------------------------------- /server/models/postgres/investimento-partidario.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | investimentoPartidario = sequelize.define( 3 | "investimento_partidario", 4 | { 5 | id_partido: { 6 | type: type.STRING, 7 | primaryKey: true 8 | }, 9 | uf: { 10 | type: type.STRING, 11 | primaryKey: true 12 | }, 13 | esfera: { 14 | type: type.STRING, 15 | primaryKey: true 16 | }, 17 | valor: type.DECIMAL(15, 2), 18 | numero_candidatos: type.INTEGER 19 | }, 20 | { 21 | timestamps: false, 22 | freezeTableName: true 23 | } 24 | ); 25 | investimentoPartidario.associate = function (models) { 26 | investimentoPartidario.belongsTo(models.partido, { 27 | foreignKey: "id_partido", 28 | targetKey: "id_partido", 29 | as: "partidoInvestimento" 30 | }) 31 | }; 32 | return investimentoPartidario; 33 | }; 34 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/posicoes/posicoes.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 17 |
18 |
19 |
20 | 27 |
28 | -------------------------------------------------------------------------------- /server/models/postgres/atividades-economicas.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | atividadesEconomicas = sequelize.define( 3 | "atividades_economicas", 4 | { 5 | id_atividade_economica: { 6 | type: type.INTEGER, 7 | primaryKey: true 8 | }, 9 | nome: type.STRING 10 | }, 11 | { 12 | timestamps: false, 13 | freezeTableName: true 14 | } 15 | ); 16 | atividadesEconomicas.associate = function (models) { 17 | atividadesEconomicas.hasMany(models.ligacoesEconomicas, { 18 | foreignKey: "id_atividade_economica", 19 | targetKey: "id_atividade_economica", 20 | as: "parlamentarLigacoes" 21 | }), 22 | atividadesEconomicas.hasMany(models.atividadesEconomicasEmpresas, { 23 | foreignKey: "id_atividade_economica", 24 | targetKey: "id_atividade_economica", 25 | as: "atividadesEconomicasEmpresas" 26 | }) 27 | }; 28 | return atividadesEconomicas; 29 | }; 30 | -------------------------------------------------------------------------------- /client/src/app/shared/services/update.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | import { SwUpdate } from '@angular/service-worker'; 4 | import { MatSnackBar } from '@angular/material/snack-bar'; 5 | 6 | @Injectable() 7 | export class UpdateService { 8 | 9 | constructor( 10 | private swUpdate: SwUpdate, 11 | private snackbar: MatSnackBar) { 12 | 13 | if (!this.swUpdate.isEnabled) { 14 | console.log('SW indisponível'); 15 | } else { 16 | console.log('SW disponível'); 17 | } 18 | 19 | this.swUpdate.available.subscribe(event => { 20 | console.log('Versão instalada:', event.current); 21 | console.log('Versão disponível:', event.available); 22 | 23 | const snack = this.snackbar.open('Nova versão disponível', 'Atualizar'); 24 | 25 | snack 26 | .onAction() 27 | .subscribe(() => { 28 | window.location.reload(); 29 | }); 30 | 31 | }); 32 | 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /client/src/app/shared/services/votacao.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient, HttpParams } from '@angular/common/http'; 3 | 4 | import { Observable } from 'rxjs'; 5 | 6 | import { environment } from '../../../environments/environment'; 7 | import { CountVotacao } from '../models/countVotacao.model'; 8 | 9 | @Injectable({ 10 | providedIn: 'root' 11 | }) 12 | export class VotacaoService { 13 | private url = environment.apiUrl + 'votacoes'; 14 | 15 | 16 | constructor(private http: HttpClient) { } 17 | 18 | getCountVotacoes(casa: string): Observable { 19 | const params = new HttpParams().set('casa', casa); 20 | 21 | return this.http 22 | .get(this.url + '/', { params }); 23 | } 24 | 25 | getCountVotacoesPorTema(casa: string): Observable { 26 | const params = new HttpParams().set('casa', casa); 27 | 28 | return this.http 29 | .get(this.url + '/temas/', { params }); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /client/src/app/shared/services/orientacao.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient, HttpParams } from '@angular/common/http'; 3 | 4 | import { Observable } from 'rxjs'; 5 | 6 | import { environment } from '../../../environments/environment'; 7 | import { Orientacao } from '../models/orientacao.model'; 8 | import { Proposicao } from '../models/proposicao.model'; 9 | 10 | @Injectable({ 11 | providedIn: 'root' 12 | }) 13 | export class OrientacaoService { 14 | private url = environment.apiUrl + 'orientacoes'; 15 | 16 | constructor(private http: HttpClient) { } 17 | 18 | getOrientacoesGoverno(): Observable { 19 | return this.http 20 | .get(this.url + '/governo' ); 21 | } 22 | 23 | getProposicoesOrientacao(casa: string): Observable { 24 | const params = new HttpParams().set('casa', casa); 25 | 26 | return this.http 27 | .get(this.url + '/proposicoes', { params }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /server/routes/api/temas.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | 4 | const models = require("../../models/index"); 5 | 6 | const Tema = models.tema; 7 | 8 | const BAD_REQUEST = 400; 9 | const SUCCESS = 200; 10 | 11 | /** 12 | * @swagger 13 | * tags: 14 | * name: Temas 15 | * description: Recupera lista de temas usados no Perfil Parlamentar 16 | */ 17 | 18 | /** 19 | * @swagger 20 | * path: 21 | * /api/temas/: 22 | * get: 23 | * summary: Recupera lista de temas das proposições do Perfil Parlamentar 24 | * tags: [Temas] 25 | * responses: 26 | * "200": 27 | * description: Lista com temas usados no Perfil 28 | */ 29 | router.get("/", (req, res) => { 30 | Tema.findAll({ 31 | attributes: [["id_tema", "idTema"], "tema", "slug"], 32 | where: { ativo: true } 33 | }) 34 | .then(temas => res.status(SUCCESS).json(temas)) 35 | .catch(err => res.status(BAD_REQUEST).json({ err })); 36 | }); 37 | 38 | module.exports = router; 39 | -------------------------------------------------------------------------------- /server/models/postgres/empresas-parlamentares.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | empresasParlamentares = sequelize.define( 3 | "empresas_parlamentares", 4 | { 5 | id_parlamentar_voz: { 6 | type: type.STRING, 7 | primaryKey: true 8 | }, 9 | cnpj: { 10 | type: type.STRING, 11 | primaryKey: true 12 | }, 13 | data_entrada_sociedade: type.DATE 14 | }, 15 | { 16 | timestamps: false, 17 | freezeTableName: true 18 | } 19 | ); 20 | empresasParlamentares.associate = function (models) { 21 | empresasParlamentares.belongsTo(models.empresas, { 22 | foreignKey: "cnpj", 23 | sourceKey: "cnpj", 24 | as: "empresasParlamentares" 25 | }), 26 | empresasParlamentares.belongsTo(models.parlamentar, { 27 | foreignKey: "id_parlamentar_voz", 28 | sourceKey: "id_parlamentar_voz", 29 | as: "parlamentaresEmpresas" 30 | }) 31 | }; 32 | return empresasParlamentares; 33 | }; 34 | -------------------------------------------------------------------------------- /server/models/postgres/proposicao.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | proposicao = sequelize.define( 3 | "proposicoe", 4 | { 5 | id_proposicao: { 6 | type: type.INTEGER, 7 | primaryKey: true 8 | }, 9 | casa: type.STRING, 10 | projeto_lei: type.STRING, 11 | titulo: type.STRING, 12 | descricao: type.STRING(800), 13 | status_proposicao: type.STRING, 14 | status_importante: type.STRING, 15 | }, 16 | { 17 | timestamps: false 18 | }, 19 | ); 20 | proposicao.associate = function(models) { 21 | proposicao.hasMany(models.votacao, { 22 | foreignKey: "id_proposicao", 23 | targetKey: "id_proposicao", 24 | as: "proposicaoVotacoes" 25 | }), 26 | proposicao.belongsToMany(models.tema, { 27 | through: { 28 | model: models.proposicaoTemas, 29 | unique: false 30 | }, 31 | foreignKey: 'id_proposicao' 32 | }); 33 | }; 34 | 35 | return proposicao; 36 | }; 37 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/cargos/cargos.component.html: -------------------------------------------------------------------------------- 1 |
2 |
6 | Sem lideranças partidárias ou cargos em comissões. 7 |
8 |
12 |
13 |
Lideranças
14 |
15 |
16 | 17 |
18 |
19 |
23 |
24 |
Comissões
25 |
26 |
27 | 28 |
29 |
30 |
31 | -------------------------------------------------------------------------------- /client/src/app/shared/components/progress-stacked/progress-stacked.component.html: -------------------------------------------------------------------------------- 1 |
{{ titulo }}
2 |
3 |
13 |
14 |
15 |
16 |
26 | {{ categoria.valor }} 27 |
28 |
29 | -------------------------------------------------------------------------------- /client/src/app/questionario/questionario.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { FormsModule } from '@angular/forms'; 4 | 5 | import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; 6 | import { SharedModule } from '../shared/components/shared.module'; 7 | import { QuestionarioRoutingModule } from './questionario-routing.module'; 8 | 9 | import { PerguntasContainerComponent } from './perguntas-container/perguntas-container.component'; 10 | import { PerguntaComponent } from './pergunta/pergunta.component'; 11 | import { QuestionarioComponent } from './questionario.component'; 12 | import { TemasComponent } from './temas/temas.component'; 13 | 14 | @NgModule({ 15 | declarations: [ 16 | PerguntasContainerComponent, 17 | PerguntaComponent, 18 | QuestionarioComponent, 19 | TemasComponent 20 | ], 21 | imports: [ 22 | CommonModule, 23 | FormsModule, 24 | NgbModule, 25 | SharedModule, 26 | QuestionarioRoutingModule 27 | ] 28 | }) 29 | export class QuestionarioModule { } 30 | -------------------------------------------------------------------------------- /server/models/postgres/atividades-economicas-empresas.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | atividadesEconomicasEmpresas = sequelize.define( 3 | "atividades_economicas_empresas", 4 | { 5 | id_atividade_economica: { 6 | type: type.INTEGER, 7 | primaryKey: true 8 | }, 9 | cnpj: { 10 | type: type.STRING, 11 | primaryKey: true 12 | }, 13 | cnae_tipo: type.DATE 14 | }, 15 | { 16 | timestamps: false, 17 | freezeTableName: true 18 | } 19 | ); 20 | atividadesEconomicasEmpresas.associate = function (models) { 21 | atividadesEconomicasEmpresas.belongsTo(models.empresas, { 22 | foreignKey: "cnpj", 23 | sourceKey: "cnpj", 24 | as: "empresasAtividadesEconomicas" 25 | }), 26 | atividadesEconomicasEmpresas.belongsTo(models.atividadesEconomicas, { 27 | foreignKey: "id_atividade_economica", 28 | sourceKey: "id_atividade_economica", 29 | as: "atividadesEconomicasEmpresas" 30 | }) 31 | }; 32 | return atividadesEconomicasEmpresas; 33 | }; 34 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/card-empresa/card-empresa.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-card-empresa', 5 | templateUrl: './card-empresa.component.html', 6 | styleUrls: ['./card-empresa.component.scss'] 7 | }) 8 | export class CardEmpresaComponent { 9 | 10 | @Input() company: any; 11 | @Input() economicSectorColor: string; 12 | 13 | constructor() { } 14 | 15 | getFormattedSupplierTaxpayerId() { 16 | const taxpayerId = this.company.cnpj; 17 | if (!taxpayerId) return '-'; 18 | if(taxpayerId.length <= 15) { 19 | return taxpayerId.replace(/^(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/, '$1.$2.$3/$4-$5') 20 | } 21 | return taxpayerId; 22 | } 23 | 24 | checkIfNeedsMoreContrast() { 25 | const hexColor = this.economicSectorColor.slice(1); 26 | const r = parseInt(hexColor.substr(0,2),16); 27 | const g = parseInt(hexColor.substr(2,2),16); 28 | const b = parseInt(hexColor.substr(4,2),16); 29 | const yiq = ((r*299)+(g*587)+(b*114))/1000; 30 | return yiq >= 186; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /client/src/app/shared/services/comissao.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient, HttpParams } from '@angular/common/http'; 3 | 4 | import { Observable } from 'rxjs'; 5 | 6 | import { environment } from '../../../environments/environment'; 7 | import { Comissao } from '../models/comissao.model'; 8 | import { Lideranca } from '../models/lideranca.model'; 9 | import { CasaService } from './casa.service'; 10 | 11 | 12 | @Injectable({ 13 | providedIn: 'root' 14 | }) 15 | export class ComissaoService { 16 | 17 | private url = environment.apiUrl + 'comissoes'; 18 | 19 | constructor( 20 | private http: HttpClient) { } 21 | 22 | getComissoes(casa: string): Observable { 23 | const params = new HttpParams() 24 | .set('casa', casa); 25 | return this.http.get(this.url, { params }); 26 | } 27 | 28 | getCargos(casa: string): Observable { 29 | const params = new HttpParams() 30 | .set('casa', casa); 31 | return this.http.get(this.url + '/cargos', { params }); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /client/src/app/questionario/temas/temas.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Quais temas você tem mais interesse?

4 |
5 |
9 | 18 |
19 |
20 |
21 | 29 |
30 |
31 |
32 | -------------------------------------------------------------------------------- /client/src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage/vozativa'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /client/README.md: -------------------------------------------------------------------------------- 1 | # Perfil Parlamentar 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.3.0. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /server/models/postgres/ligacoes-economicas.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | ligacoesEconomicas = sequelize.define( 3 | "ligacoes_economicas", 4 | { 5 | id_parlamentar_voz: { 6 | type: type.STRING, 7 | primaryKey: true 8 | }, 9 | id_atividade_economica: { 10 | type: type.INTEGER, 11 | primaryKey: true 12 | }, 13 | total_por_atividade: type.DECIMAL(15, 2), 14 | proporcao_doacao: type.REAL, 15 | indice_ligacao_atividade_economica: type.REAL 16 | }, 17 | { 18 | timestamps: false, 19 | freezeTableName: true 20 | } 21 | ); 22 | ligacoesEconomicas.associate = function (models) { 23 | ligacoesEconomicas.belongsTo(models.atividadesEconomicas, { 24 | foreignKey: "id_atividade_economica", 25 | sourceKey: "id_atividade_economica", 26 | as: "ligacaoAtividade" 27 | }), 28 | ligacoesEconomicas.belongsTo(models.parlamentar, { 29 | foreignKey: "id_parlamentar_voz", 30 | sourceKey: "id_parlamentar_voz", 31 | as: "ligacaoParlamentar" 32 | }) 33 | }; 34 | return ligacoesEconomicas; 35 | }; 36 | -------------------------------------------------------------------------------- /client/src/app/main/home/home.component.html: -------------------------------------------------------------------------------- 1 | 2 | 36 | -------------------------------------------------------------------------------- /client/src/app/shared/services/perfil-politico.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { Observable } from 'rxjs'; 4 | import { map, take } from 'rxjs/operators'; 5 | import { EmpresasRelacionadas } from '../models/empresasRelacionadas.model'; 6 | 7 | @Injectable({ 8 | providedIn: 'root' 9 | }) 10 | export class PerfilPoliticoService { 11 | 12 | private url = 'https://api-perfilpolitico.serenata.ai/api/'; 13 | 14 | constructor(private http: HttpClient) { } 15 | 16 | get(idPerfilPolitico: string): Observable { 17 | return this.http.get<[]>(this.url + 'candidate/' + idPerfilPolitico + '/'); 18 | } 19 | 20 | getEconomicBonds(idPerfilPolitico: string): Observable{ 21 | const endpointPath = 'economic-bonds/candidate/'; 22 | return this.http.get(this.url + endpointPath + idPerfilPolitico + '/') 23 | .pipe(take(1)) 24 | .pipe(map(resp => new EmpresasRelacionadas(resp))); 25 | } 26 | 27 | getAssetStats(): Observable{ 28 | return this.http.get<[]>(this.url + 'asset-stats'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /client/src/app/user/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, OnDestroy } from '@angular/core'; 2 | 3 | import { Subject } from 'rxjs'; 4 | import { takeUntil } from 'rxjs/operators'; 5 | 6 | import { LoginService } from '../../shared/services/login.service'; 7 | 8 | @Component({ 9 | selector: 'app-login', 10 | templateUrl: './login.component.html', 11 | styleUrls: ['./login.component.scss'] 12 | }) 13 | export class LoginComponent implements OnInit, OnDestroy { 14 | 15 | isLoggedIn: boolean; 16 | 17 | private unsubscribe = new Subject(); 18 | 19 | constructor(private loginService: LoginService) { } 20 | 21 | ngOnInit() { 22 | this.loginService.isLoggedIn().pipe(takeUntil(this.unsubscribe)).subscribe(res => 23 | this.isLoggedIn = res 24 | ); 25 | } 26 | 27 | loginUserGoogle() { 28 | this.loginService.loginUserGoogle(); 29 | } 30 | 31 | loginUserFacebook() { 32 | this.loginService.loginUserFacebook(); 33 | } 34 | 35 | logoutUser() { 36 | this.loginService.logoutUser(); 37 | } 38 | 39 | ngOnDestroy() { 40 | this.unsubscribe.next(); 41 | this.unsubscribe.complete(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /server/routes/api/swagger.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const swaggerJsdoc = require("swagger-jsdoc"); 4 | const swaggerUi = require("swagger-ui-express"); 5 | 6 | // Swagger set up 7 | const options = { 8 | swaggerDefinition: { 9 | openapi: "3.0.0", 10 | info: { 11 | title: "API Perfil Parlamentar", 12 | version: "3.4.1", 13 | description: 14 | "Documentação da API do Perfil Parlamentar. Documentação construída usando como base o repositório de Alexander Karan", 15 | license: { 16 | name: "MIT", 17 | url: "https://choosealicense.com/licenses/mit/" 18 | }, 19 | contact: { 20 | name: "Perfil Parlamentar", 21 | url: "https://github.com/parlametria/perfil-parlamentar" 22 | } 23 | } 24 | }, 25 | apis: ["./server/routes/api/*.js"] 26 | }; 27 | 28 | const specs = swaggerJsdoc(options); 29 | router.use("/docs", swaggerUi.serve); 30 | router.get("/docs", swaggerUi.setup(specs, { explorer: true })); 31 | 32 | module.exports = router; 33 | -------------------------------------------------------------------------------- /client/src/app/shared/components/navbar/navbar.component.scss: -------------------------------------------------------------------------------- 1 | a:link.nav-link-login, 2 | a:visited.nav-link-login { 3 | width: 40px; 4 | text-align: right; 5 | color: #20201e; 6 | text-decoration: underline; 7 | } 8 | 9 | a:hover.nav-link-active, 10 | a:active.nav-link-active { 11 | color: #43a467; 12 | text-decoration: underline; 13 | } 14 | 15 | .img-user { 16 | width: 30px; 17 | height: 30px; 18 | border-radius: 50%; 19 | } 20 | 21 | .dropdown-toggle { 22 | cursor: pointer; 23 | } 24 | 25 | .dropdown-menu { 26 | padding: 0; 27 | border: solid 1px #20201E; 28 | } 29 | 30 | .navbrand-wrapper { 31 | width: 80px; 32 | 33 | @media (min-width: 992px) { 34 | width: 140px; 35 | } 36 | } 37 | 38 | .navbar-nav-va { 39 | @media (max-width: 991.98px) { 40 | display: none; 41 | } 42 | } 43 | 44 | .navbar-nav-va-link { 45 | padding: 22px 10px; 46 | width: 165px; 47 | text-decoration: none; 48 | text-transform: uppercase; 49 | font-size: 0.8rem; 50 | color: #20201e; 51 | 52 | &.active { 53 | font-weight: 700; 54 | background-color: #20201e; 55 | color: #fff; 56 | } 57 | } 58 | 59 | .nav-line { 60 | line-height: 40px; 61 | } 62 | -------------------------------------------------------------------------------- /server/models/postgres/composicao-comissoes.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | composicaoComissoes = sequelize.define( 3 | "composicao_comissoe", 4 | { 5 | id_comissao_voz: { 6 | type: type.STRING, 7 | primaryKey: true 8 | }, 9 | id_parlamentar_voz: { 10 | type: type.STRING, 11 | primaryKey: true 12 | }, 13 | id_periodo: { 14 | type: type.STRING, 15 | primaryKey: true 16 | }, 17 | cargo: type.STRING, 18 | situacao: type.STRING, 19 | data_inicio: type.DATE, 20 | data_fim: type.DATE, 21 | is_membro_atual: type.BOOLEAN 22 | }, 23 | { 24 | timestamps: false 25 | } 26 | ); 27 | composicaoComissoes.associate = function (models) { 28 | composicaoComissoes.belongsTo(models.comissoes, { 29 | foreignKey: "id_comissao_voz", 30 | sourceKey: "id_comissao_voz", 31 | as: "infoComissao" 32 | }), 33 | composicaoComissoes.belongsTo(models.parlamentar, { 34 | foreignKey: "id_parlamentar_voz", 35 | sourceKey: "id_parlamentar_voz", 36 | as: "comissaoParlamentar" 37 | }) 38 | }; 39 | return composicaoComissoes; 40 | }; 41 | -------------------------------------------------------------------------------- /server/models/postgres/votacaou.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | const votacaou = sequelize.define( 3 | "votacoesu", 4 | { 5 | resposta: type.INTEGER 6 | }, 7 | { 8 | timestamps: false 9 | } 10 | ); 11 | votacaou.associate = function(models) { 12 | votacaou.belongsTo(models.votacao, { 13 | foreignKey: "id_votacao", 14 | as: "usuarioVotacoes" 15 | }) 16 | }; 17 | 18 | votacaou.upsertResp = function(id_votacao, user_id, resposta, cb) { 19 | const that = this; 20 | return this.findOne({ 21 | where: { 22 | id_votacao: id_votacao, 23 | user_id: user_id 24 | } 25 | }).then((resp, err) => { 26 | if (!resp) { 27 | const newResp = new that({ 28 | id_votacao: id_votacao, 29 | user_id: user_id, 30 | resposta: resposta 31 | }); 32 | 33 | newResp.save().then((savedResp, error) => { 34 | if (error) { 35 | console.log(error); 36 | } 37 | return cb(savedResp, error); 38 | }); 39 | } else { 40 | resp.update({ resposta: resposta }); 41 | return cb(resp, err); 42 | } 43 | }); 44 | }; 45 | 46 | return votacaou; 47 | }; 48 | -------------------------------------------------------------------------------- /client/src/app/user/login/login.component.scss: -------------------------------------------------------------------------------- 1 | $facebook-color: #4267b2; 2 | $google-color: #fff; 3 | $google-font-color: #757575; 4 | 5 | .facebook-login-btn, 6 | .facebook-login-btn:not(:disabled):not(.disabled):active, 7 | .facebook-login-btn:not(:disabled):not(.disabled).active { 8 | background-color: $facebook-color; 9 | border-color: $facebook-color; 10 | } 11 | 12 | .facebook-login-btn:focus, 13 | .facebook-login-btn.focus { 14 | box-shadow: 0 0 0 0.2rem rgba($facebook-color, .5); 15 | } 16 | 17 | .google-login-btn, 18 | .google-login-btn:not(:disabled):not(.disabled):active, 19 | .google-login-btn:not(:disabled):not(.disabled).active { 20 | /* Especificações da marca da Google */ 21 | /* https://developers.google.com/identity/branding-guidelines */ 22 | background-color: $google-color; 23 | border-color: $google-color; 24 | color: $google-font-color; 25 | box-shadow: 0px 2px 5px 0px rgba(0,0,0,0.25); 26 | -webkit-box-shadow: 0px 2px 5px 0px rgba(0,0,0,0.25); 27 | -moz-box-shadow: 0px 2px 5px 0px rgba(0,0,0,0.25); 28 | 29 | font-family: 'Roboto'; 30 | font-size: 14px; 31 | font-weight: bold; 32 | } 33 | 34 | .google-login-btn:focus, 35 | .google-login-btn.focus { 36 | box-shadow: 0 0 0 0.2rem rgba($google-color, .5); 37 | } 38 | -------------------------------------------------------------------------------- /client/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async(() => { 7 | TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | })); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.debugElement.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | 23 | it(`should have as title 'vozativa'`, () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.debugElement.componentInstance; 26 | expect(app.title).toEqual('vozativa'); 27 | }); 28 | 29 | it('should render title in a h1 tag', () => { 30 | const fixture = TestBed.createComponent(AppComponent); 31 | fixture.detectChanges(); 32 | const compiled = fixture.debugElement.nativeElement; 33 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to vozativa!'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /server/models/postgres/candidato.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | candidato = sequelize.define( 3 | "candidato", 4 | { 5 | estado: type.STRING, 6 | uf: type.STRING, 7 | idade_posse: type.INTEGER, 8 | nome_coligacao: type.STRING, 9 | nome_candidato: type.STRING, 10 | cpf: { 11 | type: type.STRING, 12 | primaryKey: true 13 | }, 14 | recebeu: type.BOOLEAN, 15 | num_partido: type.STRING, 16 | email: type.STRING, 17 | nome_social: type.STRING, 18 | nome_urna: type.STRING, 19 | reeleicao: type.STRING, 20 | ocupacao: type.STRING, 21 | nome_exibicao: type.STRING, 22 | raca: type.STRING, 23 | tipo_agremiacao: type.STRING, 24 | n_candidatura: type.INTEGER, 25 | composicao_coligacao: type.STRING, 26 | tem_foto: type.INTEGER, 27 | partido: type.STRING, 28 | sg_partido: type.STRING, 29 | grau_instrucao: type.STRING, 30 | genero: type.STRING, 31 | eleito: type.BOOLEAN, 32 | respondeu: type.BOOLEAN, 33 | id_parlamentar: type.STRING 34 | }, 35 | { 36 | timestamps: false 37 | } 38 | ); 39 | candidato.associate = function (models) { 40 | }; 41 | return candidato; 42 | }; 43 | -------------------------------------------------------------------------------- /client/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | const routes: Routes = [ 5 | { path: '', loadChildren: () => import('./main/main.module').then(m => m.MainModule) }, 6 | { path: 'usuario', loadChildren: () => import('./user/user.module').then(m => m.UserModule) }, 7 | // { path: 'questionario', loadChildren: './questionario/questionario.module#QuestionarioModule' }, 8 | // { path: 'alinhamento', loadChildren: './alinhamento/alinhamento.module#AlinhamentoModule' }, 9 | { path: 'parlamentar', loadChildren: () => import('./parlamentar/parlamentar.module').then(m => m.ParlamentarModule) }, 10 | // { path: 'congresso', loadChildren: './congresso/congresso.module#CongressoModule' }, 11 | { path: 'aderencia', loadChildren: () => import('./aderencia/aderencia.module').then(m => m.AderenciaModule) }, 12 | { path: 'parlamentares', loadChildren: () => import('./busca-parlamentar/busca-parlamentar.module').then(m => m.BuscaParlamentarModule) }, 13 | { path: '**', redirectTo: '' } 14 | ]; 15 | 16 | @NgModule({ 17 | imports: [RouterModule.forRoot(routes, { 18 | scrollPositionRestoration: 'enabled' 19 | })], 20 | exports: [RouterModule] 21 | }) 22 | export class AppRoutingModule { } 23 | -------------------------------------------------------------------------------- /client/src/app/shared/auth/token.interceptor.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { 3 | HttpRequest, 4 | HttpHandler, 5 | HttpEvent, 6 | HttpInterceptor, 7 | HttpErrorResponse 8 | } from '@angular/common/http'; 9 | import { Router } from '@angular/router'; 10 | 11 | 12 | import { Observable } from 'rxjs'; 13 | import { tap } from 'rxjs/operators'; 14 | 15 | import { LoginService } from '../services/login.service'; 16 | 17 | @Injectable() 18 | export class TokenInterceptor implements HttpInterceptor { 19 | 20 | constructor( 21 | private loginService: LoginService, 22 | private router: Router 23 | ) { } 24 | 25 | intercept(request: HttpRequest, next: HttpHandler): Observable> { 26 | 27 | request = request.clone({ 28 | setHeaders: { 29 | Authorization: `${this.loginService.getToken()}` 30 | } 31 | }); 32 | 33 | return next.handle(request).pipe(tap((event: HttpEvent) => { 34 | }, (err: any) => { 35 | if (err instanceof HttpErrorResponse) { 36 | // Handle Unauthorized 37 | if (err.status === 401) { 38 | this.loginService.logoutUser(); 39 | this.router.navigate(['/usuario/login']); 40 | } 41 | } 42 | })); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /client/src/app/shared/services/casa.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Observable, Subject, BehaviorSubject } from 'rxjs'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class CasaService { 8 | 9 | private casa = new BehaviorSubject('camara'); 10 | 11 | constructor() {} 12 | 13 | get(): Observable { 14 | return this.casa; 15 | } 16 | 17 | set(casa: string) { 18 | this.casa.next(casa); 19 | } 20 | 21 | // Recupera casa a partir do id do parlamentar 22 | // Ids começados com 1 são da câmara, com 2 são do senado 23 | // Retorna undefined se nenhuma dessas condições é satisfeita 24 | getCasaFromId(id: string) { 25 | if (id !== undefined) { 26 | if (id.charAt(0) === '1') { 27 | return 'camara'; 28 | } else if (id.charAt(0) === '2') { 29 | return 'senado'; 30 | } 31 | } 32 | return undefined; 33 | } 34 | 35 | getNomeCasa(casa: string, preposicao: boolean): string { 36 | if (casa === 'camara') { 37 | const prep = (preposicao) ? 'da ' : ''; 38 | return prep + 'câmara'; 39 | } else if (casa === 'senado') { 40 | const prep = (preposicao) ? 'do ' : ''; 41 | return prep + 'senado'; 42 | } 43 | return ''; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /client/src/app/aderencia/congresso-chart/congresso-chart.component.scss: -------------------------------------------------------------------------------- 1 | .d3-tip { 2 | line-height: 1.25; 3 | padding: 10px; 4 | background: white; 5 | border-radius: 5px; 6 | border: 2px solid #20201e; 7 | z-index: 999; 8 | } 9 | 10 | .d3-tip strong { 11 | font-weight: bold; 12 | text-transform: capitalize; 13 | } 14 | 15 | .d3-tip .subtitle { 16 | font-weight: normal; 17 | color: #adb5bd; 18 | } 19 | 20 | .d3-tip:after { 21 | box-sizing: border-box; 22 | display: inline-block; 23 | font-size: 10px; 24 | width: 100%; 25 | line-height: 1; 26 | color: #20201e; 27 | content: "\25BC"; 28 | position: absolute; 29 | text-align: center; 30 | } 31 | 32 | .d3-tip.n:after { 33 | margin: -1px 0 0 0; 34 | top: 100%; 35 | left: 0; 36 | } 37 | 38 | @media (min-width: 992px) { 39 | .parlamento { 40 | padding-left: 150px; 41 | padding-right: 150px; 42 | } 43 | } 44 | 45 | @media (min-width: 1200px) { 46 | .parlamento { 47 | padding-left: 200px; 48 | padding-right: 200px; 49 | } 50 | } 51 | 52 | circle:hover { 53 | stroke: #515151; 54 | } 55 | 56 | .axis-congresso { 57 | > .tick { 58 | > line { 59 | stroke-width: 0.5; 60 | stroke-dasharray: 10, 2; 61 | stroke: #515151; 62 | } 63 | > text { 64 | color: #515151; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /client/src/app/shared/models/parlamentar.model.ts: -------------------------------------------------------------------------------- 1 | import { Partido } from './partido.model'; 2 | import { ComposicaoComissao } from './composicaoComissao.model'; 3 | 4 | export class Parlamentar { 5 | 6 | public idParlamentarVoz: string; 7 | public idParlamentar: string; 8 | public casa: string; 9 | public nomeEleitoral: string; 10 | public uf: string; 11 | public parlamentarPartido: Partido; 12 | public genero: string; 13 | public emExercicio: boolean; 14 | public votacoes: any; 15 | public alinhamento?: any; 16 | public comissoes?: ComposicaoComissao[]; 17 | 18 | constructor(parlamentar: any) { 19 | this.idParlamentarVoz = parlamentar.id_parlamentar_voz; 20 | this.idParlamentar = parlamentar.id_parlamentar; 21 | this.casa = parlamentar.casa; 22 | this.nomeEleitoral = parlamentar.nome_eleitoral; 23 | this.uf = parlamentar.uf; 24 | this.parlamentarPartido = parlamentar.parlamentarPartido; 25 | this.genero = parlamentar.genero; 26 | this.emExercicio = parlamentar.em_exercicio; 27 | this.votacoes = parlamentar.votacoes; 28 | this.alinhamento = parlamentar.alinhamento; 29 | this.comissoes = parlamentar.parlamentarComissoes; 30 | } 31 | 32 | getFoto(): string { 33 | return 'https://www.camara.leg.br/internet/deputado/bandep/' + this.idParlamentar + '.jpg'; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/card-reembolso/card-reembolso.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | import { ExpenseModel } from '../../shared/models/jarbas.models'; 3 | 4 | @Component({ 5 | selector: 'app-card-reembolso', 6 | templateUrl: './card-reembolso.component.html', 7 | styleUrls: ['./card-reembolso.component.scss'] 8 | }) 9 | export class CardReembolsoComponent { 10 | 11 | @Input() expenseDetails: ExpenseModel; 12 | 13 | getFormattedDate() { 14 | let day = this.expenseDetails.issueDay.toString(); 15 | let month = this.expenseDetails.issueMonth.toString(); 16 | const year = this.expenseDetails.issueYear.toString(); 17 | if (day.length < 2) day = '0' + day; 18 | if (month.length < 2) month = '0' + month; 19 | return day + '/' + month + '/' + year; 20 | } 21 | 22 | getFormattedTotalNetValue() { 23 | return this.expenseDetails.totalNetValue 24 | .toFixed(2) 25 | .split('.'). 26 | join(',') 27 | } 28 | 29 | getFormattedSupplierTaxpayerId() { 30 | const taxpayerId = this.expenseDetails.supplierCnpjOrCpf; 31 | if (!taxpayerId) return '-'; 32 | if(taxpayerId.length < 11){ 33 | return taxpayerId.replace(/^(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4') 34 | } 35 | return taxpayerId.replace(/^(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/, '$1.$2.$3/$4-$5') 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /client/src/app/aderencia/aderencia.component.scss: -------------------------------------------------------------------------------- 1 | .subtitle-wrapper { 2 | height: 50px; 3 | } 4 | 5 | .subtitle { 6 | flex-wrap: wrap; 7 | } 8 | 9 | .btn-toolbar { 10 | line-height: 3.2rem; 11 | justify-content: center; 12 | } 13 | 14 | .chart-controls-info { 15 | order: 0; 16 | line-height: 3.2rem; 17 | } 18 | 19 | .chart-controls-info2 { 20 | order: 2; 21 | @media (min-width: 992px) { 22 | order: 1; 23 | } 24 | } 25 | 26 | .chart-controls-btns { 27 | order: 1; 28 | @media (min-width: 992px) { 29 | order: 2; 30 | } 31 | } 32 | 33 | .controls { 34 | background-color: #ffffff; 35 | 36 | @media (max-width: 575.98px) { 37 | display: flex; 38 | justify-content: space-between; 39 | 40 | // position: -webkit-sticky; 41 | // position: sticky; 42 | // top: 93px; 43 | z-index: 1050; 44 | } 45 | } 46 | 47 | .count { 48 | display: flex; 49 | 50 | @media (max-width: 575.98px) { 51 | height: 80px; 52 | flex-direction: column; 53 | justify-content: center; 54 | min-width: 120px; 55 | font-size: 0.8rem; 56 | } 57 | } 58 | 59 | .votacoes-count { 60 | @media (min-width: 576px) { 61 | margin-left: 2rem; 62 | } 63 | } 64 | 65 | .controls-toolbar { 66 | line-height: 36px; 67 | 68 | @media (min-width: 576px) { 69 | display: flex; 70 | justify-content: center; 71 | } 72 | } 73 | 74 | -------------------------------------------------------------------------------- /client/src/app/busca-parlamentar/busca-parlamentar.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | import { NgxPaginationModule } from 'ngx-pagination'; 5 | import { LazyLoadImageModule, intersectionObserverPreset } from 'ng-lazyload-image'; 6 | import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; 7 | 8 | import { SharedModule } from '../shared/components/shared.module'; 9 | import { BuscaParlamentarRoutingModule } from './busca-parlamentar-routing.module'; 10 | import { FilterModule } from '../filter/filter.module'; 11 | 12 | import { BuscaParlamentarComponent } from './busca-parlamentar.component'; 13 | import { ListaParlamentaresComponent } from './lista-parlamentares/lista-parlamentares.component'; 14 | import { CardBuscaParlamentarComponent } from './card-busca-parlamentar/card-busca-parlamentar.component'; 15 | 16 | @NgModule({ 17 | declarations: [ 18 | BuscaParlamentarComponent, 19 | ListaParlamentaresComponent, 20 | CardBuscaParlamentarComponent 21 | ], 22 | imports: [ 23 | CommonModule, 24 | NgxPaginationModule, 25 | NgbModule, 26 | LazyLoadImageModule.forRoot({ 27 | preset: intersectionObserverPreset 28 | }), 29 | SharedModule, 30 | BuscaParlamentarRoutingModule, 31 | FilterModule 32 | ] 33 | }) 34 | export class BuscaParlamentarModule { } 35 | 36 | -------------------------------------------------------------------------------- /server/models/postgres/aderencia.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | aderencia = sequelize.define( 3 | "aderencias", 4 | { 5 | id_parlamentar_voz: { 6 | type: type.STRING, 7 | primaryKey: true 8 | }, 9 | id_partido: { 10 | type: type.INTEGER, 11 | primaryKey: true 12 | }, 13 | id_tema: { 14 | type: type.STRING, 15 | primaryKey: true 16 | }, 17 | faltou: type.INTEGER, 18 | partido_liberou: type.INTEGER, 19 | nao_seguiu: type.INTEGER, 20 | seguiu: type.INTEGER, 21 | aderencia: type.REAL 22 | }, 23 | { 24 | timestamps: false 25 | } 26 | ); 27 | aderencia.associate = function (models) { 28 | aderencia.belongsTo(models.parlamentar, { 29 | foreignKey: "id_parlamentar_voz", 30 | sourceKey: "id_parlamentar_voz", 31 | as: "parlamentarAderencia" 32 | }), 33 | aderencia.belongsTo(models.partido, { 34 | foreignKey: "id_partido", 35 | sourceKey: "id_partido", 36 | as: "partido" 37 | }), 38 | aderencia.belongsTo(models.tema, { 39 | foreignKey: "id_tema", 40 | sourceKey: "id_tema", 41 | as: "aderenciaTema" 42 | }) 43 | }; 44 | return aderencia; 45 | }; 46 | -------------------------------------------------------------------------------- /client/src/app/shared/components/navbar/navbar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, OnDestroy } from '@angular/core'; 2 | 3 | import { Subject } from 'rxjs'; 4 | import { takeUntil } from 'rxjs/operators'; 5 | 6 | import { LoginService } from '../../services/login.service'; 7 | import { CasaService } from '../../services/casa.service'; 8 | 9 | @Component({ 10 | selector: 'app-navbar', 11 | templateUrl: './navbar.component.html', 12 | styleUrls: ['./navbar.component.scss'] 13 | }) 14 | export class NavbarComponent implements OnInit, OnDestroy { 15 | 16 | private unsubscribe = new Subject(); 17 | 18 | userAuthenticated: boolean; 19 | user: any; 20 | casa: string; 21 | 22 | constructor( 23 | private loginService: LoginService, 24 | public casaService: CasaService) { } 25 | 26 | ngOnInit() { 27 | this.loginService.isLoggedIn().pipe(takeUntil(this.unsubscribe)).subscribe(res => { 28 | this.userAuthenticated = res; 29 | this.user = this.loginService.getCurrentUser(); 30 | }); 31 | this.casaService.get().pipe(takeUntil(this.unsubscribe)).subscribe(casa => this.casa = casa); 32 | } 33 | 34 | logoutUser() { 35 | this.loginService.logoutUser(); 36 | } 37 | 38 | getCasa() { 39 | return this.casa; 40 | } 41 | 42 | ngOnDestroy() { 43 | this.unsubscribe.next(); 44 | this.unsubscribe.complete(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /server/models/postgres/respostasU.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | respostau = sequelize.define( 3 | "respostasu", 4 | { 5 | resposta: type.INTEGER 6 | }, 7 | { 8 | timestamps: false 9 | } 10 | ); 11 | resposta.associate = function(models) { 12 | respostau.belongsTo(models.pergunta, { 13 | foreignKey: "pergunta_id", 14 | as: "uperg_resp" 15 | }), 16 | respostau.belongsTo(models.usuario, { 17 | foreignKey: "user_id", 18 | as: "user_resp" 19 | }); 20 | }; 21 | 22 | respostau.upsertResp = function(pergunta_id, user_id, resposta, cb) { 23 | const that = this; 24 | return this.findOne({ 25 | where: { 26 | pergunta_id: pergunta_id, 27 | user_id: user_id 28 | } 29 | }).then((resp, err) => { 30 | if (!resp) { 31 | const newResp = new that({ 32 | pergunta_id: pergunta_id, 33 | user_id: user_id, 34 | resposta: resposta 35 | }); 36 | 37 | newResp.save().then((savedResp, error) => { 38 | if (error) { 39 | console.log(error); 40 | } 41 | return cb(savedResp, error); 42 | }); 43 | } else { 44 | resp.update({ resposta: resposta }); 45 | return cb(resp, err); 46 | } 47 | }); 48 | }; 49 | 50 | return respostau; 51 | }; 52 | -------------------------------------------------------------------------------- /client/src/app/shared/services/tema.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { environment } from 'src/environments/environment'; 3 | import { Observable } from 'rxjs'; 4 | import { HttpClient } from '@angular/common/http'; 5 | 6 | import { Tema } from '../models/tema.model'; 7 | 8 | @Injectable({ 9 | providedIn: 'root' 10 | }) 11 | export class TemaService { 12 | 13 | private url = environment.apiUrl + 'temas'; 14 | 15 | readonly ID_PADRAO_TEMA_TODOS = '99'; 16 | readonly SLUG_PADRAO_TEMA_TODOS = 'todos'; 17 | 18 | constructor(private http: HttpClient) { } 19 | 20 | getTemas(): Observable { 21 | return this.http.get(this.url); 22 | } 23 | 24 | getTemaSlugById(temas: Tema[], id: number): string { 25 | let temaSlug; 26 | 27 | if (temas !== undefined && temas.length > 0) { 28 | temaSlug = temas.filter(t => t.idTema === id); 29 | } 30 | 31 | if (temaSlug !== undefined && temaSlug.length > 0) { 32 | return temaSlug[0].slug; 33 | } else { 34 | return this.SLUG_PADRAO_TEMA_TODOS; 35 | } 36 | } 37 | 38 | getTemaIdBySlug(temas: Tema[], slug: string): string { 39 | const tema = temas.filter(t => t.slug === slug); 40 | 41 | if (tema && tema.length > 0) { 42 | return String(tema[0].idTema); 43 | } else { 44 | return this.ID_PADRAO_TEMA_TODOS; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /client/src/app/shared/components/shared.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { RouterModule } from '@angular/router'; 4 | 5 | import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; 6 | 7 | import { NavbarComponent } from './navbar/navbar.component'; 8 | import { StickyFooterNavbarComponent } from './sticky-footer-navbar/sticky-footer-navbar.component'; 9 | import { ProgressComponent } from './progress/progress.component'; 10 | import { ProgressStackedComponent } from './progress-stacked/progress-stacked.component'; 11 | import { LoadingComponent } from './loading/loading.component'; 12 | import { LegendComponent } from './legend/legend.component'; 13 | import { FooterComponent } from './footer/footer.component'; 14 | 15 | @NgModule({ 16 | declarations: [ 17 | NavbarComponent, 18 | StickyFooterNavbarComponent, 19 | ProgressComponent, 20 | ProgressStackedComponent, 21 | LoadingComponent, 22 | LegendComponent, 23 | FooterComponent 24 | ], 25 | imports: [ 26 | CommonModule, 27 | RouterModule, 28 | NgbModule 29 | ], 30 | exports: [ 31 | NavbarComponent, 32 | StickyFooterNavbarComponent, 33 | ProgressComponent, 34 | ProgressStackedComponent, 35 | LoadingComponent, 36 | LegendComponent, 37 | FooterComponent 38 | ] 39 | }) 40 | export class SharedModule { } 41 | -------------------------------------------------------------------------------- /client/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnDestroy } from '@angular/core'; 2 | import { RouterOutlet, Router, NavigationEnd } from '@angular/router'; 3 | import { routeAnimation } from './app-routing-animation'; 4 | 5 | import { Subject } from 'rxjs'; 6 | import { takeUntil } from 'rxjs/operators'; 7 | 8 | import { UpdateService } from './shared/services/update.service'; 9 | 10 | declare let ga; 11 | 12 | @Component({ 13 | selector: 'app-root', 14 | templateUrl: './app.component.html', 15 | styleUrls: ['./app.component.scss'], 16 | animations: [ 17 | routeAnimation 18 | ] 19 | }) 20 | export class AppComponent implements OnDestroy { 21 | 22 | private unsubscribe = new Subject(); 23 | 24 | constructor( 25 | public router: Router, 26 | private updateService: UpdateService) { 27 | 28 | // subscribe to router events and send page views to google analytics 29 | this.router.events 30 | .pipe(takeUntil(this.unsubscribe)) 31 | .subscribe(event => { 32 | if (event instanceof NavigationEnd) { 33 | ga('set', 'page', event.urlAfterRedirects); 34 | ga('send', 'pageview'); 35 | } 36 | }); 37 | } 38 | 39 | prepareRoute(outlet: RouterOutlet) { 40 | return outlet && outlet.activatedRouteData && outlet.activatedRouteData.animation; 41 | } 42 | 43 | ngOnDestroy() { 44 | this.unsubscribe.next(); 45 | this.unsubscribe.complete(); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /client/src/app/aderencia/congresso-chart-legenda/congresso-chart-legenda.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 10 |
11 |
12 | 18 |
19 |
20 | 26 |
27 |
28 | 34 |
35 |
36 | 42 |
43 |
44 | 50 |
51 |
52 |
53 | -------------------------------------------------------------------------------- /client/src/app/alinhamento/alinhamento.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { RouterModule } from '@angular/router'; 4 | import { FormsModule } from '@angular/forms'; 5 | 6 | import { NgxPaginationModule } from 'ngx-pagination'; 7 | import { LazyLoadImageModule, intersectionObserverPreset } from 'ng-lazyload-image'; 8 | import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; 9 | 10 | import { SharedModule } from '../shared/components/shared.module'; 11 | import { AlinhamentoRoutingModule } from './alinhamento-routing.module'; 12 | import { FilterModule } from '../filter/filter.module'; 13 | 14 | import { AlinhamentoComponent } from './alinhamento.component'; 15 | import { CardParlamentarComponent } from './card-parlamentar/card-parlamentar.component'; 16 | import { CongressoAlinhamentoComponent } from './congresso-alinhamento/congresso-alinhamento.component'; 17 | 18 | @NgModule({ 19 | declarations: [ 20 | AlinhamentoComponent, 21 | CardParlamentarComponent, 22 | CongressoAlinhamentoComponent 23 | ], 24 | imports: [ 25 | CommonModule, 26 | RouterModule, 27 | FormsModule, 28 | NgxPaginationModule, 29 | NgbModule, 30 | LazyLoadImageModule.forRoot({ 31 | preset: intersectionObserverPreset 32 | }), 33 | SharedModule, 34 | AlinhamentoRoutingModule, 35 | FilterModule 36 | ] 37 | }) 38 | export class AlinhamentoModule { } 39 | -------------------------------------------------------------------------------- /client/src/app/shared/models/parlamentarInfo.model.ts: -------------------------------------------------------------------------------- 1 | import { Partido } from './partido.model'; 2 | 3 | export class ParlamentarInfo { 4 | 5 | public idParlamentarVoz: string; 6 | public idParlamentar: string; 7 | public casa: string; 8 | public nomeEleitoral: string; 9 | public uf: string; 10 | public parlamentarPartido: Partido; 11 | public emExercicio: boolean; 12 | public idPerfilPolitico: string; 13 | 14 | constructor(parlamentar: any) { 15 | this.idParlamentarVoz = parlamentar.id_parlamentar_voz; 16 | this.idParlamentar = parlamentar.id_parlamentar; 17 | this.casa = parlamentar.casa; 18 | this.nomeEleitoral = parlamentar.nome_eleitoral; 19 | this.uf = parlamentar.uf; 20 | this.parlamentarPartido = parlamentar.parlamentarPartido; 21 | this.emExercicio = parlamentar.em_exercicio; 22 | this.idPerfilPolitico = parlamentar.id_perfil_politico; 23 | } 24 | 25 | getFoto(): string { 26 | if (this.casa === 'camara') { 27 | return 'https://www.camara.leg.br/internet/deputado/bandep/' + this.idParlamentar + '.jpg'; 28 | } else if (this.casa === 'senado') { 29 | return 'https://www.senado.leg.br/senadores/img/fotos-oficiais/senador' + this.idParlamentar + '.jpg'; 30 | } 31 | return ''; 32 | } 33 | 34 | getExpensesReportUrl(): string { 35 | if (this.idParlamentar) { 36 | return 'https://www.camara.leg.br/deputados/' + this.idParlamentar + '#gastos-section' 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/trajetoria/trajetoria.component.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | Trajetória Política 4 | 5 |

6 | 7 |
8 | Falha ao buscar as informações. 9 |
10 |
11 | 12 |
13 |
14 |
15 | 16 | 17 | 29 | 42 | 43 | -------------------------------------------------------------------------------- /server/config/passport.js: -------------------------------------------------------------------------------- 1 | const passport = require("passport"); 2 | const FacebookTokenStrategy = require("passport-facebook-token"); 3 | const GoogleTokenStrategy = require("passport-google-token").Strategy; 4 | const models = require("../models/index"); 5 | const Usuario = models.usuario; 6 | 7 | const keys = require("./keys"); 8 | 9 | module.exports = () => { 10 | passport.use( 11 | new FacebookTokenStrategy( 12 | { 13 | clientID: keys.facebookAppID, 14 | clientSecret: keys.facebookAppSecret, 15 | passReqToCallback: true 16 | }, 17 | (req, accessToken, refreshToken, profile, done) => { 18 | Usuario.upsertFbUser( 19 | accessToken, 20 | refreshToken, 21 | profile, 22 | req.body.respostas, 23 | (user, err) => { 24 | return done(err, user); 25 | } 26 | ); 27 | } 28 | ) 29 | ); 30 | 31 | passport.use( 32 | new GoogleTokenStrategy( 33 | { 34 | clientID: keys.googleAppID, 35 | clientSecret: keys.googleAppSecret, 36 | passReqToCallback: true 37 | }, 38 | (req, accessToken, refreshToken, profile, done) => { 39 | Usuario.upsertGoogleUser( 40 | accessToken, 41 | refreshToken, 42 | profile, 43 | req.body.respostas, 44 | (user, err) => { 45 | return done(err, user); 46 | } 47 | ); 48 | } 49 | ) 50 | ); 51 | }; 52 | -------------------------------------------------------------------------------- /server/models/postgres/investimento-partidario-parlamentar.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | investimentoPartidarioParlamentar = sequelize.define( 3 | "investimento_partidario_parlamentar", 4 | { 5 | id_parlamentar_voz: { 6 | type: type.STRING, 7 | primaryKey: true 8 | }, 9 | id_partido_atual: type.INTEGER, 10 | id_partido_eleicao: type.INTEGER, 11 | total_receita_partido: type.DECIMAL(15, 2), 12 | total_receita_candidato: type.DECIMAL(15, 2), 13 | indice_investimento_partido: type.REAL 14 | }, 15 | { 16 | timestamps: false, 17 | freezeTableName: true 18 | } 19 | ); 20 | investimentoPartidarioParlamentar.associate = function (models) { 21 | investimentoPartidarioParlamentar.belongsTo(models.parlamentar, { 22 | foreignKey: "id_parlamentar_voz", 23 | sourceKey: "id_parlamentar_voz", 24 | as: "parlamentarInvestimento" 25 | }), 26 | investimentoPartidarioParlamentar.belongsTo(models.partido, { 27 | foreignKey: "id_partido_atual", 28 | targetKey: "id_partido", 29 | as: "partidoAtual" 30 | }), 31 | investimentoPartidarioParlamentar.belongsTo(models.partido, { 32 | foreignKey: "id_partido_eleicao", 33 | targetKey: "id_partido", 34 | as: "partidoEleicao" 35 | }) 36 | }; 37 | return investimentoPartidarioParlamentar; 38 | }; 39 | -------------------------------------------------------------------------------- /client/src/assets/styles/animations.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Animações base 3 | * 4 | * Baseado no projeto de https://github.com/daneden/animate.css 5 | */ 6 | .animated { 7 | animation-duration: 1s; 8 | animation-fill-mode: both; 9 | 10 | &.infinite { 11 | animation-iteration-count: infinite; 12 | } 13 | &.delay-1s { 14 | animation-delay: 1s; 15 | } 16 | 17 | &.delay-2s { 18 | animation-delay: 2s; 19 | } 20 | 21 | &.delay-3s { 22 | animation-delay: 3s; 23 | } 24 | 25 | &.delay-4s { 26 | animation-delay: 4s; 27 | } 28 | 29 | &.delay-5s { 30 | animation-delay: 5s; 31 | } 32 | 33 | &.fast { 34 | animation-duration: 800ms; 35 | } 36 | 37 | &.faster { 38 | animation-duration: 500ms; 39 | } 40 | 41 | &.slow { 42 | animation-duration: 2s; 43 | } 44 | 45 | &.slower { 46 | animation-duration: 3s; 47 | } 48 | 49 | @media (print), (prefers-reduced-motion) { 50 | animation: unset !important; 51 | transition: none !important; 52 | } 53 | } 54 | 55 | /** 56 | * flash 57 | */ 58 | @keyframes flash { 59 | from, 60 | 50%, 61 | to { 62 | opacity: 1; 63 | } 64 | 65 | 25%, 66 | 75% { 67 | opacity: 0; 68 | } 69 | } 70 | 71 | .flash { 72 | animation-name: flash; 73 | } 74 | 75 | @keyframes flashinverse { 76 | from, 77 | 50%, 78 | to { 79 | opacity: 0; 80 | } 81 | 82 | 25%, 83 | 75% { 84 | opacity: 1; 85 | } 86 | } 87 | 88 | .flashinverse { 89 | animation-name: flashinverse; 90 | } 91 | -------------------------------------------------------------------------------- /client/src/ngsw-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "index": "/index.html", 3 | "assetGroups": [ 4 | { 5 | "name": "app", 6 | "installMode": "prefetch", 7 | "resources": { 8 | "files": [ 9 | "/favicon.ico", 10 | "/index.html", 11 | "/*.css", 12 | "/*.js", 13 | "/*.woff", 14 | "/*.ttf", 15 | "/*.eot", 16 | "/*.svg" 17 | ] 18 | } 19 | }, 20 | { 21 | "name": "icons", 22 | "installMode": "lazy", 23 | "updateMode": "prefetch", 24 | "resources": { 25 | "urls": [ 26 | "/*.woff*", 27 | "/*.ttf*", 28 | "/*.eot*", 29 | "/*.svg*" 30 | ] 31 | } 32 | }, 33 | { 34 | "name": "assets", 35 | "installMode": "lazy", 36 | "updateMode": "prefetch", 37 | "resources": { 38 | "files": [ 39 | "/assets/**" 40 | ] 41 | } 42 | }, 43 | { 44 | "name": "fonts", 45 | "installMode": "lazy", 46 | "updateMode": "lazy", 47 | "resources": { 48 | "urls": [ 49 | "/^https:\/\/fonts.(?:googleapis|gstatic).com\/.*/" 50 | ] 51 | } 52 | } 53 | ], 54 | "dataGroups": [ 55 | { 56 | "name": "api", 57 | "urls": [ 58 | "/api/*" 59 | ], 60 | "cacheConfig": { 61 | "maxSize": 10, 62 | "maxAge": "360d", 63 | "strategy": "freshness" 64 | } 65 | } 66 | ] 67 | } 68 | -------------------------------------------------------------------------------- /client/src/app/busca-parlamentar/card-busca-parlamentar/card-busca-parlamentar.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
7 |
8 | 9 | 16 | 17 |
18 |
19 |
20 |
21 | 25 | {{ parlamentar.nomeEleitoral | titlecase }} 26 | 27 | 28 | {{ parlamentar.parlamentarPartido?.sigla }}/{{ parlamentar.uf }} 29 | 30 |
31 |
35 | {{ parlamentar.parlamentarPartido?.sigla }}/{{ parlamentar.uf }} 36 |
37 |
38 |
39 |
40 | -------------------------------------------------------------------------------- /client/src/app/busca-parlamentar/lista-parlamentares/lista-parlamentares.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnDestroy, Input } from '@angular/core'; 2 | import { Router, ActivatedRoute, Params } from '@angular/router'; 3 | 4 | import { Subject } from 'rxjs'; 5 | 6 | import { ParlamentarAderencia } from 'src/app/shared/models/parlamentarAderencia.model'; 7 | 8 | @Component({ 9 | selector: 'app-lista-parlamentares', 10 | templateUrl: './lista-parlamentares.component.html', 11 | styleUrls: ['./lista-parlamentares.component.scss'] 12 | }) 13 | export class ListaParlamentaresComponent implements OnDestroy { 14 | 15 | readonly VIEW_SM = 'sm'; 16 | readonly VIEW_MD = 'md'; 17 | 18 | @Input() parlamentares: ParlamentarAderencia[]; 19 | @Input() filter: any; 20 | @Input() view: any; 21 | 22 | private unsubscribe = new Subject(); 23 | 24 | p = 1; 25 | isLoading: boolean; 26 | 27 | constructor( 28 | private activatedRoute: ActivatedRoute, 29 | private router: Router) { } 30 | 31 | pageChange(p: number) { 32 | this.p = p; 33 | 34 | const queryParams: Params = Object.assign({}, this.activatedRoute.snapshot.queryParams); 35 | queryParams.page = p; 36 | this.router.navigate([], { queryParams }); 37 | } 38 | 39 | getParlamentarPosition( 40 | index: number, 41 | itensPerPage: number, 42 | currentPage: number 43 | ) { 44 | return (itensPerPage * (currentPage - 1)) + index + 1; 45 | } 46 | 47 | ngOnDestroy() { 48 | this.unsubscribe.next(); 49 | this.unsubscribe.complete(); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /client/src/app/aderencia/aderencia.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | import { NgxPaginationModule } from 'ngx-pagination'; 5 | import { LazyLoadImageModule, intersectionObserverPreset } from 'ng-lazyload-image'; 6 | import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; 7 | 8 | import { SharedModule } from '../shared/components/shared.module'; 9 | import { AderenciaRoutingModule } from './aderencia-routing.module'; 10 | import { FilterModule } from '../filter/filter.module'; 11 | 12 | import { AderenciaComponent } from './aderencia.component'; 13 | import { AderenciaParlamentaresComponent } from './aderencia-parlamentares/aderencia-parlamentares.component'; 14 | import { CardParlamentarComponent } from './card-parlamentar/card-parlamentar.component'; 15 | import { CongressoChartLegendaComponent } from './congresso-chart-legenda/congresso-chart-legenda.component'; 16 | import { CongressoChartComponent } from './congresso-chart/congresso-chart.component'; 17 | 18 | @NgModule({ 19 | declarations: [ 20 | AderenciaComponent, 21 | AderenciaParlamentaresComponent, 22 | CardParlamentarComponent, 23 | CongressoChartLegendaComponent, 24 | CongressoChartComponent 25 | ], 26 | imports: [ 27 | CommonModule, 28 | FilterModule, 29 | SharedModule, 30 | NgxPaginationModule, 31 | NgbModule, 32 | LazyLoadImageModule.forRoot({ 33 | preset: intersectionObserverPreset 34 | }), 35 | AderenciaRoutingModule 36 | ] 37 | }) 38 | export class AderenciaModule { } 39 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/vinculos/vinculos.component.scss: -------------------------------------------------------------------------------- 1 | hr.divider { 2 | border-top: 3px solid #343a40; 3 | border-radius: 5px; 4 | } 5 | 6 | .section-title { 7 | text-align: center; 8 | font-weight: 600; 9 | margin-top: 30px; 10 | margin-bottom: 30px; 11 | } 12 | 13 | .empty-state-text { 14 | text-align: center; 15 | color: #666666; 16 | &.extra-margin { 17 | margin-bottom: 40px; 18 | } 19 | } 20 | 21 | .icon-ajuda { 22 | font-size: 0.8rem; 23 | vertical-align: top; 24 | &:hover { 25 | cursor: default; 26 | } 27 | } 28 | 29 | .hint { 30 | visibility: hidden; 31 | margin-left: -135px; 32 | margin-top: -152px; 33 | max-width: 250px; 34 | position: absolute; 35 | text-align: left; 36 | font-weight: normal; 37 | font-size: 0.85rem; 38 | color: #212529; 39 | background-color: white; 40 | padding: 5px; 41 | border: 2px solid #b7b7b7; 42 | border-radius: 2px; 43 | z-index: 1000; 44 | -webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.175); 45 | box-shadow: 0 1px 5px rgba(0, 0, 0, 0.175); 46 | 47 | &.small-balloon { 48 | margin-top: -85px; 49 | } 50 | 51 | > a { 52 | margin-top: 4px; 53 | } 54 | 55 | &:after { 56 | content: " "; 57 | position: absolute; 58 | top: 100%; 59 | left: 50%; 60 | margin-left: -5px; 61 | margin-top: 1px; 62 | border-width: 8px; 63 | border-style: solid; 64 | border-color: #b7b7b7 transparent transparent transparent; 65 | } 66 | 67 | &:hover { 68 | visibility: visible; 69 | } 70 | } 71 | 72 | .icon-ajuda:hover~.hint { 73 | visibility: visible; 74 | } 75 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/patrimonio-chart/patrimonio-chart.component.scss: -------------------------------------------------------------------------------- 1 | .axis-patrimonio { 2 | > .tick { 3 | > line { 4 | opacity: 0.7; 5 | stroke-width: 1.2; 6 | stroke: #ced4da; 7 | } 8 | &.normal { 9 | > line { 10 | opacity: 0; 11 | } 12 | } 13 | &.opaque { 14 | opacity: 0; 15 | > text { 16 | visibility: hidden; 17 | } 18 | } 19 | } 20 | > .tick:first-child { 21 | > line { 22 | opacity: 1; 23 | stroke: #595959; 24 | stroke-width: 2; 25 | } 26 | } 27 | > .tick:nth-child(even) { 28 | > line { 29 | opacity: 0.4; 30 | } 31 | } 32 | } 33 | 34 | .patrimonio-legend:hover { 35 | cursor: pointer; 36 | font-weight: bold; 37 | } 38 | 39 | .tip-patrimonio { 40 | line-height: 1.25; 41 | padding: 10px; 42 | background: white; 43 | border-radius: 5px; 44 | border: 2px solid #20201e; 45 | z-index: 999; 46 | } 47 | 48 | .tip-patrimonio strong { 49 | font-weight: bold; 50 | text-transform: capitalize; 51 | } 52 | 53 | .tip-patrimonio .subtitle { 54 | font-weight: normal; 55 | color: #adb5bd; 56 | } 57 | 58 | .tip-patrimonio:after { 59 | box-sizing: border-box; 60 | display: inline-block; 61 | font-size: 10px; 62 | width: 100%; 63 | line-height: 1; 64 | color: #20201e; 65 | content: "\25BC"; 66 | position: absolute; 67 | text-align: center; 68 | } 69 | 70 | .tip-patrimonio.n:after { 71 | margin: -1px 0 0 0; 72 | top: 100%; 73 | left: 0; 74 | } 75 | 76 | .auxiliary-vertical-line { 77 | stroke: #ced4da; 78 | stroke-width: 1px; 79 | } 80 | -------------------------------------------------------------------------------- /client/src/app/shared/services/jarbas.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | 4 | import { Observable } from 'rxjs'; 5 | import { ExpensesResponse, JarbasApplicantsResponse } from '../models/jarbas.models'; 6 | import { map, take } from 'rxjs/operators'; 7 | 8 | @Injectable({ 9 | providedIn: 'root' 10 | }) 11 | export class JarbasService { 12 | 13 | private url = 'https://jarbas.serenata.ai/api/'; 14 | 15 | constructor(private http: HttpClient) { } 16 | 17 | getJarbasApplicantId(congresspersonName: string): Observable { 18 | const endpoint = 'chamber_of_deputies/applicant/'; 19 | return this.http.get(this.url + endpoint + '?q=' + congresspersonName) 20 | .pipe(take(1)) 21 | .pipe(map(jarbasResponse => { 22 | const [firstApplicant] = jarbasResponse.results; 23 | if (firstApplicant) { 24 | return firstApplicant.applicant_id; 25 | } 26 | })); 27 | } 28 | 29 | getExpenses(jarbasApplicantId: number, pageNumber: number = 0): Observable { 30 | const maxPerPage = 25; 31 | const endpoint = 'chamber_of_deputies/reimbursement/'; 32 | const filters = [ 33 | 'applicant_id=' + jarbasApplicantId, 34 | 'limit=' + maxPerPage, 35 | 'offset=' + maxPerPage * pageNumber, 36 | 'format=json', 37 | ]; 38 | return this.http.get(this.url + endpoint + '?' + filters.join('&')) 39 | .pipe(take(1)) 40 | .pipe(map(jarbasResponse => new ExpensesResponse(jarbasResponse))); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /client/src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Perfil Parlamentar", 3 | "short_name": "Perfil Parlamentar", 4 | "description": "Saiba o que se passa no congresso.", 5 | "lang": "pt-BR", 6 | "start_url": "index.html", 7 | "display": "standalone", 8 | "orientation": "portrait-primary", 9 | "theme_color": "#ab64af", 10 | "background_color": "#ffffff", 11 | "icons": [ 12 | { 13 | "src": "assets/icons/512x512.png", 14 | "sizes": "512x512", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "assets/icons/192x192.png", 19 | "sizes": "192x192", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "assets/icons/180x180.png", 24 | "sizes": "180x180", 25 | "type": "image/png" 26 | }, 27 | { 28 | "src": "assets/icons/167x167.png", 29 | "sizes": "167x167", 30 | "type": "image/png" 31 | }, 32 | { 33 | "src": "assets/icons/152x152.png", 34 | "sizes": "152x152", 35 | "type": "image/png" 36 | }, 37 | { 38 | "src": "assets/icons/144x144.png", 39 | "sizes": "144x144", 40 | "type": "image/png" 41 | }, 42 | { 43 | "src": "assets/icons/128x128.png", 44 | "sizes": "128x128", 45 | "type": "image/png" 46 | }, 47 | { 48 | "src": "assets/icons/96x96.png", 49 | "sizes": "96x96", 50 | "type": "image/png" 51 | }, 52 | { 53 | "src": "assets/icons/48x48.png", 54 | "sizes": "48x48", 55 | "type": "image/png" 56 | }, 57 | { 58 | "src": "assets/icons/32x32.png", 59 | "sizes": "32x32", 60 | "type": "image/png" 61 | } 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/card-empresa/card-empresa.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

5 | {{company.companyName}} (CNPJ: {{getFormattedSupplierTaxpayerId()}}) 6 |

7 | 8 |
9 |
12 | Setor econômico: {{company.economicSector}} 13 |
14 | 15 | 16 | 17 | O setor econômico foi definido através de um mapeamento baseado no CNAE primário da empresa.
18 | Clique no link abaixo para mais informações de como cada setor é composto. 19 | 25 |
26 |
27 |
28 |
29 |

30 | Início das atividades da empresa: {{company.foundationDate}} 31 |

32 |

33 | Entrada do parlamentar na sociedade: {{company.politicianParticipationStartDate}} 34 |

35 |

36 | Localização: {{company.uf}} 37 |

38 |
39 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Gerenciando ícones 2 | 3 | Os ícones utilizados neste aplicativo são originais ou providos por pacotes gratuitos. Os arquivos SVGs originais precisam ser transformados em arquivos de fonte antes de serem usados. 4 | 5 | Para isso, utilizamos a ferramenta [Iconmoon](https://icomoon.io/app/). 6 | 7 | ## Carregando e modificando o pacote de ícones 8 | 9 | Na ferramenta [Iconmoon](https://icomoon.io/app/), siga os passos... 10 | 11 | ``` 12 | *Menu principal* > Manage projects > Import project 13 | ``` 14 | 15 | ...e escolha o arquivo `docs/icons.json`. Isso irá carregar todos os ícones para a ferramenta. Faça as alterações necessárias adicionando, editando ou removendo ícones. 16 | 17 | ## Atualizando pacote de ícones na aplicação 18 | 19 | Após as alterações, é preciso substituir o arquivo de fonte do projeto pelo novo gerado pelo [Iconmoon](https://icomoon.io/app/). Faça o download do arquivo ZIP contendo a fonte indo em `Generate font` e em seguida `Download` e faça as seguintes substituições no projeto: 20 | 21 | ``` 22 | No arquivo ZIP: No projeto: 23 | fonts/icomoon.eot client/src/assets/fonts/icomoon.eot 24 | fonts/icomoon.svg client/src/assets/fonts/icomoon.svg 25 | fonts/icomoon.ttf client/src/assets/fonts/icomoon.ttf 26 | fonts/icomoon.woff client/src/assets/fonts/icomoon.woff 27 | style.css client/src/assets/styles/icons.scss 28 | ``` 29 | 30 | No arquivo `icons.scss`, substituir o caminho relativo para os arquivos de fonte de acordo com o caminho do projeto. Ex.: 31 | 32 | ``` 33 | No arquivo ZIP: No projeto: 34 | src: url('fonts/icomoon.eot?k15p2l') src: url('assets/fonts/icomoon.eot?k15p2l') 35 | ``` -------------------------------------------------------------------------------- /client/src/app/aderencia/aderencia-parlamentares/aderencia-parlamentares.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnDestroy, Input } from '@angular/core'; 2 | import { Router, ActivatedRoute, Params } from '@angular/router'; 3 | 4 | import { Subject } from 'rxjs'; 5 | 6 | import { AderenciaService } from 'src/app/shared/services/aderencia.service'; 7 | 8 | import { ParlamentarAderencia } from 'src/app/shared/models/parlamentarAderencia.model'; 9 | 10 | @Component({ 11 | selector: 'app-aderencia-parlamentares', 12 | templateUrl: './aderencia-parlamentares.component.html', 13 | styleUrls: ['./aderencia-parlamentares.component.scss'] 14 | }) 15 | export class AderenciaParlamentaresComponent implements OnDestroy { 16 | readonly VIEW_SM = 'sm'; 17 | readonly VIEW_MD = 'md'; 18 | readonly VIEW_LG = 'lg'; 19 | 20 | @Input() parlamentares: ParlamentarAderencia[]; 21 | @Input() filter: any; 22 | @Input() view: string; 23 | 24 | private unsubscribe = new Subject(); 25 | 26 | p = 1; 27 | isLoading: boolean; 28 | 29 | constructor( 30 | private activatedRoute: ActivatedRoute, 31 | private router: Router) { } 32 | 33 | pageChange(p: number) { 34 | this.p = p; 35 | 36 | const queryParams: Params = Object.assign({}, this.activatedRoute.snapshot.queryParams); 37 | queryParams.page = p; 38 | this.router.navigate([], { queryParams }); 39 | } 40 | 41 | getParlamentarPosition( 42 | index: number, 43 | itensPerPage: number, 44 | currentPage: number 45 | ) { 46 | return (itensPerPage * (currentPage - 1)) + index + 1; 47 | } 48 | 49 | ngOnDestroy() { 50 | this.unsubscribe.next(); 51 | this.unsubscribe.complete(); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /server/models/postgres/partidos.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, type) => { 2 | partido = sequelize.define( 3 | "partido", 4 | { 5 | id_partido: { 6 | type: type.INTEGER, 7 | primaryKey: true 8 | }, 9 | sigla: type.STRING, 10 | tipo: type.STRING, 11 | situacao: type.STRING 12 | }, 13 | { 14 | timestamps: false 15 | } 16 | ); 17 | partido.associate = function (models) { 18 | partido.hasMany(models.parlamentar, { 19 | foreignKey: "id_partido", 20 | targetKey: "id_partido", 21 | as: "parlamentarPartido" 22 | }), 23 | partido.hasMany(models.liderancas, { 24 | foreignKey: "id_partido", 25 | targetKey: "id_partido", 26 | as: "liderancaPartido" 27 | }), 28 | partido.hasMany(models.aderencia, { 29 | foreignKey: "id_partido", 30 | sourceKey: "id_partido", 31 | as: "partido" 32 | }), 33 | partido.hasMany(models.orientacao, { 34 | foreignKey: "id_partido", 35 | targetKey: "id_partido", 36 | as: "orientacoes" 37 | }), 38 | partido.hasMany(models.investimentoPartidario, { 39 | foreignKey: "id_partido", 40 | targetKey: "id_partido_atual", 41 | as: "investimentoPartido" 42 | }), 43 | partido.hasMany(models.investimentoPartidarioParlamentar, { 44 | foreignKey: "id_partido", 45 | targetKey: "id_partido_atual", 46 | as: "investimentoPartidoAtual" 47 | }), 48 | partido.hasMany(models.investimentoPartidarioParlamentar, { 49 | foreignKey: "id_partido", 50 | targetKey: "id_partido_eleicao", 51 | as: "investimentoPartidoEleicao" 52 | }) 53 | }; 54 | return partido; 55 | }; 56 | -------------------------------------------------------------------------------- /client/src/app/questionario/perguntas-container/perguntas-container.component.scss: -------------------------------------------------------------------------------- 1 | .container-pergunta-controls { 2 | @media (min-width: 992px) { 3 | max-width: 500px; 4 | margin-left: auto; 5 | margin-right: auto; 6 | margin-top: 4rem; 7 | margin-bottom: 4rem; 8 | } 9 | } 10 | 11 | .pergunta-progress-bar { 12 | display: flex; 13 | flex-wrap: wrap; 14 | 15 | @media (min-width: 992px) { 16 | max-width: 330px; 17 | } 18 | } 19 | 20 | .pergunta-progress-item { 21 | flex: 1 1 auto; 22 | height: 1rem; 23 | margin-right: 2px; 24 | background-color: #ebe9e9; 25 | cursor: pointer; 26 | transition: background-color 0.5s; 27 | 28 | &.active { 29 | background-color: #20201e; 30 | 31 | &.positive { 32 | background-color: #43a467; 33 | } 34 | 35 | &.negative { 36 | background-color: #7f3c8b; 37 | } 38 | 39 | &.neutral { 40 | background-color: #adb5bd; 41 | } 42 | } 43 | 44 | &:last-child { 45 | margin-right: 0; 46 | } 47 | } 48 | 49 | .icon-hidden { 50 | opacity: 0; 51 | } 52 | 53 | .icon-show { 54 | opacity: 1; 55 | } 56 | 57 | .btn-pergunta { 58 | @media (max-width: 400px) { 59 | font-size: 0.65rem; 60 | } 61 | } 62 | 63 | .respostas-btn-group { 64 | @media (min-width: 992px) { 65 | max-width: 430px; 66 | margin-left: auto; 67 | } 68 | } 69 | 70 | .btn-outline-no-border { 71 | box-shadow: none; 72 | 73 | &:hover, 74 | &:active, 75 | &:focus { 76 | background-color: #ffffff; 77 | color: #343a40; 78 | } 79 | } 80 | 81 | .btn-outline-no-border-dark { 82 | border: solid 2px; 83 | color: #343a40; 84 | } 85 | 86 | .btn-outline-no-border-light { 87 | color: #ebe9e9; 88 | } 89 | -------------------------------------------------------------------------------- /client/src/app/parlamentar/patrimonio/patrimonio.component.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | Evolução de Patrimônio 4 | 5 |

6 | 7 | 8 |
9 | Falha ao buscar informações. 10 |
11 |
12 | Não foram encontrados dados de patrimônio declarado pelo parlamentar. 13 |
14 |
15 | 19 |
20 |
21 |
22 | 23 | 24 | 35 | 47 | 48 | --------------------------------------------------------------------------------