From ec6089aef732db626f82e998a52b5035ebebbad4 Mon Sep 17 00:00:00 2001 From: Lucas Vaz Date: Thu, 9 Oct 2025 21:21:16 -0300 Subject: [PATCH 1/6] =?UTF-8?q?feat(auth):=20implementar=20fluxo=20complet?= =?UTF-8?q?o=20de=20recupera=C3=A7=C3=A3o=20e=20redefini=C3=A7=C3=A3o=20de?= =?UTF-8?q?=20senha?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 8 + package.json | 1 + script/database-sync/database-sync.sh | 72 +- script/database-sync/entrypoint.sh | 34 +- src/controllers/pendencias-controller.js | 4422 ++++++++--------- src/controllers/taxonomias-controller.js | 2986 +++++------ src/controllers/tombos-controller.js | 3314 ++++++------ src/controllers/usuarios-controller.js | 94 +- .../20251001194607_fix-nome-cientifico.ts | 86 +- ...51008193832_add-reset-token-to-usuarios.ts | 15 + src/helpers/tokens.js | 10 + src/herbarium/specieslink/tombos.js | 556 +-- src/models/Usuario.js | 8 + src/routes/usuarios.js | 1040 ++-- src/validators/especie-atualiza.js | 50 +- src/validators/usuario-redefine-senha.js | 10 + src/validators/usuario-solicita-reset.js | 6 + src/views/ficha-tombo.ejs | 622 +-- yarn.lock | 5 + 19 files changed, 6784 insertions(+), 6555 deletions(-) create mode 100644 src/database/migration/20251008193832_add-reset-token-to-usuarios.ts create mode 100644 src/validators/usuario-redefine-senha.js create mode 100644 src/validators/usuario-solicita-reset.js diff --git a/.env.example b/.env.example index d7ea857..840276f 100644 --- a/.env.example +++ b/.env.example @@ -14,3 +14,11 @@ MYSQL_MIGRATION_USERNAME=root MYSQL_MIGRATION_PASSWORD=masterkey RECAPTCHA_SECRET_KEY=6LcYYYYYYYYYYYYYY + +SMTP_HOST=smtp.gmail.com +SMTP_PORT=587 +SMTP_USER="seu-email@gmail.com" +SMTP_PASS="sua-senha-de-app-de-16-digitos" +SMTP_FROM="Sistema HCF " + +URL_PAINEL=http://localhost:5173/ diff --git a/package.json b/package.json index e7b6f2b..ed50fd7 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "multer": "1.4.5-lts.2", "mysql2": "3.14.0", "node-wkhtmltopdf": "^2.0.0", + "nodemailer": "^7.0.9", "puppeteer": "24.6.0", "q": "^1.5.1", "react": "19.1.0", diff --git a/script/database-sync/database-sync.sh b/script/database-sync/database-sync.sh index 3b271f2..0928d98 100755 --- a/script/database-sync/database-sync.sh +++ b/script/database-sync/database-sync.sh @@ -1,36 +1,36 @@ -#!/bin/bash - -set -e -set -o pipefail - -EXCLUDE_PARAMS="" -if [ -n "$SYNC_EXCLUDE_TABLES" ]; then - IFS=',' read -ra TABLES <<< "$SYNC_EXCLUDE_TABLES" - for table in "${TABLES[@]}"; do - table=$(echo "$table" | xargs) # trim whitespace - if [ -n "$table" ]; then - EXCLUDE_PARAMS="$EXCLUDE_PARAMS --ignore-table=${SYNC_SOURCE_DATABASE}.${table}" - fi - done - echo "Excluding tables: $SYNC_EXCLUDE_TABLES" -fi - -echo "Starting synchronization process..." - -mysqldump \ - -h "$SYNC_SOURCE_HOST" \ - -P "$SYNC_SOURCE_PORT" \ - -u "$SYNC_SOURCE_USER" \ - ${SYNC_SOURCE_PASSWORD:+-p"$SYNC_SOURCE_PASSWORD"} \ - $EXCLUDE_PARAMS \ - --single-transaction \ - "$SYNC_SOURCE_DATABASE" | \ -mysql \ - -h "$SYNC_DEST_HOST" \ - -P "$SYNC_DEST_PORT" \ - -u "$SYNC_DEST_USER" \ - ${SYNC_DEST_PASSWORD:+-p"$SYNC_DEST_PASSWORD"} \ - "$SYNC_DEST_DATABASE" - - -echo "Synchronization completed successfully: ${SYNC_SOURCE_DATABASE} -> ${SYNC_DEST_DATABASE}" +#!/bin/bash + +set -e +set -o pipefail + +EXCLUDE_PARAMS="" +if [ -n "$SYNC_EXCLUDE_TABLES" ]; then + IFS=',' read -ra TABLES <<< "$SYNC_EXCLUDE_TABLES" + for table in "${TABLES[@]}"; do + table=$(echo "$table" | xargs) # trim whitespace + if [ -n "$table" ]; then + EXCLUDE_PARAMS="$EXCLUDE_PARAMS --ignore-table=${SYNC_SOURCE_DATABASE}.${table}" + fi + done + echo "Excluding tables: $SYNC_EXCLUDE_TABLES" +fi + +echo "Starting synchronization process..." + +mysqldump \ + -h "$SYNC_SOURCE_HOST" \ + -P "$SYNC_SOURCE_PORT" \ + -u "$SYNC_SOURCE_USER" \ + ${SYNC_SOURCE_PASSWORD:+-p"$SYNC_SOURCE_PASSWORD"} \ + $EXCLUDE_PARAMS \ + --single-transaction \ + "$SYNC_SOURCE_DATABASE" | \ +mysql \ + -h "$SYNC_DEST_HOST" \ + -P "$SYNC_DEST_PORT" \ + -u "$SYNC_DEST_USER" \ + ${SYNC_DEST_PASSWORD:+-p"$SYNC_DEST_PASSWORD"} \ + "$SYNC_DEST_DATABASE" + + +echo "Synchronization completed successfully: ${SYNC_SOURCE_DATABASE} -> ${SYNC_DEST_DATABASE}" diff --git a/script/database-sync/entrypoint.sh b/script/database-sync/entrypoint.sh index 69adea0..2c357eb 100755 --- a/script/database-sync/entrypoint.sh +++ b/script/database-sync/entrypoint.sh @@ -1,17 +1,17 @@ -#!/bin/sh - -echo "Configuring cron job with schedule: $CRON_SCHEDULE (timezone: $TZ)" - -# ensure environment variables are passed to the cron job -printenv | grep -E "^SYNC_" >> /etc/environment - -echo "$CRON_SCHEDULE /database-sync.sh 1> /proc/1/fd/1 2> /proc/1/fd/2" | crontab - - -if ! crontab -l >/dev/null 2>&1; then - echo "Failed to configure cron job" - exit 1 -fi - -crontab -l - -exec $@ +#!/bin/sh + +echo "Configuring cron job with schedule: $CRON_SCHEDULE (timezone: $TZ)" + +# ensure environment variables are passed to the cron job +printenv | grep -E "^SYNC_" >> /etc/environment + +echo "$CRON_SCHEDULE /database-sync.sh 1> /proc/1/fd/1 2> /proc/1/fd/2" | crontab - + +if ! crontab -l >/dev/null 2>&1; then + echo "Failed to configure cron job" + exit 1 +fi + +crontab -l + +exec $@ diff --git a/src/controllers/pendencias-controller.js b/src/controllers/pendencias-controller.js index 8f9cc18..5f9238d 100644 --- a/src/controllers/pendencias-controller.js +++ b/src/controllers/pendencias-controller.js @@ -1,2211 +1,2211 @@ -import BadRequestExeption from '../errors/bad-request-exception'; -import { converteParaDecimal } from '../helpers/coordenadas'; -import models from '../models'; -import codigos from '../resources/codigos-http'; - -const { - Alteracao, - Usuario, - Herbario, - Solo, - Relevo, - Vegetacao, - Cidade, - FaseSucessional, - LocalColeta, - sequelize, - Sequelize: { Op }, - Tombo, - Especie, - Variedade, - Coletor, - Tipo, - Familia, - Subfamilia, - Genero, - Subespecie, - ColecaoAnexa, - TomboIdentificador, - Identificador, - ColetorComplementar, -} = models; - -export const listagem = (request, response, next) => { - const { limite, pagina, offset } = request.paginacao; - const { status, nome_usuario: nomeUsuario } = request.query; - const retorno = { - metadados: { - total: 0, - pagina, - limite, - }, - resultado: {}, - }; - let where = { - ativo: 1, - }; - let whereUsuario = {}; - if (status) { - where = { - ...where, - status, - }; - } else { - where = { - ...where, - status: { [Op.ne]: 'APROVADO' }, - }; - } - if (nomeUsuario) { - whereUsuario = { - nome: { [Op.like]: `%${nomeUsuario}%` }, - }; - } - const callback = transaction => Promise.resolve() - .then(() => Alteracao.findAndCountAll({ - include: [ - { - model: Usuario, - whereUsuario, - }, - ], - limit: limite, - offset, - where, - order: [['id', 'DESC']], - transaction, - })) - .then(alteracoes => { - retorno.metadados.total = alteracoes.count; - // const alteracoesValidas = alteracoes.rows.filter(item => { - // if (item.usuario.tipo_usuario_id === 1) { - // return false; - // } - // if (item.identificacao) { - // if (item.usuario.tipo_usuario_id === 3) { - // return true; - // } - // return false; - // } - // return true; - // }); - retorno.resultado = alteracoes.rows.map(item => ({ - id: item.id, - nome_usuario: item.usuario.nome, - numero_tombo: item.tombo_hcf, - json: JSON.parse(item.tombo_json), - data_criacao: item.created_at, - status: item.status, - observacao: item.observacao || '', - })); - return retorno; - }); - sequelize.transaction(callback) - .then(() => { - response.status(codigos.LISTAGEM).json(retorno); - }) - .catch(next); -}; - -export const desativar = (request, response, next) => { - const id = request.params.pendencia_id; - - const callback = transaction => Promise.resolve() - .then(() => Alteracao.findOne({ - where: { - ativo: true, - id, - }, - transaction, - })) - .then(alteracao => { - if (!alteracao) { - throw new BadRequestExeption(800); - } - return Alteracao.update({ - ativo: false, - }, { - where: { - id, - }, - transaction, - }); - }); - sequelize.transaction(callback) - .then(() => { - response.status(codigos.DESATIVAR).send(); - }) - .catch(next); -}; - -const comparaDoisTombos = (tombo, tomboAlterado) => { - const parametros = []; - if (tombo.data_coleta_dia !== tomboAlterado.data_coleta_dia) { - parametros.push({ - key: '1', - campo: 'Dia da coleta', - antigo: tombo.data_coleta_dia, - novo: tomboAlterado.data_coleta_dia, - }); - } - if (tombo.data_coleta_mes !== tomboAlterado.data_coleta_mes) { - parametros.push({ - key: '2', - campo: 'Mes da coleta', - antigo: tombo.data_coleta_mes, - novo: tomboAlterado.data_coleta_mes, - }); - } - if (tombo.data_coleta_ano !== tomboAlterado.data_coleta_ano) { - parametros.push({ - key: '3', - campo: 'Ano da coleta', - antigo: tombo.data_coleta_ano, - novo: tomboAlterado.data_coleta_ano, - }); - } - if (tombo.observacao !== tomboAlterado.observacao) { - parametros.push({ - key: '4', - campo: 'Observação', - antigo: tombo.observacao, - novo: tomboAlterado.observacao, - }); - } - if (tombo.nomes_populares !== tomboAlterado.nomes_populares) { - parametros.push({ - key: '5', - campo: 'Nomes populares', - antigo: tombo.nomes_populares, - novo: tomboAlterado.nomes_populares, - }); - } - if (tombo.numero_coleta !== tomboAlterado.numero_coleta) { - parametros.push({ - key: '6', - campo: 'Numero de coleta', - antigo: tombo.numero_coleta, - novo: tomboAlterado.numero_coleta, - }); - } - if (tombo.latitude !== tomboAlterado.latitude) { - parametros.push({ - key: '7', - campo: 'Latitude', - antigo: tombo.latitude, - novo: tomboAlterado.latitude, - }); - } - if (tombo.longitude !== tomboAlterado.longitude) { - parametros.push({ - key: '8', - campo: 'Longitude', - antigo: tombo.longitude, - novo: tomboAlterado.longitude, - }); - } - if (tombo.altitude !== tomboAlterado.altitude) { - parametros.push({ - key: '9', - campo: 'Altitude', - antigo: tombo.altitude, - novo: tomboAlterado.altitude, - }); - } - if (tombo.herbario && tomboAlterado.herbario - && (tombo.herbario.nome !== tomboAlterado.herbario.nome)) { - parametros.push({ - key: '10', - campo: 'Herbário', - antigo: tombo.herbario.nome, - novo: tomboAlterado.herbario.nome, - }); - } - if (tombo.locais_coletum && tomboAlterado.locais_coletum - && tombo.locais_coletum.descricao !== tomboAlterado.locais_coletum.descricao) { - parametros.push({ - key: '11', - campo: 'Descrição do local de coleta', - antigo: tombo.locais_coletum.descricao, - novo: tomboAlterado.locais_coletum.descricao, - }); - } - if (tombo.locais_coletum && tombo.locais_coletum.solo - && tomboAlterado.locais_coletum && tomboAlterado.locais_coletum.solo - && tombo.locais_coletum.solo.nome !== tomboAlterado.locais_coletum.solo.nome) { - parametros.push({ - key: '12', - campo: 'Solo', - antigo: tombo.locais_coletum.solo.nome, - novo: tomboAlterado.locais_coletum.solo.nome, - }); - } - if (tombo.locais_coletum && tombo.locais_coletum.relevo - && tombo.locais_coletum && tombo.locais_coletum.relevo - && tombo.locais_coletum.relevo.nome !== tomboAlterado.locais_coletum.relevo.nome) { - parametros.push({ - key: '13', - campo: 'Relevo', - antigo: tombo.locais_coletum.relevo.nome, - novo: tomboAlterado.locais_coletum.relevo.nome, - }); - } - if (tombo.locais_coletum && tombo.locais_coletum.vegetaco - && tomboAlterado.locais_coletum && tomboAlterado.locais_coletum.vegetaco - && tombo.locais_coletum.vegetaco.nome !== tomboAlterado.locais_coletum.vegetaco.nome) { - parametros.push({ - key: '14', - campo: 'Vegetação', - antigo: tombo.locais_coletum.vegetaco.nome, - novo: tomboAlterado.locais_coletum.vegetaco.nome, - }); - } - if (tombo.locais_coletum && tombo.locais_coletum.cidade - && tomboAlterado.locais_coletum && tomboAlterado.locais_coletum.cidade - && tombo.locais_coletum.cidade.nome !== tomboAlterado.locais_coletum.cidade.nome) { - parametros.push({ - key: '15', - campo: 'Cidade', - antigo: tombo.locais_coletum.cidade.nome, - novo: tomboAlterado.locais_coletum.cidade.nome, - }); - } - if (tombo.locais_coletum && tomboAlterado.locais_coletum - && tombo.locais_coletum.fase_sucessional !== tomboAlterado.locais_coletum.fase_sucessional) { - parametros.push({ - key: '16', - campo: 'Fase Sucessional', - antigo: tombo.locais_coletum.fase_sucessional, - novo: tomboAlterado.locais_coletum.fase_sucessional, - }); - } - if (tombo.situacao !== tomboAlterado.situacao) { - parametros.push({ - key: '17', - campo: 'Situação', - antigo: tombo.situacao, - novo: tomboAlterado.situacao, - }); - } - if (tombo.nome_cientifico !== tomboAlterado.nome_cientifico) { - parametros.push({ - key: '18', - campo: 'Nome Científico', - antigo: tombo.nome_cientifico, - novo: tomboAlterado.nome_cientifico, - }); - } - if (tombo.cor !== tomboAlterado.cor) { - parametros.push({ - key: '19', - campo: 'Cor - Localização', - antigo: tombo.cor, - novo: tomboAlterado.cor, - }); - } - if (tombo.variedade && tomboAlterado.variedade - && tombo.variedade.nome !== tomboAlterado.variedade.nome) { - parametros.push({ - key: '20', - campo: 'Variedade', - antigo: tombo.variedade.nome, - novo: tomboAlterado.variedade.nome, - }); - } - if (tombo.tipo && tomboAlterado.tipo - && tombo.tipo.nome !== tomboAlterado.tipo.nome) { - parametros.push({ - key: '21', - campo: 'Tipo', - antigo: tombo.tipo.nome, - novo: tomboAlterado.tipo.nome, - }); - } - if (tombo.especy && tomboAlterado.especy - && tombo.especy.nome !== tomboAlterado.especy.nome) { - parametros.push({ - key: '22', - campo: 'Espécie', - antigo: tombo.especy.nome, - novo: tomboAlterado.especy.nome, - }); - } - if (tombo.genero && tomboAlterado.genero - && tombo.genero.nome !== tomboAlterado.genero.nome) { - parametros.push({ - key: '23', - campo: 'Género', - antigo: tombo.genero.nome, - novo: tomboAlterado.genero.nome, - }); - } - if (tombo.familia && tomboAlterado.familia - && tombo.familia.nome !== tomboAlterado.familia.nome) { - parametros.push({ - key: '24', - campo: 'Família', - antigo: tombo.familia.nome, - novo: tomboAlterado.familia.nome, - }); - } - if (tombo.sub_familia && tomboAlterado.sub_familia - && tombo.sub_familia.nome !== tomboAlterado.sub_familia.nome) { - parametros.push({ - key: '25', - campo: 'Subfamília', - antigo: tombo.sub_familia.nome, - novo: tomboAlterado.sub_familia.nome, - }); - } - if (tombo.sub_especy && tomboAlterado.sub_especy - && tombo.sub_especy.nome !== tomboAlterado.sub_especy.nome) { - parametros.push({ - key: '26', - campo: 'Subespécie', - antigo: tombo.sub_especy.nome, - novo: tomboAlterado.sub_especy.nome, - }); - } - if (tombo.colecoes_anexa && tomboAlterado.colecoes_anexa - && tombo.colecoes_anexa.observacoes !== tomboAlterado.colecoes_anexa.observacoes) { - parametros.push({ - key: '27', - campo: 'Observações - Coleção Anexa', - antigo: tombo.colecoes_anexa.observacoes, - novo: tomboAlterado.colecoes_anexa.observacoes, - }); - } - if (tombo.colecoes_anexa && tomboAlterado.colecoes_anexa - && tombo.colecoes_anexa.tipo !== tomboAlterado.colecoes_anexa.tipo) { - parametros.push({ - key: '28', - campo: 'Tipo - Coleção Anexa', - antigo: tombo.colecoes_anexa.tipo, - novo: tomboAlterado.colecoes_anexa.tipo, - }); - } - - return parametros; -}; - -export const formatarTomboNovo = tombo => { - const parametros = []; - parametros.push({ - key: '1', - campo: 'Dia da coleta', - antigo: '', - novo: tombo.data_coleta_dia, - }); - parametros.push({ - key: '2', - campo: 'Mes da coleta', - antigo: '', - novo: tombo.data_coleta_mes, - }); - parametros.push({ - key: '3', - campo: 'Ano da coleta', - antigo: '', - novo: tombo.data_coleta_ano, - }); - parametros.push({ - key: '4', - campo: 'Observação', - antigo: '', - novo: tombo.observacao, - }); - parametros.push({ - key: '5', - campo: 'Nomes populares', - antigo: '', - novo: tombo.nomes_populares, - }); - parametros.push({ - key: '6', - campo: 'Numero de coleta', - antigo: '', - novo: tombo.numero_coleta, - }); - parametros.push({ - key: '7', - campo: 'Latitude', - antigo: '', - novo: tombo.latitude, - }); - parametros.push({ - key: '8', - campo: 'Longitude', - antigo: '', - novo: tombo.longitude, - }); - parametros.push({ - key: '9', - campo: 'Altitude', - antigo: '', - novo: tombo.altitude, - }); - if (tombo.herbario) { - parametros.push({ - key: '10', - campo: 'Herbário', - antigo: '', - novo: tombo.herbario.nome, - }); - } - if (tombo.locais_coletum) { - parametros.push({ - key: '11', - campo: 'Descrição do local de coleta', - antigo: '', - novo: tombo.locais_coletum.descricao, - }); - if (tombo.locais_coletum.solo) { - parametros.push({ - key: '12', - campo: 'Solo', - antigo: '', - novo: tombo.locais_coletum.solo.nome, - }); - } - if (tombo.locais_coletum.relevo) { - parametros.push({ - key: '13', - campo: 'Relevo', - antigo: '', - novo: tombo.locais_coletum.relevo.nome, - }); - } - if (tombo.locais_coletum.vegetaco) { - parametros.push({ - key: '14', - campo: 'Vegetação', - antigo: '', - novo: tombo.locais_coletum.vegetaco.nome, - }); - } - if (tombo.locais_coletum.cidade) { - parametros.push({ - key: '15', - campo: 'Cidade', - antigo: '', - novo: tombo.locais_coletum.cidade.nome, - }); - } - if (tombo.locais_coletum.fase_sucessional) { - parametros.push({ - key: '16', - campo: 'Fase Sucessional', - antigo: '', - novo: tombo.locais_coletum.fase_sucessional.nome, - }); - } - } - parametros.push({ - key: '17', - campo: 'Situação', - antigo: '', - novo: tombo.situacao, - }); - parametros.push({ - key: '18', - campo: 'Nome Científico', - antigo: '', - novo: tombo.nome_cientifico, - }); - parametros.push({ - key: '19', - campo: 'Cor', - antigo: '', - novo: tombo.cor, - }); - if (tombo.variedade) { - parametros.push({ - key: '20', - campo: 'Variedade', - antigo: '', - novo: tombo.variedade.nome, - }); - } - if (tombo.tipo) { - parametros.push({ - key: '21', - campo: 'Tipo', - antigo: '', - novo: tombo.tipo.nome, - }); - } - if (tombo.especy) { - parametros.push({ - key: '22', - campo: 'Espécie', - antigo: '', - novo: tombo.especy.nome, - }); - } - if (tombo.genero) { - parametros.push({ - key: '23', - campo: 'Genero', - antigo: '', - novo: tombo.genero.nome, - }); - } - if (tombo.familia) { - parametros.push({ - key: '24', - campo: 'Família', - antigo: '', - novo: tombo.familia.nome, - }); - } - if (tombo.sub_familia) { - parametros.push({ - key: '25', - campo: 'Subfamília', - antigo: '', - novo: tombo.sub_familia.nome, - }); - } - if (tombo.sub_especy) { - parametros.push({ - key: '26', - campo: 'Subespécie', - antigo: '', - novo: tombo.sub_especy.nome, - }); - } - if (tombo.colecoes_anexa) { - parametros.push({ - key: '27', - campo: 'Observações - Coleção Anexa', - antigo: '', - novo: tombo.colecoes_anexa.observacoes, - }); - } - if (tombo.colecoes_anexa) { - parametros.push({ - key: '28', - campo: 'Tipo - Coleção Anexa', - antigo: '', - novo: tombo.colecoes_anexa.tipo, - }); - } - return parametros; -}; - -export const visualizarComCadastro = (alteracao, transaction) => { - let parametros = {}; - - return new Promise((resolve, reject) => { - - parametros = { - ...parametros, - numero_tombo: alteracao.tombo_hcf, - numero_tombo_alteracao: JSON.parse(alteracao.tombo_json).hcf, - }; - Tombo.findAll({ - where: { - hcf: { - [Op.in]: [alteracao.tombo_hcf, parametros.numero_tombo_alteracao], - }, - ativo: true, - }, - include: [ - { - model: Herbario, - }, - { - model: Variedade, - }, - { - model: Tipo, - }, - { - model: Especie, - }, - { - model: Familia, - }, - { - model: Subfamilia, - }, - { - model: Genero, - }, - { - model: Subespecie, - }, - { - model: ColecaoAnexa, - }, - { - model: LocalColeta, - include: [ - { - model: Solo, - }, - { - model: Relevo, - }, - { - model: Vegetacao, - }, - { - model: Cidade, - }, - { - model: FaseSucessional, - }, - ], - }, - ], - transaction, - }) - .then(tombos => { - parametros = { - ...parametros, - retorno: [], - }; - if (tombos.length === 2) { - if (tombos[0].hcf === parametros.numero_tombo) { - parametros = { - ...parametros, - tombo: tombos[0], - tombo_alterado: tombos[1], - }; - } else { - parametros = { - ...parametros, - tombo: tombos[1], - tombo_alterado: tombos[0], - }; - } - parametros = comparaDoisTombos(parametros.tombo, parametros.tombo_alterado); - } else { - parametros = formatarTomboNovo(tombos[0]); - } - resolve(parametros); - }) - .catch(reject); - }); -}; - -const insereNoParametro = (key, campo, antigo, novo) => ({ - key, campo, antigo, novo, -}); - -const comparaDoisTombosOperador = (tombo, tomboAlterado) => { - const parametros = []; - // / colecoes anexas - if (tomboAlterado.colecoes_anexas) { - if (tombo.colecoes_anexa) { - if (tombo.colecoes_anexa.tipo !== tomboAlterado.colecoes_anexas.tipo) { - parametros.push(insereNoParametro('1', 'Coleções anexas tipo', tombo.colecoes_anexa.tipo, tomboAlterado.colecoes_anexas.tipo)); - } - if (tombo.colecoes_anexa.observacoes !== tomboAlterado.colecoes_anexas.observacoes) { - // eslint-disable-next-line - parametros.push( - insereNoParametro( - '2', - 'Coleções anexas observacoes', - tombo.colecoes_anexa.observacoes, - tomboAlterado.colecoes_anexas.observacoes - ) - ); - } - } else { - if (tomboAlterado.colecoes_anexas.tipo) { - parametros.push(insereNoParametro('1', 'Coleções anexas tipo', '', tomboAlterado.colecoes_anexas.tipo)); - } - if (tomboAlterado.colecoes_anexas.observacoes) { - parametros.push(insereNoParametro('2', 'Coleções anexas observacoes', '', tomboAlterado.colecoes_anexas.observacoes)); - } - } - } - // / coletores - let coletorPrincipalOrig = {}; - let coletoresOrig = ''; - let coletoresAlt = ''; - let novo = ''; - let antigo = ''; - - if (tomboAlterado.coletores) { - const colAlt = tomboAlterado.coletores; - for (let i = 0; i < colAlt.length; i++) { // eslint-disable-line - coletoresAlt += ` ${colAlt[i].nome} `; - } - novo = coletoresAlt; - } - if (tombo.coletores) { - const colOrig = tombo.coletores; - for (let i = 0; i < colOrig.length; i++) { // eslint-disable-line - if (colOrig[i].tombos_coletores.principal) { - coletorPrincipalOrig = { - id: colOrig[i].id, - nome: colOrig[i].nome, - }; - } else { - coletoresOrig += ` ${colOrig[i].nome} `; - } - } - antigo = coletoresOrig; - } - parametros.push(insereNoParametro('3', 'Coletores', antigo, novo)); - if (coletorPrincipalOrig.id) { - if (tomboAlterado.coletor_principal.id) { - if (coletorPrincipalOrig.id !== tomboAlterado.coletor_principal.id) { - parametros.push(insereNoParametro('4', 'Coletor principal', coletorPrincipalOrig.nome, tomboAlterado.coletor_principal.nome)); - } - } - } else if (tomboAlterado.coletor_principal.id) { - parametros.push(insereNoParametro('4', 'Coletor principal', '', tomboAlterado.coletor_principal.nome)); - } - // /////local de coleta - if (tomboAlterado.localidade) { - if (tomboAlterado.localidade.altitude) { - if (tombo.altitude) { - if (tombo.altitude !== tomboAlterado.localidade.altitude) { - parametros.push(insereNoParametro('5', 'Altitude', tombo.altitude, tomboAlterado.localidade.altitude)); - } - } else { - parametros.push(insereNoParametro('5', 'Altitude', '', tomboAlterado.localidade.altitude)); - } - } - if (tomboAlterado.localidade.cidade) { - if (tomboAlterado.localidade.cidade.id) { - if (tombo.locais_coletum && tombo.locais_coletum.cidade) { - if (tombo.locais_coletum.cidade.id !== tomboAlterado.localidade.cidade.id) { - parametros.push(insereNoParametro('6', 'Cidade', tombo.locais_coletum.cidade.nome, tomboAlterado.localidade.cidade.nome)); - } - } else { - parametros.push(insereNoParametro('6', 'Cidade', '', tomboAlterado.localidade.cidade.nome)); - } - } - } - if (tomboAlterado.localidade.latitude) { - if (tombo.latitude) { - if (converteParaDecimal(tomboAlterado.localidade.latitude) !== tombo.latitude) { - parametros.push(insereNoParametro('7', 'Latitude', tombo.latitude, tomboAlterado.localidade.latitude)); - } - } else { - parametros.push(insereNoParametro('7', 'Latitude', '', tomboAlterado.localidade.latitude)); - } - } - if (tomboAlterado.localidade.longitude) { - if (tombo.longitude) { - if (converteParaDecimal(tomboAlterado.localidade.longitude) !== tombo.longitude) { - parametros.push(insereNoParametro('8', 'Longitude', tombo.longitude, tomboAlterado.localidade.longitude)); - } - } else { - parametros.push(insereNoParametro('8', 'Longitude', '', tomboAlterado.localidade.longitude)); - } - } - } - - if (tomboAlterado.observacoes) { - if (tombo.observacoes) { - parametros.push(insereNoParametro('9', 'Observações', tombo.observacoes, tomboAlterado.observacoes)); - } else { - parametros.push(insereNoParametro('9', 'Observações', '', tomboAlterado.observacoes)); - } - } - - if (tomboAlterado.paisagem) { - const { - descricao, fase_sucessional: faseSucessional, relevo, solo, vegetacao, - } = tomboAlterado.paisagem; - if (descricao) { - if (tombo.locais_coletum && tombo.locais_coletum.descricao) { - if (descricao !== tombo.locais_coletum.descricao) { - parametros.push(insereNoParametro('10', 'Descrição do local de coleta', tombo.locais_coletum.descricao, descricao)); - } - } else { - parametros.push(insereNoParametro('10', 'Descrição do local de coleta', '', descricao)); - } - } - if (faseSucessional) { - if (tombo.locais_coletum && tombo.locais_coletum.fase_sucessional) { - if (tombo.locais_coletum.fase_sucessional.nome !== faseSucessional.nome) { - parametros.push(insereNoParametro('11', 'Fase sucessional', tombo.locais_coletum.nome, faseSucessional.nome)); - } - } else { - parametros.push(insereNoParametro('11', 'Fase sucessional', '', faseSucessional.nome)); - } - } - if (relevo) { - if (tombo.locais_coletum && tombo.locais_coletum.relevo) { - if (tombo.locais_coletum.relevo.nome !== relevo.nome) { - parametros.push(insereNoParametro('12', 'Relevo', tombo.locais_coletum.relevo.nome, relevo.nome)); - } - } else { - parametros.push(insereNoParametro('12', 'Relevo', '', relevo.nome)); - } - } - if (solo) { - if (tombo.locais_coletum && tombo.locais_coletum.solo) { - if (tombo.locais_coletum.solo.nome !== solo.nome) { - parametros.push(insereNoParametro('13', 'Solo', tombo.locais_coletum.solo.nome, solo.nome)); - } - } else { - parametros.push(insereNoParametro('13', 'Solo', '', solo.nome)); - } - } - if (vegetacao) { - if (tombo.locais_coletum && tombo.locais_coletum.vegetaco) { - if (tombo.locais_coletum.vegetaco.nome !== solo.nome) { - parametros.push(insereNoParametro('14', 'Vegetação', tombo.locais_coletum.vegetaco.nome, vegetacao.nome)); - } - } else { - parametros.push(insereNoParametro('14', 'Vegetação', '', vegetacao.nome)); - } - } - } - - if (tomboAlterado.principal) { - const { - cor, data_coleta: dataColeta, entidade, - nome_popular: nomePopular, numero_coleta: numColeta, tipo, - } = tomboAlterado.principal; - - if (cor) { - if (tombo.cor !== cor) { - parametros.push(insereNoParametro('15', 'Cor', '', tombo.cor)); - } - } - if (dataColeta) { - if (dataColeta.dia) { - if (tombo.data_coleta_dia) { - if (dataColeta.dia !== tombo.data_coleta_dia) { - parametros.push(insereNoParametro('16', 'Data coleta dia', tombo.data_coleta_dia, dataColeta.dia)); - } - } else { - parametros.push(insereNoParametro('16', 'Data coleta dia', '', dataColeta.dia)); - } - } - if (dataColeta.mes) { - if (tombo.data_coleta_mes) { - if (dataColeta.mes !== tombo.data_coleta_mes) { - parametros.push(insereNoParametro('17', 'Data coleta mes', tombo.data_coleta_mes, dataColeta.mes)); - } - } else { - parametros.push(insereNoParametro('17', 'Data coleta mes', '', dataColeta.mes)); - } - } - if (dataColeta.ano) { - if (tombo.data_coleta_ano) { - if (dataColeta.ano !== tombo.data_coleta_ano) { - parametros.push(insereNoParametro('18', 'Data coleta ano', tombo.data_coleta_ano, dataColeta.ano)); - } - } else { - parametros.push(insereNoParametro('18', 'Data coleta ano', '', dataColeta.ano)); - } - } - } - - if (entidade) { - if (tombo.herbario) { - if (entidade.id !== tombo.herbario.id) { - parametros.push(insereNoParametro('19', 'Herbário', tombo.herbario.nome, entidade.nome)); - } - } else { - parametros.push(insereNoParametro('19', 'Herbário', '', entidade.nome)); - } - } - - if (nomePopular) { - if (tombo.nome_populares) { - if (nomePopular !== tombo.nome_populares) { - parametros.push(insereNoParametro('20', 'Nomes populares', tombo.nome_populares, nomePopular)); - } - } else { - parametros.push(insereNoParametro('20', 'Nomes populares', '', nomePopular)); - } - } - - if (numColeta) { - if (tombo.numero_coleta) { - if (numColeta !== tombo.numero_coleta) { - parametros.push(insereNoParametro('21', 'Numero de coleta', numColeta, tombo.numero_coleta)); - } - } else { - parametros.push(insereNoParametro('21', 'Numero de coleta', '', tombo.numero_coleta)); - } - } - - if (tipo) { - if (tombo.tipo) { - if (tipo.id !== tombo.tipo.id) { - parametros.push(insereNoParametro('22', 'Tipo', tombo.tipo.nome, tipo.nome)); - } - } else { - parametros.push(insereNoParametro('22', 'Tipo', '', tipo.nome)); - } - } - } - - if (tomboAlterado.taxonomia) { - const { - especie, familia, genero, sub_especie: subEspecie, sub_familia: subFamilia, variedade, - } = tomboAlterado.taxonomia; - - if (especie) { - if (tombo.especy) { - if (especie.nome !== tombo.especy.nome) { - parametros.push(insereNoParametro('23', 'Especie', especie, tombo.especy.nome)); - } - } else { - parametros.push(insereNoParametro('23', 'Especie', '', especie.nome)); - } - } - - if (familia) { - if (tombo.familia) { - if (familia.nome !== tombo.familia.nome) { - parametros.push(insereNoParametro('24', 'Familia', familia, tombo.familia.nome)); - } - } else { - parametros.push(insereNoParametro('24', 'Familia', '', familia.nome)); - } - } - - if (genero) { - if (tombo.genero) { - if (genero.nome !== tombo.genero.nome) { - parametros.push(insereNoParametro('25', 'Genero', genero, tombo.genero.nome)); - } - } else { - parametros.push(insereNoParametro('25', 'Genero', '', genero.nome)); - } - } - - if (subEspecie) { - if (tombo.sub_especy) { - if (subEspecie.nome !== tombo.sub_especy) { - parametros.push(insereNoParametro('26', 'Subespecie', subEspecie, tombo.sub_especy.nome)); - } - } else { - parametros.push(insereNoParametro('26', 'Subespecie', '', subEspecie.nome)); - } - } - - if (subFamilia) { - if (tombo.sub_familia) { - if (subFamilia.nome !== tombo.sub_familia) { - parametros.push(insereNoParametro('27', 'Subfamilia', subFamilia, tombo.sub_familia.nome)); - } - } else { - parametros.push(insereNoParametro('27', 'Subfamilia', '', subFamilia.nome)); - } - } - - if (variedade) { - if (tombo.variedade) { - if (variedade.nome !== tombo.variedade) { - parametros.push(insereNoParametro('28', 'Variedade', variedade, tombo.variedade.nome)); - } - } else { - parametros.push(insereNoParametro('28', 'Variedade', '', variedade.nome)); - } - } - } - return parametros; - -}; - -export const visualizarAlteracaoOperador = (json, alteracao, transaction) => { - let parametros = {}; - - return new Promise((resolve, reject) => { - - parametros = { - ...parametros, - numero_tombo: alteracao.tombo_hcf, - }; - Tombo.findAll({ - where: { - hcf: alteracao.tombo_hcf, - ativo: true, - }, - include: [ - { - model: Coletor, - }, - { - model: Herbario, - }, - { - model: Variedade, - }, - { - model: Tipo, - }, - { - model: Especie, - }, - { - model: Familia, - }, - { - model: Subfamilia, - }, - { - model: Genero, - }, - { - model: Subespecie, - }, - { - model: ColecaoAnexa, - }, - { - model: LocalColeta, - include: [ - { - model: Solo, - }, - { - model: Relevo, - }, - { - model: Vegetacao, - }, - { - model: Cidade, - }, - { - model: FaseSucessional, - }, - ], - }, - ], - transaction, - }) - .then(tombo => { - parametros = { - ...parametros, - tombo_original: tombo, - }; - const visualizacaoFormatada = comparaDoisTombosOperador(tombo, json); - parametros = { - ...parametros, - retorno: visualizacaoFormatada, - }; - resolve(visualizacaoFormatada); - }) - .catch(reject); - }); -}; - -export const aprovarPendencia = async (alteracao, hcf, transaction) => { - if (!alteracao || !hcf) { - throw new BadRequestExeption(404); - } - - const tomboAtual = await Tombo.findOne({ - where: { hcf, ativo: true }, - transaction, - raw: true, - nest: true, - }); - - if (!tomboAtual) { - throw new BadRequestExeption(404); - } - - const updateTombo = {}; - const nomesCientificosPartes = []; - - if (alteracao.nomes_populares !== undefined) { - updateTombo.nomes_populares = alteracao.nomes_populares; - } - - if (alteracao.unicata !== undefined) { - updateTombo.unicata = alteracao.unicata; - } - - if (alteracao.numero_coleta !== undefined) { - updateTombo.numero_coleta = alteracao.numero_coleta; - } - - if (alteracao.observacao !== undefined) { - updateTombo.observacao = alteracao.observacao; - } - - if (alteracao.cor !== undefined) { - updateTombo.cor = alteracao.cor ? alteracao.cor.toUpperCase() : null; - } - - if (alteracao.data_tombo !== undefined) { - updateTombo.data_tombo = alteracao.data_tombo; - } - - if (alteracao.data_coleta_dia !== undefined) { - updateTombo.data_coleta_dia = alteracao.data_coleta_dia; - } - - if (alteracao.data_coleta_mes !== undefined) { - updateTombo.data_coleta_mes = alteracao.data_coleta_mes; - } - - if (alteracao.data_coleta_ano !== undefined) { - updateTombo.data_coleta_ano = alteracao.data_coleta_ano; - } - - if (alteracao.data_identificacao_dia !== undefined) { - updateTombo.data_identificacao_dia = alteracao.data_identificacao_dia; - } - - if (alteracao.data_identificacao_mes !== undefined) { - updateTombo.data_identificacao_mes = alteracao.data_identificacao_mes; - } - - if (alteracao.data_identificacao_ano !== undefined) { - updateTombo.data_identificacao_ano = alteracao.data_identificacao_ano; - } - - if (alteracao.latitude !== undefined) { - let latitudeValue = null; - if (alteracao.latitude !== null) { - if (typeof alteracao.latitude === 'string') { - latitudeValue = converteParaDecimal(alteracao.latitude); - } else { - latitudeValue = alteracao.latitude; - } - } - updateTombo.latitude = latitudeValue; - } - - if (alteracao.longitude !== undefined) { - let longitudeValue = null; - if (alteracao.longitude !== null) { - if (typeof alteracao.longitude === 'string') { - longitudeValue = converteParaDecimal(alteracao.longitude); - } else { - longitudeValue = alteracao.longitude; - } - } - updateTombo.longitude = longitudeValue; - } - - if (alteracao.altitude !== undefined) { - updateTombo.altitude = alteracao.altitude; - } - - if (alteracao.entidade_id !== undefined) { - if (alteracao.entidade_id !== null) { - const herbario = await Herbario.findOne({ - where: { id: alteracao.entidade_id }, - transaction, - raw: true, - nest: true, - }); - - if (!herbario) { - throw new BadRequestExeption(404); - } - } - updateTombo.entidade_id = alteracao.entidade_id; - } - - if (alteracao.tipo_id !== undefined) { - if (alteracao.tipo_id !== null) { - const tipo = await Tipo.findOne({ - where: { id: alteracao.tipo_id }, - transaction, - raw: true, - nest: true, - }); - - if (!tipo) { - throw new BadRequestExeption(404); - } - } - updateTombo.tipo_id = alteracao.tipo_id; - } - - if (alteracao.familia_id !== undefined) { - if (alteracao.familia_id !== null) { - const familia = await Familia.findOne({ - where: { id: alteracao.familia_id }, - transaction, - raw: true, - nest: true, - }); - - if (!familia) { - throw new BadRequestExeption(404); - } - } - - updateTombo.familia_id = alteracao.familia_id; - - if (alteracao.familia_id === null) { - updateTombo.sub_familia_id = null; - updateTombo.genero_id = null; - updateTombo.especie_id = null; - updateTombo.sub_especie_id = null; - updateTombo.variedade_id = null; - } - } - - if (alteracao.sub_familia_id !== undefined) { - if (alteracao.sub_familia_id !== null) { - const subfamilia = await Subfamilia.findOne({ - where: { - id: alteracao.sub_familia_id, - familia_id: updateTombo.familia_id || tomboAtual.familia_id, - }, - transaction, - raw: true, - nest: true, - }); - - if (!subfamilia) { - throw new BadRequestExeption(404); - } - } - - updateTombo.sub_familia_id = alteracao.sub_familia_id; - - if (alteracao.sub_familia_id === null) { - updateTombo.genero_id = null; - updateTombo.especie_id = null; - updateTombo.sub_especie_id = null; - updateTombo.variedade_id = null; - } - } - - if (alteracao.genero_id !== undefined) { - if (alteracao.genero_id !== null) { - const genero = await Genero.findOne({ - where: { - id: alteracao.genero_id, - familia_id: updateTombo.familia_id || tomboAtual.familia_id, - }, - transaction, - raw: true, - nest: true, - }); - - if (!genero) { - throw new BadRequestExeption(404); - } - nomesCientificosPartes.push(genero.nome); - } - - updateTombo.genero_id = alteracao.genero_id; - - if (alteracao.genero_id === null) { - updateTombo.especie_id = null; - updateTombo.sub_especie_id = null; - updateTombo.variedade_id = null; - } - } - - if (alteracao.especie_id !== undefined) { - if (alteracao.especie_id !== null) { - const especie = await Especie.findOne({ - where: { - id: alteracao.especie_id, - genero_id: updateTombo.genero_id || tomboAtual.genero_id, - }, - transaction, - raw: true, - nest: true, - }); - - if (!especie) { - throw new BadRequestExeption(404); - } - nomesCientificosPartes.push(especie.nome); - } - - updateTombo.especie_id = alteracao.especie_id; - - if (alteracao.especie_id === null) { - updateTombo.sub_especie_id = null; - updateTombo.variedade_id = null; - } - } - - if (alteracao.sub_especie_id !== undefined) { - if (alteracao.sub_especie_id !== null) { - const subespecie = await Subespecie.findOne({ - where: { - id: alteracao.sub_especie_id, - especie_id: updateTombo.especie_id || tomboAtual.especie_id, - }, - transaction, - raw: true, - nest: true, - }); - - if (!subespecie) { - throw new BadRequestExeption(404); - } - } - - updateTombo.sub_especie_id = alteracao.sub_especie_id; - - if (alteracao.sub_especie_id === null) { - updateTombo.variedade_id = null; - } - } - - if (alteracao.variedade_id !== undefined) { - if (alteracao.variedade_id !== null) { - const variedade = await Variedade.findOne({ - where: { - id: alteracao.variedade_id, - especie_id: updateTombo.especie_id || tomboAtual.especie_id, - }, - transaction, - raw: true, - nest: true, - }); - - if (!variedade) { - throw new BadRequestExeption(404); - } - } - - updateTombo.variedade_id = alteracao.variedade_id; - } - - if (nomesCientificosPartes.length > 0) { - updateTombo.nome_cientifico = nomesCientificosPartes.join(' '); - } else if (Object.keys(updateTombo).some(key => key.includes('genero_id') || key.includes('especie_id'))) { - updateTombo.nome_cientifico = null; - } - - if (alteracao.local_coleta_id !== undefined) { - if (alteracao.local_coleta_id !== null) { - const localColeta = await LocalColeta.findOne({ - where: { id: alteracao.local_coleta_id }, - transaction, - raw: true, - nest: true, - }); - - if (!localColeta) { - throw new BadRequestExeption(404); - } - } - updateTombo.local_coleta_id = alteracao.local_coleta_id; - } - - if (alteracao.descricao !== undefined) { - updateTombo.descricao = alteracao.descricao; - } - - if (alteracao.solo_id !== undefined) { - if (alteracao.solo_id !== null) { - const solo = await Solo.findOne({ - where: { id: alteracao.solo_id }, - transaction, - raw: true, - nest: true, - }); - - if (!solo) { - throw new BadRequestExeption(404); - } - } - updateTombo.solo_id = alteracao.solo_id; - } - - if (alteracao.relevo_id !== undefined) { - if (alteracao.relevo_id !== null) { - const relevo = await Relevo.findOne({ - where: { id: alteracao.relevo_id }, - transaction, - raw: true, - nest: true, - }); - - if (!relevo) { - throw new BadRequestExeption(404); - } - } - updateTombo.relevo_id = alteracao.relevo_id; - } - - if (alteracao.vegetacao_id !== undefined) { - if (alteracao.vegetacao_id !== null) { - const vegetacao = await Vegetacao.findOne({ - where: { id: alteracao.vegetacao_id }, - transaction, - raw: true, - nest: true, - }); - - if (!vegetacao) { - throw new BadRequestExeption(404); - } - } - updateTombo.vegetacao_id = alteracao.vegetacao_id; - } - - if (alteracao.coletor_id !== undefined) { - if (alteracao.coletor_id !== null) { - const coletor = await Coletor.findOne({ - where: { id: alteracao.coletor_id }, - transaction, - raw: true, - nest: true, - }); - - if (!coletor) { - throw new BadRequestExeption(404); - } - - } - updateTombo.coletor_id = alteracao.coletor_id; - } - - updateTombo.rascunho = false; - - if (Object.keys(updateTombo).length > 0) { - await Tombo.update(updateTombo, { - where: { hcf }, - transaction, - }); - } - - if (alteracao.identificadores !== undefined) { - await TomboIdentificador.destroy({ - where: { tombo_hcf: hcf }, - transaction, - }); - - if (Array.isArray(alteracao.identificadores) && alteracao.identificadores.length > 0) { - const identificadoresPromises = alteracao.identificadores.map(async (identificadorId, index) => { - const identificador = await Identificador.findOne({ - where: { id: identificadorId }, - transaction, - raw: true, - nest: true, - }); - - if (!identificador) { - throw new BadRequestExeption(404); - } - - return TomboIdentificador.create({ - tombo_hcf: hcf, - identificador_id: identificadorId, - ordem: index + 1, - }, { transaction }); - }); - - await Promise.all(identificadoresPromises); - } - } - - if (alteracao.complementares !== undefined) { - await ColetorComplementar.destroy({ - where: { hcf }, - transaction, - }); - - if (alteracao.complementares) { - await ColetorComplementar.create({ - hcf, - complementares: alteracao.complementares, - }, { transaction }); - } - } - - if (alteracao.colecoes_anexas_tipo !== undefined || alteracao.colecoes_anexas_observacoes !== undefined) { - const tomboAtualizado = await Tombo.findOne({ - where: { hcf }, - transaction, - raw: true, - nest: true, - }); - - if (tomboAtualizado.colecao_anexa_id) { - const updateColecao = {}; - - if (alteracao.colecoes_anexas_tipo !== undefined) { - updateColecao.tipo = alteracao.colecoes_anexas_tipo; - } - - if (alteracao.colecoes_anexas_observacoes !== undefined) { - updateColecao.observacoes = alteracao.colecoes_anexas_observacoes; - } - - if (Object.keys(updateColecao).length > 0) { - await ColecaoAnexa.update(updateColecao, { - where: { id: tomboAtualizado.colecao_anexa_id }, - transaction, - }); - } - } else if (alteracao.colecoes_anexas_tipo || alteracao.colecoes_anexas_observacoes) { - const novaColecao = await ColecaoAnexa.create({ - tipo: alteracao.colecoes_anexas_tipo, - observacoes: alteracao.colecoes_anexas_observacoes, - }, { transaction }); - - await Tombo.update({ - colecao_anexa_id: novaColecao.id, - }, { - where: { hcf }, - transaction, - }); - } - } - - const tomboFinal = await Tombo.findOne({ - where: { hcf, ativo: true }, - transaction, - raw: true, - nest: true, - }); - - return { - success: true, - message: 'Pendência aprovada com sucesso', - tombo: tomboFinal, - }; -}; - -export const visualizarComJsonNome = (alteracao, hcf, transaction) => new Promise((resolve, reject) => { - Tombo.findOne({ - where: { - hcf, - }, - include: [ - { - model: Variedade, - }, - { - model: Especie, - }, - { - model: Familia, - }, - { - model: Subfamilia, - }, - { - model: Genero, - }, - { - model: Subespecie, - }, - ], - transaction, - }) - .then(tombos => { - // eslint-disable-next-line - var jsonRetorno = []; - if (tombos.especy) { - if (alteracao.especie_nome) { - if (tombos.especy.nome !== alteracao.especie_nome || tombos.rascunho) { - jsonRetorno.push({ - key: '1', - campo: 'Especie', - antigo: tombos.especy.nome, - novo: alteracao.especie_nome, - }); - } - } - } else if (alteracao.especie_nome || tombos.rascunho) { - jsonRetorno.push({ - key: '1', - campo: 'Especie', - antigo: '', - novo: alteracao.especie_nome, - }); - } - if (tombos.familia) { - if (alteracao.familia_nome) { - if (tombos.familia.nome !== alteracao.familia_nome || tombos.rascunho) { - jsonRetorno.push({ - key: '2', - campo: 'Familia', - antigo: tombos.familia.nome, - novo: alteracao.familia_nome, - }); - } - } - } else if (alteracao.familia_nome || tombos.rascunho) { - jsonRetorno.push({ - key: '2', - campo: 'Familia', - antigo: '', - novo: alteracao.familia_nome, - }); - } - if (tombos.genero) { - if (alteracao.genero_nome) { - if (tombos.genero.nome !== alteracao.genero_nome || tombos.rascunho) { - jsonRetorno.push({ - key: '3', - campo: 'Gênero', - antigo: tombos.genero.nome, - novo: alteracao.genero_nome, - }); - } - } - } else if (alteracao.genero_nome || tombos.rascunho) { - jsonRetorno.push({ - key: '3', - campo: 'Gênero', - antigo: '', - novo: alteracao.genero_nome, - }); - } - if (tombos.variedade) { - if (alteracao.variedade_nome) { - if (tombos.variedade.nome !== alteracao.variedade_nome || tombos.rascunho) { - jsonRetorno.push({ - key: '4', - campo: 'Variedade', - antigo: tombos.variedade.nome, - novo: alteracao.variedade_nome, - }); - } - } - } else if (alteracao.variedade_nome || tombos.rascunho) { - jsonRetorno.push({ - key: '4', - campo: 'Variedade', - antigo: '', - novo: alteracao.variedade_nome, - }); - } - if (tombos.sub_especy) { - if (alteracao.subespecie_nome) { - if (tombos.sub_especy.nome !== alteracao.subespecie_nome || tombos.rascunho) { - jsonRetorno.push({ - key: '5', - campo: 'Subespecie', - antigo: tombos.sub_especy.nome, - novo: alteracao.subespecie_nome, - }); - } - } - } else if (alteracao.subespecie_nome || tombos.rascunho) { - jsonRetorno.push({ - key: '5', - campo: 'Subespecie', - antigo: '', - novo: alteracao.subespecie_nome, - }); - } - if (tombos.sub_familia || tombos.rascunho) { - if (alteracao.subfamilia_nome) { - if (tombos.sub_familia.nome !== alteracao.subfamilia_nome) { - jsonRetorno.push({ - key: '6', - campo: 'Subfamilia', - antigo: tombos.sub_familia.nome, - novo: alteracao.subfamilia_nome, - }); - } - } - } else if (alteracao.subfamilia_nome || tombos.rascunho) { - jsonRetorno.push({ - key: '6', - campo: 'Subfamilia', - antigo: '', - novo: alteracao.subfamilia_nome, - }); - } - resolve(jsonRetorno); - }) - .catch(reject); -}); - -export async function visualizar(request, response, next) { - try { - const id = request.params.pendencia_id; - const alteracao = await Alteracao.findOne({ - where: { ativo: true, id }, - }); - - if (!alteracao) { - throw new BadRequestExeption(800); - } - - const objetoAlterado = JSON.parse(alteracao.tombo_json); - const parametros = {}; - const alteracaoAprovada = alteracao.status === 'APROVADO'; - - if (objetoAlterado.nomes_populares !== undefined) { - parametros.nome_popular = objetoAlterado.nomes_populares; - } - - if (objetoAlterado.numero_coleta !== undefined) { - parametros.numero_coleta = objetoAlterado.numero_coleta; - } - - if (objetoAlterado.data_coleta_dia !== undefined) { - parametros.data_coleta_dia = objetoAlterado.data_coleta_dia; - } - - if (objetoAlterado.data_coleta_mes !== undefined) { - parametros.data_coleta_mes = objetoAlterado.data_coleta_mes; - } - - if (objetoAlterado.data_coleta_ano !== undefined) { - parametros.data_coleta_ano = objetoAlterado.data_coleta_ano; - } - - if (objetoAlterado.cor !== undefined) { - parametros.cor = objetoAlterado.cor; - } - - if (objetoAlterado.altitude !== undefined) { - parametros.altitude = objetoAlterado.altitude; - } - - if (objetoAlterado.local_coleta_id !== undefined) { - parametros.localColeta = await LocalColeta.findOne({ where: { id: objetoAlterado.local_coleta_id }, raw: true, nest: true }); - } - - if (objetoAlterado.descricao !== undefined) { - parametros.descricao = objetoAlterado.descricao; - } - - if (objetoAlterado.data_identificacao_dia !== undefined) { - parametros.data_identificacao_dia = objetoAlterado.data_identificacao_dia; - } - - if (objetoAlterado.data_identificacao_mes !== undefined) { - parametros.data_identificacao_mes = objetoAlterado.data_identificacao_mes; - } - - if (objetoAlterado.data_identificacao_ano !== undefined) { - parametros.data_identificacao_ano = objetoAlterado.data_identificacao_ano; - } - - if (objetoAlterado.colecoes_anexas_observacoes !== undefined) { - parametros.colecoes_anexas_observacoes = objetoAlterado.colecoes_anexas_observacoes; - } - - if (objetoAlterado.observacao !== undefined) { - parametros.observacoes = objetoAlterado.observacao; - } - - if (objetoAlterado.unicata !== undefined) { - parametros.unicata = objetoAlterado.unicata; - } - - if (objetoAlterado.latitude !== undefined) { - parametros.latitude = objetoAlterado.latitude; - } - - if (objetoAlterado.longitude !== undefined) { - parametros.longitude = objetoAlterado.longitude; - } - - if (objetoAlterado.coletor_id !== undefined) { - parametros.coletor = await Coletor.findOne({ where: { id: objetoAlterado.coletor_id }, raw: true, nest: true }); - } - - if (objetoAlterado.complementares !== undefined) { - parametros.complementares = objetoAlterado.complementares; - } - - if (objetoAlterado.familia_id !== undefined) { - parametros.familia = await Familia.findOne({ where: { id: objetoAlterado.familia_id }, raw: true, nest: true }); - } - - if (objetoAlterado.subfamilia_id !== undefined) { - parametros.subfamilia = await Subfamilia.findOne({ where: { id: objetoAlterado.subfamilia_id }, raw: true, nest: true }); - } - - if (objetoAlterado.genero_id !== undefined) { - parametros.genero = await Genero.findOne({ where: { id: objetoAlterado.genero_id }, raw: true, nest: true }); - } - - if (objetoAlterado.especie_id !== undefined) { - parametros.especie = await Especie.findOne({ where: { id: objetoAlterado.especie_id }, raw: true, nest: true }); - } - - if (objetoAlterado.identificadores !== undefined) { - const idsIdent = Array.isArray(objetoAlterado.identificadores) - ? objetoAlterado.identificadores - : [objetoAlterado.identificadores]; - parametros.identificadores = await Identificador.findAll({ - where: { id: { [Op.in]: idsIdent } }, - raw: true, - nest: true, - }); - } - - if (objetoAlterado.fase_sucessional_id !== undefined) { - parametros.faseSucessional = await FaseSucessional.findOne({ where: { numero: objetoAlterado.fase_sucessional_id }, raw: true, nest: true }); - } - - if (objetoAlterado.vegetacao_id !== undefined) { - parametros.vegetacao = await Vegetacao.findOne({ where: { id: objetoAlterado.vegetacao_id }, raw: true, nest: true }); - } - - if (objetoAlterado.relevo_id !== undefined) { - parametros.relevo = await Relevo.findOne({ where: { id: objetoAlterado.relevo_id }, raw: true, nest: true }); - } - - if (objetoAlterado.solo_id !== undefined) { - parametros.solo = await Solo.findOne({ where: { id: objetoAlterado.solo_id }, raw: true, nest: true }); - } - - if (objetoAlterado.cidade_id !== undefined) { - parametros.cidade = await Cidade.findOne({ where: { id: objetoAlterado.cidade_id }, raw: true, nest: true }); - } - - if (objetoAlterado.tipo_id !== undefined) { - parametros.tipo = await Tipo.findOne({ where: { id: objetoAlterado.tipo_id }, raw: true, nest: true }); - } - - if (objetoAlterado.entidade_id !== undefined) { - parametros.entidade = await Herbario.findOne({ where: { id: objetoAlterado.entidade_id }, raw: true, nest: true }); - } - - if (objetoAlterado.variedade_id !== undefined) { - parametros.variedade = await Variedade.findOne({ where: { id: objetoAlterado.variedade_id }, raw: true, nest: true }); - } - - if (objetoAlterado.sub_especie_id !== undefined) { - parametros.subespecie = await Subespecie.findOne({ where: { id: objetoAlterado.sub_especie_id }, raw: true, nest: true }); - } - - const tombo = await Tombo.findOne({ - where: { hcf: alteracao.dataValues.tombo_hcf, ativo: true }, - include: [ - { model: Variedade }, { model: Especie }, { model: Familia }, - { model: Subfamilia }, { model: Genero }, { model: Subespecie }, - { model: Herbario }, { model: Tipo }, { model: Coletor }, { model: ColetorComplementar, as: 'coletor_complementar' }, - { model: Solo }, { model: Relevo }, { model: Vegetacao }, { model: ColecaoAnexa }, - { - model: LocalColeta, - as: 'locais_coletum', - include: [{ model: Cidade }, { model: FaseSucessional }], - }, - { model: Usuario }, - ], - raw: true, - nest: true, - }); - - if (!tombo) { - throw new BadRequestExeption(801, 'Tombo não encontrado'); - } - - const jsonRetorno = []; - const ehRascunho = tombo?.rascunho === 1; - - const converteDecimalParaDMS = (decimal, isLatitude = true) => { - if (decimal === null || decimal === undefined || decimal === '') { - return ''; - } - - const abs = Math.abs(decimal); - const graus = Math.floor(abs); - const minutosDecimal = (abs - graus) * 60; - const minutos = Math.floor(minutosDecimal); - const segundos = ((minutosDecimal - minutos) * 60).toFixed(2); - - let hemisferio; - if (isLatitude) { - hemisferio = decimal >= 0 ? 'N' : 'S'; - } else { - hemisferio = decimal >= 0 ? 'E' : 'W'; - } - - return `${graus}° ${minutos}' ${segundos}" ${hemisferio}`; - }; - - const addRetorno = (key, campo, antigo, novo) => { - const antigoStr = String(antigo || '').trim(); - const novoStr = String(novo || '').trim(); - - if (antigoStr === '' && novoStr === '') { - return; - } - if (antigoStr !== novoStr) { - jsonRetorno.push({ key, campo, antigo: antigoStr, novo: novoStr }); - } - }; - - if (parametros.familia !== undefined) { - const nomeFamilia = typeof parametros.familia === 'string' ? parametros.familia : parametros.familia?.nome || ''; - const antigoFamilia = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.familia?.nome || ''); - addRetorno('1', 'Família', antigoFamilia, nomeFamilia); - } - - if (parametros.subfamilia !== undefined) { - const nomeSubfamilia = typeof parametros.subfamilia === 'string' ? parametros.subfamilia : parametros.subfamilia?.nome || ''; - const antigoSubfamilia = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.sub_familia?.nome || ''); - addRetorno('2', 'Subfamília', antigoSubfamilia, nomeSubfamilia); - } - - if (parametros.genero !== undefined) { - const nomeGenero = typeof parametros.genero === 'string' ? parametros.genero : parametros.genero?.nome || ''; - const antigoGenero = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.genero?.nome || ''); - addRetorno('3', 'Gênero', antigoGenero, nomeGenero); - } - - if (parametros.especie !== undefined) { - const nomeEspecie = typeof parametros.especie === 'string' ? parametros.especie : parametros.especie?.nome || ''; - const antigoEspecie = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.especy?.nome || ''); - addRetorno('4', 'Espécie', antigoEspecie, nomeEspecie); - } - - if (parametros.subespecie !== undefined) { - const antigoSubespecie = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.sub_especy?.nome || ''); - addRetorno('5', 'Subespécie', antigoSubespecie, parametros.subespecie?.nome || ''); - } - - if (parametros.variedade !== undefined) { - const antigoVariedade = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.variedade?.nome || ''); - addRetorno('6', 'Variedade', antigoVariedade, parametros.variedade?.nome || ''); - } - - if (parametros.coletor !== undefined) { - const antigoColetor = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.coletore?.nome || ''); - addRetorno('7', 'Coletor', antigoColetor, parametros.coletor?.nome || ''); - } - - if (parametros.complementares !== undefined) { - const complementaresAtuais = tombo?.coletor_complementar?.complementares || ''; - const complementaresNovos = parametros.complementares === null ? '' : parametros.complementares; - const antigoComplementares = (alteracaoAprovada || ehRascunho) ? '' : complementaresAtuais; - addRetorno('8', 'Coletores complementares', antigoComplementares, complementaresNovos); - } - - if (parametros.numero_coleta !== undefined) { - const antigoNumeroColeta = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.numero_coleta || ''); - addRetorno('9', 'Número da coleta', antigoNumeroColeta, parametros.numero_coleta); - } - - if (parametros.data_coleta_dia !== undefined) { - const antigoDataDia = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_coleta_dia || ''); - addRetorno('10', 'Data de coleta dia', antigoDataDia, parametros.data_coleta_dia); - } - - if (parametros.data_coleta_mes !== undefined) { - const antigoDataMes = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_coleta_mes || ''); - addRetorno('11', 'Data de coleta mês', antigoDataMes, parametros.data_coleta_mes); - } - - if (parametros.data_coleta_ano !== undefined) { - const antigoDataAno = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_coleta_ano || ''); - addRetorno('12', 'Data de coleta ano', antigoDataAno, parametros.data_coleta_ano); - } - - if (parametros.cor !== undefined) { - const antigoCor = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.cor || ''); - addRetorno('13', 'Localidade cor', antigoCor, parametros.cor); - } - - if (parametros.nome_popular !== undefined) { - const antigoNomePopular = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.nomes_populares || ''); - addRetorno('14', 'Nome popular', antigoNomePopular, parametros.nome_popular); - } - - if (parametros.entidade !== undefined) { - const antigoHerbario = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.herbario?.nome || ''); - addRetorno('15', 'Herbário', antigoHerbario, parametros.entidade?.nome || ''); - } - - if (parametros.tipo !== undefined) { - const antigoTipo = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.tipo?.nome || ''); - addRetorno('16', 'Tipo', antigoTipo, parametros.tipo?.nome || ''); - } - - if (parametros.latitude !== undefined) { - const antigoLatitude = (alteracaoAprovada || ehRascunho) ? '' : converteDecimalParaDMS(tombo?.latitude, true); - const novoLatitude = converteDecimalParaDMS(parametros.latitude, true); - addRetorno('17', 'Latitude', antigoLatitude, novoLatitude); - } - - if (parametros.longitude !== undefined) { - const antigoLongitude = (alteracaoAprovada || ehRascunho) ? '' : converteDecimalParaDMS(tombo?.longitude, false); - const novoLongitude = converteDecimalParaDMS(parametros.longitude, false); - addRetorno('18', 'Longitude', antigoLongitude, novoLongitude); - } - - if (parametros.altitude !== undefined) { - const antigoAltitude = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.altitude || ''); - addRetorno('19', 'Altitude', antigoAltitude, parametros.altitude); - } - - if (parametros.localColeta !== undefined) { - const antigoLocalColeta = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.locais_coletum?.descricao || ''); - addRetorno('20', 'Local de Coleta', antigoLocalColeta, parametros.localColeta?.descricao || ''); - } - - if (parametros.descricao !== undefined) { - const antigoDescricao = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.descricao || ''); - addRetorno('21', 'Descrição do relevo', antigoDescricao, parametros.descricao); - } - - if (parametros.solo !== undefined) { - const antigoSolo = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.solo?.nome || ''); - addRetorno('22', 'Solo', antigoSolo, parametros.solo?.nome || ''); - } - - if (parametros.relevo !== undefined) { - const antigoRelevo = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.relevo?.nome || ''); - addRetorno('23', 'Relevo', antigoRelevo, parametros.relevo?.nome || ''); - } - - if (parametros.vegetacao !== undefined) { - const antigoVegetacao = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.vegetaco?.nome || ''); - addRetorno('24', 'Vegetação', antigoVegetacao, parametros.vegetacao?.nome || ''); - } - - if (parametros.identificadores !== undefined) { - const identificadoresAtuais = await TomboIdentificador.findAll({ - attributes: ['tombo_hcf', 'identificador_id', 'ordem'], - where: { tombo_hcf: tombo?.hcf }, - include: [{ model: Identificador }], - order: [['ordem', 'ASC']], - raw: true, - nest: true, - }); - - const nomesNovos = parametros.identificadores.map(ident => ident.nome).join(', '); - const nomesAntigos = identificadoresAtuais.map(ident => ident.identificadore?.nome || '').join(', '); - const antigoIdentificadores = (alteracaoAprovada || ehRascunho) ? '' : nomesAntigos; - - addRetorno('25', 'Identificadores', antigoIdentificadores, nomesNovos); - } - - if (parametros.data_identificacao_dia !== undefined) { - const antigoDataIdentDia = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_identificacao_dia || ''); - addRetorno('26', 'Data de identificação dia', antigoDataIdentDia, parametros.data_identificacao_dia); - } - - if (parametros.data_identificacao_mes !== undefined) { - const antigoDataIdentMes = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_identificacao_mes || ''); - addRetorno('27', 'Data de identificação mês', antigoDataIdentMes, parametros.data_identificacao_mes); - } - - if (parametros.data_identificacao_ano !== undefined) { - const antigoDataIdentAno = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_identificacao_ano || ''); - addRetorno('28', 'Data de identificação ano', antigoDataIdentAno, parametros.data_identificacao_ano); - } - - if (objetoAlterado.colecoes_anexas_tipo !== undefined) { - const antigoTipoColecao = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.colecoes_anexa?.tipo || ''); - addRetorno('29', 'Tipo - Coleção Anexa', antigoTipoColecao, objetoAlterado.colecoes_anexas_tipo); - } - - if (parametros.colecoes_anexas_observacoes !== undefined) { - const antigoObsColecao = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.colecoes_anexa?.observacoes || ''); - addRetorno('30', 'Observações - Coleção Anexa', antigoObsColecao, parametros.colecoes_anexas_observacoes); - } - - if (parametros.observacoes !== undefined) { - const antigoObservacoes = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.observacao || ''); - addRetorno('31', 'Observações', antigoObservacoes, parametros.observacoes); - } - - if (parametros.unicata !== undefined) { - let unicataAntigo; - if (alteracaoAprovada || ehRascunho) { - unicataAntigo = ''; - } else { - unicataAntigo = tombo?.unicata ? 'Unicata' : 'Duplicata'; - } - - const unicataNovo = parametros.unicata ? 'Unicata' : 'Duplicata'; - addRetorno('32', 'Tipo de Exsicata', unicataAntigo, unicataNovo); - } - - const jsonRender = { - fotos: { novas: [], antigas: [] }, - status: null, - tabela: jsonRetorno, - }; - - response.status(codigos.LISTAGEM).json(jsonRender); - } catch (error) { - next(error); - } -} - -export function aceitarPendencia(request, response, next) { - const id = request.params.pendencia_id; - const { observacao, status } = request.body; - let retorno = {}; - const callback = transaction => Promise.resolve() - .then(() => Alteracao.update({ - observacao, - status, - }, { - where: { - ativo: true, - id, - }, - transaction, - })) - .then(() => Alteracao.findOne({ - where: { - ativo: true, - id, - }, - transaction, - })) - .then(alt => { - if (status === 'APROVADO') { - const objetoAlterado = JSON.parse(alt.tombo_json); - retorno = aprovarPendencia(objetoAlterado, alt.tombo_hcf, transaction); - } - return retorno; - }); - sequelize.transaction(callback) - .then(() => { - // eslint-disable-next-line no-underscore-dangle - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); - -} - -export function avaliaPendencia(request, response, next) { - const { pendencia_id: pendenciaId } = request.params; - const { observacao, status } = request.body; - - return Promise.resolve() - .then(() => { - Alteracao.update({ - status, - observacao, - }, { - where: { - id: pendenciaId, - }, - }).then(pendencias => { - response.status(codigos.BUSCAR_UM_ITEM) - .json(pendencias); - }); - }) - .catch(next); -} - -export function verificaAlteracao(request, response, next) { - const { tombo_id: tomboId } = request.params; - const callback = transaction => Promise.resolve() - .then(() => Alteracao.findOne({ - where: { - status: 'ESPERANDO', - tombo_hcf: tomboId, - }, - transaction, - })) - .then(retorno => retorno); - sequelize.transaction(callback) - .then(retorno => { - response.status(codigos.BUSCAR_VARIOS_ITENS) - .json(retorno); - - }) - .catch(next); - -} +import BadRequestExeption from '../errors/bad-request-exception'; +import { converteParaDecimal } from '../helpers/coordenadas'; +import models from '../models'; +import codigos from '../resources/codigos-http'; + +const { + Alteracao, + Usuario, + Herbario, + Solo, + Relevo, + Vegetacao, + Cidade, + FaseSucessional, + LocalColeta, + sequelize, + Sequelize: { Op }, + Tombo, + Especie, + Variedade, + Coletor, + Tipo, + Familia, + Subfamilia, + Genero, + Subespecie, + ColecaoAnexa, + TomboIdentificador, + Identificador, + ColetorComplementar, +} = models; + +export const listagem = (request, response, next) => { + const { limite, pagina, offset } = request.paginacao; + const { status, nome_usuario: nomeUsuario } = request.query; + const retorno = { + metadados: { + total: 0, + pagina, + limite, + }, + resultado: {}, + }; + let where = { + ativo: 1, + }; + let whereUsuario = {}; + if (status) { + where = { + ...where, + status, + }; + } else { + where = { + ...where, + status: { [Op.ne]: 'APROVADO' }, + }; + } + if (nomeUsuario) { + whereUsuario = { + nome: { [Op.like]: `%${nomeUsuario}%` }, + }; + } + const callback = transaction => Promise.resolve() + .then(() => Alteracao.findAndCountAll({ + include: [ + { + model: Usuario, + whereUsuario, + }, + ], + limit: limite, + offset, + where, + order: [['id', 'DESC']], + transaction, + })) + .then(alteracoes => { + retorno.metadados.total = alteracoes.count; + // const alteracoesValidas = alteracoes.rows.filter(item => { + // if (item.usuario.tipo_usuario_id === 1) { + // return false; + // } + // if (item.identificacao) { + // if (item.usuario.tipo_usuario_id === 3) { + // return true; + // } + // return false; + // } + // return true; + // }); + retorno.resultado = alteracoes.rows.map(item => ({ + id: item.id, + nome_usuario: item.usuario.nome, + numero_tombo: item.tombo_hcf, + json: JSON.parse(item.tombo_json), + data_criacao: item.created_at, + status: item.status, + observacao: item.observacao || '', + })); + return retorno; + }); + sequelize.transaction(callback) + .then(() => { + response.status(codigos.LISTAGEM).json(retorno); + }) + .catch(next); +}; + +export const desativar = (request, response, next) => { + const id = request.params.pendencia_id; + + const callback = transaction => Promise.resolve() + .then(() => Alteracao.findOne({ + where: { + ativo: true, + id, + }, + transaction, + })) + .then(alteracao => { + if (!alteracao) { + throw new BadRequestExeption(800); + } + return Alteracao.update({ + ativo: false, + }, { + where: { + id, + }, + transaction, + }); + }); + sequelize.transaction(callback) + .then(() => { + response.status(codigos.DESATIVAR).send(); + }) + .catch(next); +}; + +const comparaDoisTombos = (tombo, tomboAlterado) => { + const parametros = []; + if (tombo.data_coleta_dia !== tomboAlterado.data_coleta_dia) { + parametros.push({ + key: '1', + campo: 'Dia da coleta', + antigo: tombo.data_coleta_dia, + novo: tomboAlterado.data_coleta_dia, + }); + } + if (tombo.data_coleta_mes !== tomboAlterado.data_coleta_mes) { + parametros.push({ + key: '2', + campo: 'Mes da coleta', + antigo: tombo.data_coleta_mes, + novo: tomboAlterado.data_coleta_mes, + }); + } + if (tombo.data_coleta_ano !== tomboAlterado.data_coleta_ano) { + parametros.push({ + key: '3', + campo: 'Ano da coleta', + antigo: tombo.data_coleta_ano, + novo: tomboAlterado.data_coleta_ano, + }); + } + if (tombo.observacao !== tomboAlterado.observacao) { + parametros.push({ + key: '4', + campo: 'Observação', + antigo: tombo.observacao, + novo: tomboAlterado.observacao, + }); + } + if (tombo.nomes_populares !== tomboAlterado.nomes_populares) { + parametros.push({ + key: '5', + campo: 'Nomes populares', + antigo: tombo.nomes_populares, + novo: tomboAlterado.nomes_populares, + }); + } + if (tombo.numero_coleta !== tomboAlterado.numero_coleta) { + parametros.push({ + key: '6', + campo: 'Numero de coleta', + antigo: tombo.numero_coleta, + novo: tomboAlterado.numero_coleta, + }); + } + if (tombo.latitude !== tomboAlterado.latitude) { + parametros.push({ + key: '7', + campo: 'Latitude', + antigo: tombo.latitude, + novo: tomboAlterado.latitude, + }); + } + if (tombo.longitude !== tomboAlterado.longitude) { + parametros.push({ + key: '8', + campo: 'Longitude', + antigo: tombo.longitude, + novo: tomboAlterado.longitude, + }); + } + if (tombo.altitude !== tomboAlterado.altitude) { + parametros.push({ + key: '9', + campo: 'Altitude', + antigo: tombo.altitude, + novo: tomboAlterado.altitude, + }); + } + if (tombo.herbario && tomboAlterado.herbario + && (tombo.herbario.nome !== tomboAlterado.herbario.nome)) { + parametros.push({ + key: '10', + campo: 'Herbário', + antigo: tombo.herbario.nome, + novo: tomboAlterado.herbario.nome, + }); + } + if (tombo.locais_coletum && tomboAlterado.locais_coletum + && tombo.locais_coletum.descricao !== tomboAlterado.locais_coletum.descricao) { + parametros.push({ + key: '11', + campo: 'Descrição do local de coleta', + antigo: tombo.locais_coletum.descricao, + novo: tomboAlterado.locais_coletum.descricao, + }); + } + if (tombo.locais_coletum && tombo.locais_coletum.solo + && tomboAlterado.locais_coletum && tomboAlterado.locais_coletum.solo + && tombo.locais_coletum.solo.nome !== tomboAlterado.locais_coletum.solo.nome) { + parametros.push({ + key: '12', + campo: 'Solo', + antigo: tombo.locais_coletum.solo.nome, + novo: tomboAlterado.locais_coletum.solo.nome, + }); + } + if (tombo.locais_coletum && tombo.locais_coletum.relevo + && tombo.locais_coletum && tombo.locais_coletum.relevo + && tombo.locais_coletum.relevo.nome !== tomboAlterado.locais_coletum.relevo.nome) { + parametros.push({ + key: '13', + campo: 'Relevo', + antigo: tombo.locais_coletum.relevo.nome, + novo: tomboAlterado.locais_coletum.relevo.nome, + }); + } + if (tombo.locais_coletum && tombo.locais_coletum.vegetaco + && tomboAlterado.locais_coletum && tomboAlterado.locais_coletum.vegetaco + && tombo.locais_coletum.vegetaco.nome !== tomboAlterado.locais_coletum.vegetaco.nome) { + parametros.push({ + key: '14', + campo: 'Vegetação', + antigo: tombo.locais_coletum.vegetaco.nome, + novo: tomboAlterado.locais_coletum.vegetaco.nome, + }); + } + if (tombo.locais_coletum && tombo.locais_coletum.cidade + && tomboAlterado.locais_coletum && tomboAlterado.locais_coletum.cidade + && tombo.locais_coletum.cidade.nome !== tomboAlterado.locais_coletum.cidade.nome) { + parametros.push({ + key: '15', + campo: 'Cidade', + antigo: tombo.locais_coletum.cidade.nome, + novo: tomboAlterado.locais_coletum.cidade.nome, + }); + } + if (tombo.locais_coletum && tomboAlterado.locais_coletum + && tombo.locais_coletum.fase_sucessional !== tomboAlterado.locais_coletum.fase_sucessional) { + parametros.push({ + key: '16', + campo: 'Fase Sucessional', + antigo: tombo.locais_coletum.fase_sucessional, + novo: tomboAlterado.locais_coletum.fase_sucessional, + }); + } + if (tombo.situacao !== tomboAlterado.situacao) { + parametros.push({ + key: '17', + campo: 'Situação', + antigo: tombo.situacao, + novo: tomboAlterado.situacao, + }); + } + if (tombo.nome_cientifico !== tomboAlterado.nome_cientifico) { + parametros.push({ + key: '18', + campo: 'Nome Científico', + antigo: tombo.nome_cientifico, + novo: tomboAlterado.nome_cientifico, + }); + } + if (tombo.cor !== tomboAlterado.cor) { + parametros.push({ + key: '19', + campo: 'Cor - Localização', + antigo: tombo.cor, + novo: tomboAlterado.cor, + }); + } + if (tombo.variedade && tomboAlterado.variedade + && tombo.variedade.nome !== tomboAlterado.variedade.nome) { + parametros.push({ + key: '20', + campo: 'Variedade', + antigo: tombo.variedade.nome, + novo: tomboAlterado.variedade.nome, + }); + } + if (tombo.tipo && tomboAlterado.tipo + && tombo.tipo.nome !== tomboAlterado.tipo.nome) { + parametros.push({ + key: '21', + campo: 'Tipo', + antigo: tombo.tipo.nome, + novo: tomboAlterado.tipo.nome, + }); + } + if (tombo.especy && tomboAlterado.especy + && tombo.especy.nome !== tomboAlterado.especy.nome) { + parametros.push({ + key: '22', + campo: 'Espécie', + antigo: tombo.especy.nome, + novo: tomboAlterado.especy.nome, + }); + } + if (tombo.genero && tomboAlterado.genero + && tombo.genero.nome !== tomboAlterado.genero.nome) { + parametros.push({ + key: '23', + campo: 'Género', + antigo: tombo.genero.nome, + novo: tomboAlterado.genero.nome, + }); + } + if (tombo.familia && tomboAlterado.familia + && tombo.familia.nome !== tomboAlterado.familia.nome) { + parametros.push({ + key: '24', + campo: 'Família', + antigo: tombo.familia.nome, + novo: tomboAlterado.familia.nome, + }); + } + if (tombo.sub_familia && tomboAlterado.sub_familia + && tombo.sub_familia.nome !== tomboAlterado.sub_familia.nome) { + parametros.push({ + key: '25', + campo: 'Subfamília', + antigo: tombo.sub_familia.nome, + novo: tomboAlterado.sub_familia.nome, + }); + } + if (tombo.sub_especy && tomboAlterado.sub_especy + && tombo.sub_especy.nome !== tomboAlterado.sub_especy.nome) { + parametros.push({ + key: '26', + campo: 'Subespécie', + antigo: tombo.sub_especy.nome, + novo: tomboAlterado.sub_especy.nome, + }); + } + if (tombo.colecoes_anexa && tomboAlterado.colecoes_anexa + && tombo.colecoes_anexa.observacoes !== tomboAlterado.colecoes_anexa.observacoes) { + parametros.push({ + key: '27', + campo: 'Observações - Coleção Anexa', + antigo: tombo.colecoes_anexa.observacoes, + novo: tomboAlterado.colecoes_anexa.observacoes, + }); + } + if (tombo.colecoes_anexa && tomboAlterado.colecoes_anexa + && tombo.colecoes_anexa.tipo !== tomboAlterado.colecoes_anexa.tipo) { + parametros.push({ + key: '28', + campo: 'Tipo - Coleção Anexa', + antigo: tombo.colecoes_anexa.tipo, + novo: tomboAlterado.colecoes_anexa.tipo, + }); + } + + return parametros; +}; + +export const formatarTomboNovo = tombo => { + const parametros = []; + parametros.push({ + key: '1', + campo: 'Dia da coleta', + antigo: '', + novo: tombo.data_coleta_dia, + }); + parametros.push({ + key: '2', + campo: 'Mes da coleta', + antigo: '', + novo: tombo.data_coleta_mes, + }); + parametros.push({ + key: '3', + campo: 'Ano da coleta', + antigo: '', + novo: tombo.data_coleta_ano, + }); + parametros.push({ + key: '4', + campo: 'Observação', + antigo: '', + novo: tombo.observacao, + }); + parametros.push({ + key: '5', + campo: 'Nomes populares', + antigo: '', + novo: tombo.nomes_populares, + }); + parametros.push({ + key: '6', + campo: 'Numero de coleta', + antigo: '', + novo: tombo.numero_coleta, + }); + parametros.push({ + key: '7', + campo: 'Latitude', + antigo: '', + novo: tombo.latitude, + }); + parametros.push({ + key: '8', + campo: 'Longitude', + antigo: '', + novo: tombo.longitude, + }); + parametros.push({ + key: '9', + campo: 'Altitude', + antigo: '', + novo: tombo.altitude, + }); + if (tombo.herbario) { + parametros.push({ + key: '10', + campo: 'Herbário', + antigo: '', + novo: tombo.herbario.nome, + }); + } + if (tombo.locais_coletum) { + parametros.push({ + key: '11', + campo: 'Descrição do local de coleta', + antigo: '', + novo: tombo.locais_coletum.descricao, + }); + if (tombo.locais_coletum.solo) { + parametros.push({ + key: '12', + campo: 'Solo', + antigo: '', + novo: tombo.locais_coletum.solo.nome, + }); + } + if (tombo.locais_coletum.relevo) { + parametros.push({ + key: '13', + campo: 'Relevo', + antigo: '', + novo: tombo.locais_coletum.relevo.nome, + }); + } + if (tombo.locais_coletum.vegetaco) { + parametros.push({ + key: '14', + campo: 'Vegetação', + antigo: '', + novo: tombo.locais_coletum.vegetaco.nome, + }); + } + if (tombo.locais_coletum.cidade) { + parametros.push({ + key: '15', + campo: 'Cidade', + antigo: '', + novo: tombo.locais_coletum.cidade.nome, + }); + } + if (tombo.locais_coletum.fase_sucessional) { + parametros.push({ + key: '16', + campo: 'Fase Sucessional', + antigo: '', + novo: tombo.locais_coletum.fase_sucessional.nome, + }); + } + } + parametros.push({ + key: '17', + campo: 'Situação', + antigo: '', + novo: tombo.situacao, + }); + parametros.push({ + key: '18', + campo: 'Nome Científico', + antigo: '', + novo: tombo.nome_cientifico, + }); + parametros.push({ + key: '19', + campo: 'Cor', + antigo: '', + novo: tombo.cor, + }); + if (tombo.variedade) { + parametros.push({ + key: '20', + campo: 'Variedade', + antigo: '', + novo: tombo.variedade.nome, + }); + } + if (tombo.tipo) { + parametros.push({ + key: '21', + campo: 'Tipo', + antigo: '', + novo: tombo.tipo.nome, + }); + } + if (tombo.especy) { + parametros.push({ + key: '22', + campo: 'Espécie', + antigo: '', + novo: tombo.especy.nome, + }); + } + if (tombo.genero) { + parametros.push({ + key: '23', + campo: 'Genero', + antigo: '', + novo: tombo.genero.nome, + }); + } + if (tombo.familia) { + parametros.push({ + key: '24', + campo: 'Família', + antigo: '', + novo: tombo.familia.nome, + }); + } + if (tombo.sub_familia) { + parametros.push({ + key: '25', + campo: 'Subfamília', + antigo: '', + novo: tombo.sub_familia.nome, + }); + } + if (tombo.sub_especy) { + parametros.push({ + key: '26', + campo: 'Subespécie', + antigo: '', + novo: tombo.sub_especy.nome, + }); + } + if (tombo.colecoes_anexa) { + parametros.push({ + key: '27', + campo: 'Observações - Coleção Anexa', + antigo: '', + novo: tombo.colecoes_anexa.observacoes, + }); + } + if (tombo.colecoes_anexa) { + parametros.push({ + key: '28', + campo: 'Tipo - Coleção Anexa', + antigo: '', + novo: tombo.colecoes_anexa.tipo, + }); + } + return parametros; +}; + +export const visualizarComCadastro = (alteracao, transaction) => { + let parametros = {}; + + return new Promise((resolve, reject) => { + + parametros = { + ...parametros, + numero_tombo: alteracao.tombo_hcf, + numero_tombo_alteracao: JSON.parse(alteracao.tombo_json).hcf, + }; + Tombo.findAll({ + where: { + hcf: { + [Op.in]: [alteracao.tombo_hcf, parametros.numero_tombo_alteracao], + }, + ativo: true, + }, + include: [ + { + model: Herbario, + }, + { + model: Variedade, + }, + { + model: Tipo, + }, + { + model: Especie, + }, + { + model: Familia, + }, + { + model: Subfamilia, + }, + { + model: Genero, + }, + { + model: Subespecie, + }, + { + model: ColecaoAnexa, + }, + { + model: LocalColeta, + include: [ + { + model: Solo, + }, + { + model: Relevo, + }, + { + model: Vegetacao, + }, + { + model: Cidade, + }, + { + model: FaseSucessional, + }, + ], + }, + ], + transaction, + }) + .then(tombos => { + parametros = { + ...parametros, + retorno: [], + }; + if (tombos.length === 2) { + if (tombos[0].hcf === parametros.numero_tombo) { + parametros = { + ...parametros, + tombo: tombos[0], + tombo_alterado: tombos[1], + }; + } else { + parametros = { + ...parametros, + tombo: tombos[1], + tombo_alterado: tombos[0], + }; + } + parametros = comparaDoisTombos(parametros.tombo, parametros.tombo_alterado); + } else { + parametros = formatarTomboNovo(tombos[0]); + } + resolve(parametros); + }) + .catch(reject); + }); +}; + +const insereNoParametro = (key, campo, antigo, novo) => ({ + key, campo, antigo, novo, +}); + +const comparaDoisTombosOperador = (tombo, tomboAlterado) => { + const parametros = []; + // / colecoes anexas + if (tomboAlterado.colecoes_anexas) { + if (tombo.colecoes_anexa) { + if (tombo.colecoes_anexa.tipo !== tomboAlterado.colecoes_anexas.tipo) { + parametros.push(insereNoParametro('1', 'Coleções anexas tipo', tombo.colecoes_anexa.tipo, tomboAlterado.colecoes_anexas.tipo)); + } + if (tombo.colecoes_anexa.observacoes !== tomboAlterado.colecoes_anexas.observacoes) { + // eslint-disable-next-line + parametros.push( + insereNoParametro( + '2', + 'Coleções anexas observacoes', + tombo.colecoes_anexa.observacoes, + tomboAlterado.colecoes_anexas.observacoes + ) + ); + } + } else { + if (tomboAlterado.colecoes_anexas.tipo) { + parametros.push(insereNoParametro('1', 'Coleções anexas tipo', '', tomboAlterado.colecoes_anexas.tipo)); + } + if (tomboAlterado.colecoes_anexas.observacoes) { + parametros.push(insereNoParametro('2', 'Coleções anexas observacoes', '', tomboAlterado.colecoes_anexas.observacoes)); + } + } + } + // / coletores + let coletorPrincipalOrig = {}; + let coletoresOrig = ''; + let coletoresAlt = ''; + let novo = ''; + let antigo = ''; + + if (tomboAlterado.coletores) { + const colAlt = tomboAlterado.coletores; + for (let i = 0; i < colAlt.length; i++) { // eslint-disable-line + coletoresAlt += ` ${colAlt[i].nome} `; + } + novo = coletoresAlt; + } + if (tombo.coletores) { + const colOrig = tombo.coletores; + for (let i = 0; i < colOrig.length; i++) { // eslint-disable-line + if (colOrig[i].tombos_coletores.principal) { + coletorPrincipalOrig = { + id: colOrig[i].id, + nome: colOrig[i].nome, + }; + } else { + coletoresOrig += ` ${colOrig[i].nome} `; + } + } + antigo = coletoresOrig; + } + parametros.push(insereNoParametro('3', 'Coletores', antigo, novo)); + if (coletorPrincipalOrig.id) { + if (tomboAlterado.coletor_principal.id) { + if (coletorPrincipalOrig.id !== tomboAlterado.coletor_principal.id) { + parametros.push(insereNoParametro('4', 'Coletor principal', coletorPrincipalOrig.nome, tomboAlterado.coletor_principal.nome)); + } + } + } else if (tomboAlterado.coletor_principal.id) { + parametros.push(insereNoParametro('4', 'Coletor principal', '', tomboAlterado.coletor_principal.nome)); + } + // /////local de coleta + if (tomboAlterado.localidade) { + if (tomboAlterado.localidade.altitude) { + if (tombo.altitude) { + if (tombo.altitude !== tomboAlterado.localidade.altitude) { + parametros.push(insereNoParametro('5', 'Altitude', tombo.altitude, tomboAlterado.localidade.altitude)); + } + } else { + parametros.push(insereNoParametro('5', 'Altitude', '', tomboAlterado.localidade.altitude)); + } + } + if (tomboAlterado.localidade.cidade) { + if (tomboAlterado.localidade.cidade.id) { + if (tombo.locais_coletum && tombo.locais_coletum.cidade) { + if (tombo.locais_coletum.cidade.id !== tomboAlterado.localidade.cidade.id) { + parametros.push(insereNoParametro('6', 'Cidade', tombo.locais_coletum.cidade.nome, tomboAlterado.localidade.cidade.nome)); + } + } else { + parametros.push(insereNoParametro('6', 'Cidade', '', tomboAlterado.localidade.cidade.nome)); + } + } + } + if (tomboAlterado.localidade.latitude) { + if (tombo.latitude) { + if (converteParaDecimal(tomboAlterado.localidade.latitude) !== tombo.latitude) { + parametros.push(insereNoParametro('7', 'Latitude', tombo.latitude, tomboAlterado.localidade.latitude)); + } + } else { + parametros.push(insereNoParametro('7', 'Latitude', '', tomboAlterado.localidade.latitude)); + } + } + if (tomboAlterado.localidade.longitude) { + if (tombo.longitude) { + if (converteParaDecimal(tomboAlterado.localidade.longitude) !== tombo.longitude) { + parametros.push(insereNoParametro('8', 'Longitude', tombo.longitude, tomboAlterado.localidade.longitude)); + } + } else { + parametros.push(insereNoParametro('8', 'Longitude', '', tomboAlterado.localidade.longitude)); + } + } + } + + if (tomboAlterado.observacoes) { + if (tombo.observacoes) { + parametros.push(insereNoParametro('9', 'Observações', tombo.observacoes, tomboAlterado.observacoes)); + } else { + parametros.push(insereNoParametro('9', 'Observações', '', tomboAlterado.observacoes)); + } + } + + if (tomboAlterado.paisagem) { + const { + descricao, fase_sucessional: faseSucessional, relevo, solo, vegetacao, + } = tomboAlterado.paisagem; + if (descricao) { + if (tombo.locais_coletum && tombo.locais_coletum.descricao) { + if (descricao !== tombo.locais_coletum.descricao) { + parametros.push(insereNoParametro('10', 'Descrição do local de coleta', tombo.locais_coletum.descricao, descricao)); + } + } else { + parametros.push(insereNoParametro('10', 'Descrição do local de coleta', '', descricao)); + } + } + if (faseSucessional) { + if (tombo.locais_coletum && tombo.locais_coletum.fase_sucessional) { + if (tombo.locais_coletum.fase_sucessional.nome !== faseSucessional.nome) { + parametros.push(insereNoParametro('11', 'Fase sucessional', tombo.locais_coletum.nome, faseSucessional.nome)); + } + } else { + parametros.push(insereNoParametro('11', 'Fase sucessional', '', faseSucessional.nome)); + } + } + if (relevo) { + if (tombo.locais_coletum && tombo.locais_coletum.relevo) { + if (tombo.locais_coletum.relevo.nome !== relevo.nome) { + parametros.push(insereNoParametro('12', 'Relevo', tombo.locais_coletum.relevo.nome, relevo.nome)); + } + } else { + parametros.push(insereNoParametro('12', 'Relevo', '', relevo.nome)); + } + } + if (solo) { + if (tombo.locais_coletum && tombo.locais_coletum.solo) { + if (tombo.locais_coletum.solo.nome !== solo.nome) { + parametros.push(insereNoParametro('13', 'Solo', tombo.locais_coletum.solo.nome, solo.nome)); + } + } else { + parametros.push(insereNoParametro('13', 'Solo', '', solo.nome)); + } + } + if (vegetacao) { + if (tombo.locais_coletum && tombo.locais_coletum.vegetaco) { + if (tombo.locais_coletum.vegetaco.nome !== solo.nome) { + parametros.push(insereNoParametro('14', 'Vegetação', tombo.locais_coletum.vegetaco.nome, vegetacao.nome)); + } + } else { + parametros.push(insereNoParametro('14', 'Vegetação', '', vegetacao.nome)); + } + } + } + + if (tomboAlterado.principal) { + const { + cor, data_coleta: dataColeta, entidade, + nome_popular: nomePopular, numero_coleta: numColeta, tipo, + } = tomboAlterado.principal; + + if (cor) { + if (tombo.cor !== cor) { + parametros.push(insereNoParametro('15', 'Cor', '', tombo.cor)); + } + } + if (dataColeta) { + if (dataColeta.dia) { + if (tombo.data_coleta_dia) { + if (dataColeta.dia !== tombo.data_coleta_dia) { + parametros.push(insereNoParametro('16', 'Data coleta dia', tombo.data_coleta_dia, dataColeta.dia)); + } + } else { + parametros.push(insereNoParametro('16', 'Data coleta dia', '', dataColeta.dia)); + } + } + if (dataColeta.mes) { + if (tombo.data_coleta_mes) { + if (dataColeta.mes !== tombo.data_coleta_mes) { + parametros.push(insereNoParametro('17', 'Data coleta mes', tombo.data_coleta_mes, dataColeta.mes)); + } + } else { + parametros.push(insereNoParametro('17', 'Data coleta mes', '', dataColeta.mes)); + } + } + if (dataColeta.ano) { + if (tombo.data_coleta_ano) { + if (dataColeta.ano !== tombo.data_coleta_ano) { + parametros.push(insereNoParametro('18', 'Data coleta ano', tombo.data_coleta_ano, dataColeta.ano)); + } + } else { + parametros.push(insereNoParametro('18', 'Data coleta ano', '', dataColeta.ano)); + } + } + } + + if (entidade) { + if (tombo.herbario) { + if (entidade.id !== tombo.herbario.id) { + parametros.push(insereNoParametro('19', 'Herbário', tombo.herbario.nome, entidade.nome)); + } + } else { + parametros.push(insereNoParametro('19', 'Herbário', '', entidade.nome)); + } + } + + if (nomePopular) { + if (tombo.nome_populares) { + if (nomePopular !== tombo.nome_populares) { + parametros.push(insereNoParametro('20', 'Nomes populares', tombo.nome_populares, nomePopular)); + } + } else { + parametros.push(insereNoParametro('20', 'Nomes populares', '', nomePopular)); + } + } + + if (numColeta) { + if (tombo.numero_coleta) { + if (numColeta !== tombo.numero_coleta) { + parametros.push(insereNoParametro('21', 'Numero de coleta', numColeta, tombo.numero_coleta)); + } + } else { + parametros.push(insereNoParametro('21', 'Numero de coleta', '', tombo.numero_coleta)); + } + } + + if (tipo) { + if (tombo.tipo) { + if (tipo.id !== tombo.tipo.id) { + parametros.push(insereNoParametro('22', 'Tipo', tombo.tipo.nome, tipo.nome)); + } + } else { + parametros.push(insereNoParametro('22', 'Tipo', '', tipo.nome)); + } + } + } + + if (tomboAlterado.taxonomia) { + const { + especie, familia, genero, sub_especie: subEspecie, sub_familia: subFamilia, variedade, + } = tomboAlterado.taxonomia; + + if (especie) { + if (tombo.especy) { + if (especie.nome !== tombo.especy.nome) { + parametros.push(insereNoParametro('23', 'Especie', especie, tombo.especy.nome)); + } + } else { + parametros.push(insereNoParametro('23', 'Especie', '', especie.nome)); + } + } + + if (familia) { + if (tombo.familia) { + if (familia.nome !== tombo.familia.nome) { + parametros.push(insereNoParametro('24', 'Familia', familia, tombo.familia.nome)); + } + } else { + parametros.push(insereNoParametro('24', 'Familia', '', familia.nome)); + } + } + + if (genero) { + if (tombo.genero) { + if (genero.nome !== tombo.genero.nome) { + parametros.push(insereNoParametro('25', 'Genero', genero, tombo.genero.nome)); + } + } else { + parametros.push(insereNoParametro('25', 'Genero', '', genero.nome)); + } + } + + if (subEspecie) { + if (tombo.sub_especy) { + if (subEspecie.nome !== tombo.sub_especy) { + parametros.push(insereNoParametro('26', 'Subespecie', subEspecie, tombo.sub_especy.nome)); + } + } else { + parametros.push(insereNoParametro('26', 'Subespecie', '', subEspecie.nome)); + } + } + + if (subFamilia) { + if (tombo.sub_familia) { + if (subFamilia.nome !== tombo.sub_familia) { + parametros.push(insereNoParametro('27', 'Subfamilia', subFamilia, tombo.sub_familia.nome)); + } + } else { + parametros.push(insereNoParametro('27', 'Subfamilia', '', subFamilia.nome)); + } + } + + if (variedade) { + if (tombo.variedade) { + if (variedade.nome !== tombo.variedade) { + parametros.push(insereNoParametro('28', 'Variedade', variedade, tombo.variedade.nome)); + } + } else { + parametros.push(insereNoParametro('28', 'Variedade', '', variedade.nome)); + } + } + } + return parametros; + +}; + +export const visualizarAlteracaoOperador = (json, alteracao, transaction) => { + let parametros = {}; + + return new Promise((resolve, reject) => { + + parametros = { + ...parametros, + numero_tombo: alteracao.tombo_hcf, + }; + Tombo.findAll({ + where: { + hcf: alteracao.tombo_hcf, + ativo: true, + }, + include: [ + { + model: Coletor, + }, + { + model: Herbario, + }, + { + model: Variedade, + }, + { + model: Tipo, + }, + { + model: Especie, + }, + { + model: Familia, + }, + { + model: Subfamilia, + }, + { + model: Genero, + }, + { + model: Subespecie, + }, + { + model: ColecaoAnexa, + }, + { + model: LocalColeta, + include: [ + { + model: Solo, + }, + { + model: Relevo, + }, + { + model: Vegetacao, + }, + { + model: Cidade, + }, + { + model: FaseSucessional, + }, + ], + }, + ], + transaction, + }) + .then(tombo => { + parametros = { + ...parametros, + tombo_original: tombo, + }; + const visualizacaoFormatada = comparaDoisTombosOperador(tombo, json); + parametros = { + ...parametros, + retorno: visualizacaoFormatada, + }; + resolve(visualizacaoFormatada); + }) + .catch(reject); + }); +}; + +export const aprovarPendencia = async (alteracao, hcf, transaction) => { + if (!alteracao || !hcf) { + throw new BadRequestExeption(404); + } + + const tomboAtual = await Tombo.findOne({ + where: { hcf, ativo: true }, + transaction, + raw: true, + nest: true, + }); + + if (!tomboAtual) { + throw new BadRequestExeption(404); + } + + const updateTombo = {}; + const nomesCientificosPartes = []; + + if (alteracao.nomes_populares !== undefined) { + updateTombo.nomes_populares = alteracao.nomes_populares; + } + + if (alteracao.unicata !== undefined) { + updateTombo.unicata = alteracao.unicata; + } + + if (alteracao.numero_coleta !== undefined) { + updateTombo.numero_coleta = alteracao.numero_coleta; + } + + if (alteracao.observacao !== undefined) { + updateTombo.observacao = alteracao.observacao; + } + + if (alteracao.cor !== undefined) { + updateTombo.cor = alteracao.cor ? alteracao.cor.toUpperCase() : null; + } + + if (alteracao.data_tombo !== undefined) { + updateTombo.data_tombo = alteracao.data_tombo; + } + + if (alteracao.data_coleta_dia !== undefined) { + updateTombo.data_coleta_dia = alteracao.data_coleta_dia; + } + + if (alteracao.data_coleta_mes !== undefined) { + updateTombo.data_coleta_mes = alteracao.data_coleta_mes; + } + + if (alteracao.data_coleta_ano !== undefined) { + updateTombo.data_coleta_ano = alteracao.data_coleta_ano; + } + + if (alteracao.data_identificacao_dia !== undefined) { + updateTombo.data_identificacao_dia = alteracao.data_identificacao_dia; + } + + if (alteracao.data_identificacao_mes !== undefined) { + updateTombo.data_identificacao_mes = alteracao.data_identificacao_mes; + } + + if (alteracao.data_identificacao_ano !== undefined) { + updateTombo.data_identificacao_ano = alteracao.data_identificacao_ano; + } + + if (alteracao.latitude !== undefined) { + let latitudeValue = null; + if (alteracao.latitude !== null) { + if (typeof alteracao.latitude === 'string') { + latitudeValue = converteParaDecimal(alteracao.latitude); + } else { + latitudeValue = alteracao.latitude; + } + } + updateTombo.latitude = latitudeValue; + } + + if (alteracao.longitude !== undefined) { + let longitudeValue = null; + if (alteracao.longitude !== null) { + if (typeof alteracao.longitude === 'string') { + longitudeValue = converteParaDecimal(alteracao.longitude); + } else { + longitudeValue = alteracao.longitude; + } + } + updateTombo.longitude = longitudeValue; + } + + if (alteracao.altitude !== undefined) { + updateTombo.altitude = alteracao.altitude; + } + + if (alteracao.entidade_id !== undefined) { + if (alteracao.entidade_id !== null) { + const herbario = await Herbario.findOne({ + where: { id: alteracao.entidade_id }, + transaction, + raw: true, + nest: true, + }); + + if (!herbario) { + throw new BadRequestExeption(404); + } + } + updateTombo.entidade_id = alteracao.entidade_id; + } + + if (alteracao.tipo_id !== undefined) { + if (alteracao.tipo_id !== null) { + const tipo = await Tipo.findOne({ + where: { id: alteracao.tipo_id }, + transaction, + raw: true, + nest: true, + }); + + if (!tipo) { + throw new BadRequestExeption(404); + } + } + updateTombo.tipo_id = alteracao.tipo_id; + } + + if (alteracao.familia_id !== undefined) { + if (alteracao.familia_id !== null) { + const familia = await Familia.findOne({ + where: { id: alteracao.familia_id }, + transaction, + raw: true, + nest: true, + }); + + if (!familia) { + throw new BadRequestExeption(404); + } + } + + updateTombo.familia_id = alteracao.familia_id; + + if (alteracao.familia_id === null) { + updateTombo.sub_familia_id = null; + updateTombo.genero_id = null; + updateTombo.especie_id = null; + updateTombo.sub_especie_id = null; + updateTombo.variedade_id = null; + } + } + + if (alteracao.sub_familia_id !== undefined) { + if (alteracao.sub_familia_id !== null) { + const subfamilia = await Subfamilia.findOne({ + where: { + id: alteracao.sub_familia_id, + familia_id: updateTombo.familia_id || tomboAtual.familia_id, + }, + transaction, + raw: true, + nest: true, + }); + + if (!subfamilia) { + throw new BadRequestExeption(404); + } + } + + updateTombo.sub_familia_id = alteracao.sub_familia_id; + + if (alteracao.sub_familia_id === null) { + updateTombo.genero_id = null; + updateTombo.especie_id = null; + updateTombo.sub_especie_id = null; + updateTombo.variedade_id = null; + } + } + + if (alteracao.genero_id !== undefined) { + if (alteracao.genero_id !== null) { + const genero = await Genero.findOne({ + where: { + id: alteracao.genero_id, + familia_id: updateTombo.familia_id || tomboAtual.familia_id, + }, + transaction, + raw: true, + nest: true, + }); + + if (!genero) { + throw new BadRequestExeption(404); + } + nomesCientificosPartes.push(genero.nome); + } + + updateTombo.genero_id = alteracao.genero_id; + + if (alteracao.genero_id === null) { + updateTombo.especie_id = null; + updateTombo.sub_especie_id = null; + updateTombo.variedade_id = null; + } + } + + if (alteracao.especie_id !== undefined) { + if (alteracao.especie_id !== null) { + const especie = await Especie.findOne({ + where: { + id: alteracao.especie_id, + genero_id: updateTombo.genero_id || tomboAtual.genero_id, + }, + transaction, + raw: true, + nest: true, + }); + + if (!especie) { + throw new BadRequestExeption(404); + } + nomesCientificosPartes.push(especie.nome); + } + + updateTombo.especie_id = alteracao.especie_id; + + if (alteracao.especie_id === null) { + updateTombo.sub_especie_id = null; + updateTombo.variedade_id = null; + } + } + + if (alteracao.sub_especie_id !== undefined) { + if (alteracao.sub_especie_id !== null) { + const subespecie = await Subespecie.findOne({ + where: { + id: alteracao.sub_especie_id, + especie_id: updateTombo.especie_id || tomboAtual.especie_id, + }, + transaction, + raw: true, + nest: true, + }); + + if (!subespecie) { + throw new BadRequestExeption(404); + } + } + + updateTombo.sub_especie_id = alteracao.sub_especie_id; + + if (alteracao.sub_especie_id === null) { + updateTombo.variedade_id = null; + } + } + + if (alteracao.variedade_id !== undefined) { + if (alteracao.variedade_id !== null) { + const variedade = await Variedade.findOne({ + where: { + id: alteracao.variedade_id, + especie_id: updateTombo.especie_id || tomboAtual.especie_id, + }, + transaction, + raw: true, + nest: true, + }); + + if (!variedade) { + throw new BadRequestExeption(404); + } + } + + updateTombo.variedade_id = alteracao.variedade_id; + } + + if (nomesCientificosPartes.length > 0) { + updateTombo.nome_cientifico = nomesCientificosPartes.join(' '); + } else if (Object.keys(updateTombo).some(key => key.includes('genero_id') || key.includes('especie_id'))) { + updateTombo.nome_cientifico = null; + } + + if (alteracao.local_coleta_id !== undefined) { + if (alteracao.local_coleta_id !== null) { + const localColeta = await LocalColeta.findOne({ + where: { id: alteracao.local_coleta_id }, + transaction, + raw: true, + nest: true, + }); + + if (!localColeta) { + throw new BadRequestExeption(404); + } + } + updateTombo.local_coleta_id = alteracao.local_coleta_id; + } + + if (alteracao.descricao !== undefined) { + updateTombo.descricao = alteracao.descricao; + } + + if (alteracao.solo_id !== undefined) { + if (alteracao.solo_id !== null) { + const solo = await Solo.findOne({ + where: { id: alteracao.solo_id }, + transaction, + raw: true, + nest: true, + }); + + if (!solo) { + throw new BadRequestExeption(404); + } + } + updateTombo.solo_id = alteracao.solo_id; + } + + if (alteracao.relevo_id !== undefined) { + if (alteracao.relevo_id !== null) { + const relevo = await Relevo.findOne({ + where: { id: alteracao.relevo_id }, + transaction, + raw: true, + nest: true, + }); + + if (!relevo) { + throw new BadRequestExeption(404); + } + } + updateTombo.relevo_id = alteracao.relevo_id; + } + + if (alteracao.vegetacao_id !== undefined) { + if (alteracao.vegetacao_id !== null) { + const vegetacao = await Vegetacao.findOne({ + where: { id: alteracao.vegetacao_id }, + transaction, + raw: true, + nest: true, + }); + + if (!vegetacao) { + throw new BadRequestExeption(404); + } + } + updateTombo.vegetacao_id = alteracao.vegetacao_id; + } + + if (alteracao.coletor_id !== undefined) { + if (alteracao.coletor_id !== null) { + const coletor = await Coletor.findOne({ + where: { id: alteracao.coletor_id }, + transaction, + raw: true, + nest: true, + }); + + if (!coletor) { + throw new BadRequestExeption(404); + } + + } + updateTombo.coletor_id = alteracao.coletor_id; + } + + updateTombo.rascunho = false; + + if (Object.keys(updateTombo).length > 0) { + await Tombo.update(updateTombo, { + where: { hcf }, + transaction, + }); + } + + if (alteracao.identificadores !== undefined) { + await TomboIdentificador.destroy({ + where: { tombo_hcf: hcf }, + transaction, + }); + + if (Array.isArray(alteracao.identificadores) && alteracao.identificadores.length > 0) { + const identificadoresPromises = alteracao.identificadores.map(async (identificadorId, index) => { + const identificador = await Identificador.findOne({ + where: { id: identificadorId }, + transaction, + raw: true, + nest: true, + }); + + if (!identificador) { + throw new BadRequestExeption(404); + } + + return TomboIdentificador.create({ + tombo_hcf: hcf, + identificador_id: identificadorId, + ordem: index + 1, + }, { transaction }); + }); + + await Promise.all(identificadoresPromises); + } + } + + if (alteracao.complementares !== undefined) { + await ColetorComplementar.destroy({ + where: { hcf }, + transaction, + }); + + if (alteracao.complementares) { + await ColetorComplementar.create({ + hcf, + complementares: alteracao.complementares, + }, { transaction }); + } + } + + if (alteracao.colecoes_anexas_tipo !== undefined || alteracao.colecoes_anexas_observacoes !== undefined) { + const tomboAtualizado = await Tombo.findOne({ + where: { hcf }, + transaction, + raw: true, + nest: true, + }); + + if (tomboAtualizado.colecao_anexa_id) { + const updateColecao = {}; + + if (alteracao.colecoes_anexas_tipo !== undefined) { + updateColecao.tipo = alteracao.colecoes_anexas_tipo; + } + + if (alteracao.colecoes_anexas_observacoes !== undefined) { + updateColecao.observacoes = alteracao.colecoes_anexas_observacoes; + } + + if (Object.keys(updateColecao).length > 0) { + await ColecaoAnexa.update(updateColecao, { + where: { id: tomboAtualizado.colecao_anexa_id }, + transaction, + }); + } + } else if (alteracao.colecoes_anexas_tipo || alteracao.colecoes_anexas_observacoes) { + const novaColecao = await ColecaoAnexa.create({ + tipo: alteracao.colecoes_anexas_tipo, + observacoes: alteracao.colecoes_anexas_observacoes, + }, { transaction }); + + await Tombo.update({ + colecao_anexa_id: novaColecao.id, + }, { + where: { hcf }, + transaction, + }); + } + } + + const tomboFinal = await Tombo.findOne({ + where: { hcf, ativo: true }, + transaction, + raw: true, + nest: true, + }); + + return { + success: true, + message: 'Pendência aprovada com sucesso', + tombo: tomboFinal, + }; +}; + +export const visualizarComJsonNome = (alteracao, hcf, transaction) => new Promise((resolve, reject) => { + Tombo.findOne({ + where: { + hcf, + }, + include: [ + { + model: Variedade, + }, + { + model: Especie, + }, + { + model: Familia, + }, + { + model: Subfamilia, + }, + { + model: Genero, + }, + { + model: Subespecie, + }, + ], + transaction, + }) + .then(tombos => { + // eslint-disable-next-line + var jsonRetorno = []; + if (tombos.especy) { + if (alteracao.especie_nome) { + if (tombos.especy.nome !== alteracao.especie_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '1', + campo: 'Especie', + antigo: tombos.especy.nome, + novo: alteracao.especie_nome, + }); + } + } + } else if (alteracao.especie_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '1', + campo: 'Especie', + antigo: '', + novo: alteracao.especie_nome, + }); + } + if (tombos.familia) { + if (alteracao.familia_nome) { + if (tombos.familia.nome !== alteracao.familia_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '2', + campo: 'Familia', + antigo: tombos.familia.nome, + novo: alteracao.familia_nome, + }); + } + } + } else if (alteracao.familia_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '2', + campo: 'Familia', + antigo: '', + novo: alteracao.familia_nome, + }); + } + if (tombos.genero) { + if (alteracao.genero_nome) { + if (tombos.genero.nome !== alteracao.genero_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '3', + campo: 'Gênero', + antigo: tombos.genero.nome, + novo: alteracao.genero_nome, + }); + } + } + } else if (alteracao.genero_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '3', + campo: 'Gênero', + antigo: '', + novo: alteracao.genero_nome, + }); + } + if (tombos.variedade) { + if (alteracao.variedade_nome) { + if (tombos.variedade.nome !== alteracao.variedade_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '4', + campo: 'Variedade', + antigo: tombos.variedade.nome, + novo: alteracao.variedade_nome, + }); + } + } + } else if (alteracao.variedade_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '4', + campo: 'Variedade', + antigo: '', + novo: alteracao.variedade_nome, + }); + } + if (tombos.sub_especy) { + if (alteracao.subespecie_nome) { + if (tombos.sub_especy.nome !== alteracao.subespecie_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '5', + campo: 'Subespecie', + antigo: tombos.sub_especy.nome, + novo: alteracao.subespecie_nome, + }); + } + } + } else if (alteracao.subespecie_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '5', + campo: 'Subespecie', + antigo: '', + novo: alteracao.subespecie_nome, + }); + } + if (tombos.sub_familia || tombos.rascunho) { + if (alteracao.subfamilia_nome) { + if (tombos.sub_familia.nome !== alteracao.subfamilia_nome) { + jsonRetorno.push({ + key: '6', + campo: 'Subfamilia', + antigo: tombos.sub_familia.nome, + novo: alteracao.subfamilia_nome, + }); + } + } + } else if (alteracao.subfamilia_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '6', + campo: 'Subfamilia', + antigo: '', + novo: alteracao.subfamilia_nome, + }); + } + resolve(jsonRetorno); + }) + .catch(reject); +}); + +export async function visualizar(request, response, next) { + try { + const id = request.params.pendencia_id; + const alteracao = await Alteracao.findOne({ + where: { ativo: true, id }, + }); + + if (!alteracao) { + throw new BadRequestExeption(800); + } + + const objetoAlterado = JSON.parse(alteracao.tombo_json); + const parametros = {}; + const alteracaoAprovada = alteracao.status === 'APROVADO'; + + if (objetoAlterado.nomes_populares !== undefined) { + parametros.nome_popular = objetoAlterado.nomes_populares; + } + + if (objetoAlterado.numero_coleta !== undefined) { + parametros.numero_coleta = objetoAlterado.numero_coleta; + } + + if (objetoAlterado.data_coleta_dia !== undefined) { + parametros.data_coleta_dia = objetoAlterado.data_coleta_dia; + } + + if (objetoAlterado.data_coleta_mes !== undefined) { + parametros.data_coleta_mes = objetoAlterado.data_coleta_mes; + } + + if (objetoAlterado.data_coleta_ano !== undefined) { + parametros.data_coleta_ano = objetoAlterado.data_coleta_ano; + } + + if (objetoAlterado.cor !== undefined) { + parametros.cor = objetoAlterado.cor; + } + + if (objetoAlterado.altitude !== undefined) { + parametros.altitude = objetoAlterado.altitude; + } + + if (objetoAlterado.local_coleta_id !== undefined) { + parametros.localColeta = await LocalColeta.findOne({ where: { id: objetoAlterado.local_coleta_id }, raw: true, nest: true }); + } + + if (objetoAlterado.descricao !== undefined) { + parametros.descricao = objetoAlterado.descricao; + } + + if (objetoAlterado.data_identificacao_dia !== undefined) { + parametros.data_identificacao_dia = objetoAlterado.data_identificacao_dia; + } + + if (objetoAlterado.data_identificacao_mes !== undefined) { + parametros.data_identificacao_mes = objetoAlterado.data_identificacao_mes; + } + + if (objetoAlterado.data_identificacao_ano !== undefined) { + parametros.data_identificacao_ano = objetoAlterado.data_identificacao_ano; + } + + if (objetoAlterado.colecoes_anexas_observacoes !== undefined) { + parametros.colecoes_anexas_observacoes = objetoAlterado.colecoes_anexas_observacoes; + } + + if (objetoAlterado.observacao !== undefined) { + parametros.observacoes = objetoAlterado.observacao; + } + + if (objetoAlterado.unicata !== undefined) { + parametros.unicata = objetoAlterado.unicata; + } + + if (objetoAlterado.latitude !== undefined) { + parametros.latitude = objetoAlterado.latitude; + } + + if (objetoAlterado.longitude !== undefined) { + parametros.longitude = objetoAlterado.longitude; + } + + if (objetoAlterado.coletor_id !== undefined) { + parametros.coletor = await Coletor.findOne({ where: { id: objetoAlterado.coletor_id }, raw: true, nest: true }); + } + + if (objetoAlterado.complementares !== undefined) { + parametros.complementares = objetoAlterado.complementares; + } + + if (objetoAlterado.familia_id !== undefined) { + parametros.familia = await Familia.findOne({ where: { id: objetoAlterado.familia_id }, raw: true, nest: true }); + } + + if (objetoAlterado.subfamilia_id !== undefined) { + parametros.subfamilia = await Subfamilia.findOne({ where: { id: objetoAlterado.subfamilia_id }, raw: true, nest: true }); + } + + if (objetoAlterado.genero_id !== undefined) { + parametros.genero = await Genero.findOne({ where: { id: objetoAlterado.genero_id }, raw: true, nest: true }); + } + + if (objetoAlterado.especie_id !== undefined) { + parametros.especie = await Especie.findOne({ where: { id: objetoAlterado.especie_id }, raw: true, nest: true }); + } + + if (objetoAlterado.identificadores !== undefined) { + const idsIdent = Array.isArray(objetoAlterado.identificadores) + ? objetoAlterado.identificadores + : [objetoAlterado.identificadores]; + parametros.identificadores = await Identificador.findAll({ + where: { id: { [Op.in]: idsIdent } }, + raw: true, + nest: true, + }); + } + + if (objetoAlterado.fase_sucessional_id !== undefined) { + parametros.faseSucessional = await FaseSucessional.findOne({ where: { numero: objetoAlterado.fase_sucessional_id }, raw: true, nest: true }); + } + + if (objetoAlterado.vegetacao_id !== undefined) { + parametros.vegetacao = await Vegetacao.findOne({ where: { id: objetoAlterado.vegetacao_id }, raw: true, nest: true }); + } + + if (objetoAlterado.relevo_id !== undefined) { + parametros.relevo = await Relevo.findOne({ where: { id: objetoAlterado.relevo_id }, raw: true, nest: true }); + } + + if (objetoAlterado.solo_id !== undefined) { + parametros.solo = await Solo.findOne({ where: { id: objetoAlterado.solo_id }, raw: true, nest: true }); + } + + if (objetoAlterado.cidade_id !== undefined) { + parametros.cidade = await Cidade.findOne({ where: { id: objetoAlterado.cidade_id }, raw: true, nest: true }); + } + + if (objetoAlterado.tipo_id !== undefined) { + parametros.tipo = await Tipo.findOne({ where: { id: objetoAlterado.tipo_id }, raw: true, nest: true }); + } + + if (objetoAlterado.entidade_id !== undefined) { + parametros.entidade = await Herbario.findOne({ where: { id: objetoAlterado.entidade_id }, raw: true, nest: true }); + } + + if (objetoAlterado.variedade_id !== undefined) { + parametros.variedade = await Variedade.findOne({ where: { id: objetoAlterado.variedade_id }, raw: true, nest: true }); + } + + if (objetoAlterado.sub_especie_id !== undefined) { + parametros.subespecie = await Subespecie.findOne({ where: { id: objetoAlterado.sub_especie_id }, raw: true, nest: true }); + } + + const tombo = await Tombo.findOne({ + where: { hcf: alteracao.dataValues.tombo_hcf, ativo: true }, + include: [ + { model: Variedade }, { model: Especie }, { model: Familia }, + { model: Subfamilia }, { model: Genero }, { model: Subespecie }, + { model: Herbario }, { model: Tipo }, { model: Coletor }, { model: ColetorComplementar, as: 'coletor_complementar' }, + { model: Solo }, { model: Relevo }, { model: Vegetacao }, { model: ColecaoAnexa }, + { + model: LocalColeta, + as: 'locais_coletum', + include: [{ model: Cidade }, { model: FaseSucessional }], + }, + { model: Usuario }, + ], + raw: true, + nest: true, + }); + + if (!tombo) { + throw new BadRequestExeption(801, 'Tombo não encontrado'); + } + + const jsonRetorno = []; + const ehRascunho = tombo?.rascunho === 1; + + const converteDecimalParaDMS = (decimal, isLatitude = true) => { + if (decimal === null || decimal === undefined || decimal === '') { + return ''; + } + + const abs = Math.abs(decimal); + const graus = Math.floor(abs); + const minutosDecimal = (abs - graus) * 60; + const minutos = Math.floor(minutosDecimal); + const segundos = ((minutosDecimal - minutos) * 60).toFixed(2); + + let hemisferio; + if (isLatitude) { + hemisferio = decimal >= 0 ? 'N' : 'S'; + } else { + hemisferio = decimal >= 0 ? 'E' : 'W'; + } + + return `${graus}° ${minutos}' ${segundos}" ${hemisferio}`; + }; + + const addRetorno = (key, campo, antigo, novo) => { + const antigoStr = String(antigo || '').trim(); + const novoStr = String(novo || '').trim(); + + if (antigoStr === '' && novoStr === '') { + return; + } + if (antigoStr !== novoStr) { + jsonRetorno.push({ key, campo, antigo: antigoStr, novo: novoStr }); + } + }; + + if (parametros.familia !== undefined) { + const nomeFamilia = typeof parametros.familia === 'string' ? parametros.familia : parametros.familia?.nome || ''; + const antigoFamilia = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.familia?.nome || ''); + addRetorno('1', 'Família', antigoFamilia, nomeFamilia); + } + + if (parametros.subfamilia !== undefined) { + const nomeSubfamilia = typeof parametros.subfamilia === 'string' ? parametros.subfamilia : parametros.subfamilia?.nome || ''; + const antigoSubfamilia = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.sub_familia?.nome || ''); + addRetorno('2', 'Subfamília', antigoSubfamilia, nomeSubfamilia); + } + + if (parametros.genero !== undefined) { + const nomeGenero = typeof parametros.genero === 'string' ? parametros.genero : parametros.genero?.nome || ''; + const antigoGenero = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.genero?.nome || ''); + addRetorno('3', 'Gênero', antigoGenero, nomeGenero); + } + + if (parametros.especie !== undefined) { + const nomeEspecie = typeof parametros.especie === 'string' ? parametros.especie : parametros.especie?.nome || ''; + const antigoEspecie = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.especy?.nome || ''); + addRetorno('4', 'Espécie', antigoEspecie, nomeEspecie); + } + + if (parametros.subespecie !== undefined) { + const antigoSubespecie = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.sub_especy?.nome || ''); + addRetorno('5', 'Subespécie', antigoSubespecie, parametros.subespecie?.nome || ''); + } + + if (parametros.variedade !== undefined) { + const antigoVariedade = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.variedade?.nome || ''); + addRetorno('6', 'Variedade', antigoVariedade, parametros.variedade?.nome || ''); + } + + if (parametros.coletor !== undefined) { + const antigoColetor = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.coletore?.nome || ''); + addRetorno('7', 'Coletor', antigoColetor, parametros.coletor?.nome || ''); + } + + if (parametros.complementares !== undefined) { + const complementaresAtuais = tombo?.coletor_complementar?.complementares || ''; + const complementaresNovos = parametros.complementares === null ? '' : parametros.complementares; + const antigoComplementares = (alteracaoAprovada || ehRascunho) ? '' : complementaresAtuais; + addRetorno('8', 'Coletores complementares', antigoComplementares, complementaresNovos); + } + + if (parametros.numero_coleta !== undefined) { + const antigoNumeroColeta = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.numero_coleta || ''); + addRetorno('9', 'Número da coleta', antigoNumeroColeta, parametros.numero_coleta); + } + + if (parametros.data_coleta_dia !== undefined) { + const antigoDataDia = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_coleta_dia || ''); + addRetorno('10', 'Data de coleta dia', antigoDataDia, parametros.data_coleta_dia); + } + + if (parametros.data_coleta_mes !== undefined) { + const antigoDataMes = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_coleta_mes || ''); + addRetorno('11', 'Data de coleta mês', antigoDataMes, parametros.data_coleta_mes); + } + + if (parametros.data_coleta_ano !== undefined) { + const antigoDataAno = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_coleta_ano || ''); + addRetorno('12', 'Data de coleta ano', antigoDataAno, parametros.data_coleta_ano); + } + + if (parametros.cor !== undefined) { + const antigoCor = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.cor || ''); + addRetorno('13', 'Localidade cor', antigoCor, parametros.cor); + } + + if (parametros.nome_popular !== undefined) { + const antigoNomePopular = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.nomes_populares || ''); + addRetorno('14', 'Nome popular', antigoNomePopular, parametros.nome_popular); + } + + if (parametros.entidade !== undefined) { + const antigoHerbario = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.herbario?.nome || ''); + addRetorno('15', 'Herbário', antigoHerbario, parametros.entidade?.nome || ''); + } + + if (parametros.tipo !== undefined) { + const antigoTipo = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.tipo?.nome || ''); + addRetorno('16', 'Tipo', antigoTipo, parametros.tipo?.nome || ''); + } + + if (parametros.latitude !== undefined) { + const antigoLatitude = (alteracaoAprovada || ehRascunho) ? '' : converteDecimalParaDMS(tombo?.latitude, true); + const novoLatitude = converteDecimalParaDMS(parametros.latitude, true); + addRetorno('17', 'Latitude', antigoLatitude, novoLatitude); + } + + if (parametros.longitude !== undefined) { + const antigoLongitude = (alteracaoAprovada || ehRascunho) ? '' : converteDecimalParaDMS(tombo?.longitude, false); + const novoLongitude = converteDecimalParaDMS(parametros.longitude, false); + addRetorno('18', 'Longitude', antigoLongitude, novoLongitude); + } + + if (parametros.altitude !== undefined) { + const antigoAltitude = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.altitude || ''); + addRetorno('19', 'Altitude', antigoAltitude, parametros.altitude); + } + + if (parametros.localColeta !== undefined) { + const antigoLocalColeta = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.locais_coletum?.descricao || ''); + addRetorno('20', 'Local de Coleta', antigoLocalColeta, parametros.localColeta?.descricao || ''); + } + + if (parametros.descricao !== undefined) { + const antigoDescricao = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.descricao || ''); + addRetorno('21', 'Descrição do relevo', antigoDescricao, parametros.descricao); + } + + if (parametros.solo !== undefined) { + const antigoSolo = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.solo?.nome || ''); + addRetorno('22', 'Solo', antigoSolo, parametros.solo?.nome || ''); + } + + if (parametros.relevo !== undefined) { + const antigoRelevo = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.relevo?.nome || ''); + addRetorno('23', 'Relevo', antigoRelevo, parametros.relevo?.nome || ''); + } + + if (parametros.vegetacao !== undefined) { + const antigoVegetacao = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.vegetaco?.nome || ''); + addRetorno('24', 'Vegetação', antigoVegetacao, parametros.vegetacao?.nome || ''); + } + + if (parametros.identificadores !== undefined) { + const identificadoresAtuais = await TomboIdentificador.findAll({ + attributes: ['tombo_hcf', 'identificador_id', 'ordem'], + where: { tombo_hcf: tombo?.hcf }, + include: [{ model: Identificador }], + order: [['ordem', 'ASC']], + raw: true, + nest: true, + }); + + const nomesNovos = parametros.identificadores.map(ident => ident.nome).join(', '); + const nomesAntigos = identificadoresAtuais.map(ident => ident.identificadore?.nome || '').join(', '); + const antigoIdentificadores = (alteracaoAprovada || ehRascunho) ? '' : nomesAntigos; + + addRetorno('25', 'Identificadores', antigoIdentificadores, nomesNovos); + } + + if (parametros.data_identificacao_dia !== undefined) { + const antigoDataIdentDia = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_identificacao_dia || ''); + addRetorno('26', 'Data de identificação dia', antigoDataIdentDia, parametros.data_identificacao_dia); + } + + if (parametros.data_identificacao_mes !== undefined) { + const antigoDataIdentMes = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_identificacao_mes || ''); + addRetorno('27', 'Data de identificação mês', antigoDataIdentMes, parametros.data_identificacao_mes); + } + + if (parametros.data_identificacao_ano !== undefined) { + const antigoDataIdentAno = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_identificacao_ano || ''); + addRetorno('28', 'Data de identificação ano', antigoDataIdentAno, parametros.data_identificacao_ano); + } + + if (objetoAlterado.colecoes_anexas_tipo !== undefined) { + const antigoTipoColecao = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.colecoes_anexa?.tipo || ''); + addRetorno('29', 'Tipo - Coleção Anexa', antigoTipoColecao, objetoAlterado.colecoes_anexas_tipo); + } + + if (parametros.colecoes_anexas_observacoes !== undefined) { + const antigoObsColecao = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.colecoes_anexa?.observacoes || ''); + addRetorno('30', 'Observações - Coleção Anexa', antigoObsColecao, parametros.colecoes_anexas_observacoes); + } + + if (parametros.observacoes !== undefined) { + const antigoObservacoes = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.observacao || ''); + addRetorno('31', 'Observações', antigoObservacoes, parametros.observacoes); + } + + if (parametros.unicata !== undefined) { + let unicataAntigo; + if (alteracaoAprovada || ehRascunho) { + unicataAntigo = ''; + } else { + unicataAntigo = tombo?.unicata ? 'Unicata' : 'Duplicata'; + } + + const unicataNovo = parametros.unicata ? 'Unicata' : 'Duplicata'; + addRetorno('32', 'Tipo de Exsicata', unicataAntigo, unicataNovo); + } + + const jsonRender = { + fotos: { novas: [], antigas: [] }, + status: null, + tabela: jsonRetorno, + }; + + response.status(codigos.LISTAGEM).json(jsonRender); + } catch (error) { + next(error); + } +} + +export function aceitarPendencia(request, response, next) { + const id = request.params.pendencia_id; + const { observacao, status } = request.body; + let retorno = {}; + const callback = transaction => Promise.resolve() + .then(() => Alteracao.update({ + observacao, + status, + }, { + where: { + ativo: true, + id, + }, + transaction, + })) + .then(() => Alteracao.findOne({ + where: { + ativo: true, + id, + }, + transaction, + })) + .then(alt => { + if (status === 'APROVADO') { + const objetoAlterado = JSON.parse(alt.tombo_json); + retorno = aprovarPendencia(objetoAlterado, alt.tombo_hcf, transaction); + } + return retorno; + }); + sequelize.transaction(callback) + .then(() => { + // eslint-disable-next-line no-underscore-dangle + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); + +} + +export function avaliaPendencia(request, response, next) { + const { pendencia_id: pendenciaId } = request.params; + const { observacao, status } = request.body; + + return Promise.resolve() + .then(() => { + Alteracao.update({ + status, + observacao, + }, { + where: { + id: pendenciaId, + }, + }).then(pendencias => { + response.status(codigos.BUSCAR_UM_ITEM) + .json(pendencias); + }); + }) + .catch(next); +} + +export function verificaAlteracao(request, response, next) { + const { tombo_id: tomboId } = request.params; + const callback = transaction => Promise.resolve() + .then(() => Alteracao.findOne({ + where: { + status: 'ESPERANDO', + tombo_hcf: tomboId, + }, + transaction, + })) + .then(retorno => retorno); + sequelize.transaction(callback) + .then(retorno => { + response.status(codigos.BUSCAR_VARIOS_ITENS) + .json(retorno); + + }) + .catch(next); + +} diff --git a/src/controllers/taxonomias-controller.js b/src/controllers/taxonomias-controller.js index 9a01706..b97815f 100644 --- a/src/controllers/taxonomias-controller.js +++ b/src/controllers/taxonomias-controller.js @@ -1,1493 +1,1493 @@ -import BadRequestExeption from '../errors/bad-request-exception'; -import models from '../models'; -import codigos from '../resources/codigos-http'; -import listaTaxonomiasSQL from '../resources/sqls/lista-taxonomias'; -import verifyRecaptcha from '../utils/verify-recaptcha'; - -const { - sequelize, Sequelize: { Op }, Sequelize, Reino, Familia, Genero, Subfamilia, Especie, Variedade, Subespecie, Autor, Tombo, -} = models; -// ////////////////////FAMILIA/////////////////////////// -export const cadastrarFamilia = (request, response, next) => { - const { nome, reinoId } = request.body; - - const callback = transaction => Promise.resolve() - .then(() => Familia.findOne({ - where: { - nome, - ativo: 1, - }, - transaction, - })) - .then(familiaEncontrada => { - if (familiaEncontrada) { - throw new BadRequestExeption(501); - } - }) - .then(() => Familia.create({ nome, reino_id: reinoId }, transaction)); - sequelize.transaction(callback) - .then(familiaCriada => { - console.log(familiaCriada); // eslint-disable-line - if (!familiaCriada) { - throw new BadRequestExeption(502); - } - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; - -export const cadastrarReino = (request, response, next) => { - const { nome } = request.body; - - const callback = transaction => Promise.resolve() - .then(() => Reino.findOne({ - where: { - nome, - }, - transaction, - })) - .then(reinoEncontrado => { - if (reinoEncontrado) { - throw new BadRequestExeption(501); - } - }) - .then(() => Reino.create({ nome }, transaction)); - sequelize.transaction(callback) - .then(reinoCriado => { - console.log(reinoCriado); // eslint-disable-line - if (!reinoCriado) { - throw new BadRequestExeption(502); - } - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; - -export const editarReino = (request, response, next) => { - const id = request.params.reino_id; - const { nome } = request.body; - - const callback = transaction => Promise.resolve() - .then(() => Reino.findOne({ - where: { - id, - }, - transaction, - })) - .then(reinoEncontrado => { - if (!reinoEncontrado) { - throw new BadRequestExeption(516); - } - }) - .then(() => Reino.update({ nome }, { - where: { - id, - }, - transaction, - })); - sequelize.transaction(callback) - .then(reinoEditado => { - console.log(reinoEditado); // eslint-disable-line - if (!reinoEditado) { - throw new BadRequestExeption(502); - } - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; - -export const buscarReinos = async (request, response, next) => { - try { - if (request.query.recaptchaToken) { - await verifyRecaptcha(request); - } - - const { limite, pagina, offset } = request.paginacao; - const { orderClause } = request.ordenacao; - const { reino, reinoId } = request.query; - - let where; - if (reino) { - where = { nome: { [Op.like]: `%${reino}%` } }; - } - if (reinoId) { - where = { ...where, reino_id: reinoId }; - } - - const resultado = await Reino.findAndCountAll({ - attributes: ['id', 'nome'], - order: orderClause, - limit: limite, - offset, - where, - }); - - response.status(codigos.LISTAGEM).json({ - metadados: { - total: resultado.count, - pagina, - limite, - }, - resultado: resultado.rows, - }); - } catch (err) { - next(err); - } - return true; -}; - -export const buscarFamilias = async (request, response, next) => { - try { - if (request.query.recaptchaToken) { - await verifyRecaptcha(request); - } - - const { limite, pagina, offset } = request.paginacao; - const { orderClause } = request.ordenacao; - const { familia, reino_id: reinoId } = request.query; - - const where = { ativo: 1 }; - if (familia) where.nome = { [Op.like]: `%${familia}%` }; - if (reinoId) where.reino_id = reinoId; - - const result = await Familia.findAndCountAll({ - attributes: ['id', 'nome'], - order: orderClause, - limit: limite, - offset, - where, - include: [{ model: Reino, attributes: ['id', 'nome'] }], - }); - - return response.status(codigos.LISTAGEM).json({ - metadados: { total: result.count, pagina, limite }, - resultado: result.rows, - }); - } catch (err) { - next(err); - } - return true; -}; - -export const editarFamilia = (request, response, next) => { - const id = request.params.familia_id; - const { nome } = request.body; - - const callback = transaction => Promise.resolve() - .then(() => Familia.findOne({ - where: { - id, - ativo: 1, - }, - transaction, - })) - .then(familiaEncontrada => { - if (!familiaEncontrada) { - throw new BadRequestExeption(516); - } - }) - .then(() => Familia.update({ nome }, { - where: { - id, - }, - transaction, - })); - sequelize.transaction(callback) - .then(familiaCriada => { - console.log(familiaCriada); // eslint-disable-line - if (!familiaCriada) { - throw new BadRequestExeption(502); - } - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; - -export const excluirFamilia = (request, response, next) => { - const id = request.params.familia_id; - - const callback = transaction => - Promise.resolve() - .then(() => - Familia.findOne({ - where: { - id, - ativo: 1, - }, - transaction, - }) - ) - .then(familiaEncontrada => { - if (!familiaEncontrada) { - throw new BadRequestExeption(516); - } - }) - .then(() => - Promise.all([ - Genero.count({ where: { familia_id: id }, transaction }), - Especie.count({ where: { familia_id: id }, transaction }), - Subespecie.count({ where: { familia_id: id }, transaction }), - Variedade.count({ where: { familia_id: id }, transaction }), - Subfamilia.count({ where: { familia_id: id }, transaction }), - Tombo.count({ where: { familia_id: id }, transaction }), - ]) - ) - .then(([generosCount, especiesCount, subEspeciesCount, variedadesCount, subFamiliasCount, tombosCount]) => { - if (generosCount > 0 || especiesCount > 0 || subEspeciesCount > 0 || variedadesCount > 0 || subFamiliasCount > 0 || tombosCount > 0) { - throw new BadRequestExeption('A família não pode ser excluída porque possui dependentes.'); - } - }) - .then(() => - Familia.update( - { ativo: 0 }, - { - where: { - id, - }, - transaction, - } - ) - ); - - sequelize - .transaction(callback) - .then(() => { - response.status(codigos.DESATIVAR).send(); - }) - .catch(next); -}; -// /////////////////////SUBFAMILIA///////////////////////// -export const cadastrarSubfamilia = (request, response, next) => { - const { nome, familia_id: familiaId } = request.body; - - const callback = transaction => Promise.resolve() - .then(() => Subfamilia.findOne({ - where: { - nome, - familia_id: familiaId, - }, - transaction, - })) - .then(subfamiliaEncontrada => { - if (subfamiliaEncontrada) { - throw new BadRequestExeption(503); - } - }) - .then(() => Familia.findOne({ - where: { - id: familiaId, - }, - transaction, - })) - .then(familiaEncontrada => { - if (!familiaEncontrada) { - throw new BadRequestExeption(516); - } - - return familiaEncontrada; - }) - .then(() => Subfamilia.create({ nome, - familia_id: familiaId, - }, transaction)); - sequelize.transaction(callback) - .then(subfamiliaCriado => { - if (!subfamiliaCriado) { - throw new BadRequestExeption(504); - } - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; - -export const buscarSubfamilia = async (req, res, next) => { - try { - if (req.query.recaptchaToken) { - await verifyRecaptcha(req); - } - - const { limite, pagina, offset } = req.paginacao; - const { orderClause } = req.ordenacao; - - const { - subfamilia: nomeFiltro, - familia_id: familiaIdRaw, - familia_nome: familiaNomeFiltro, - } = req.query; - - const where = { ativo: 1 }; - if (nomeFiltro) { - where.nome = { [Op.like]: `%${nomeFiltro}%` }; - } - if (familiaIdRaw) { - const familiaId = parseInt(familiaIdRaw, 10); - if (!Number.isNaN(familiaId)) { - where.familia_id = familiaId; - } - } - - const familiaWhere = {}; - if (familiaNomeFiltro) { - familiaWhere.nome = { [Op.like]: `%${familiaNomeFiltro}%` }; - } - - const { count, rows } = await Subfamilia.findAndCountAll({ - attributes: ['id', 'nome'], - where, - order: orderClause, - limit: parseInt(limite, 10), - offset: parseInt(offset, 10), - include: [ - { model: Familia, attributes: ['id', 'nome'], where: familiaWhere }, - { model: Autor, attributes: ['id', 'nome'], as: 'autor' }, - ], - }); - - return res.status(codigos.LISTAGEM).json({ - metadados: { - total: count, - pagina: parseInt(pagina, 10), - limite: parseInt(limite, 10), - }, - resultado: rows, - }); - } catch (err) { - return next(err); - } -}; - -export const excluirSubfamilia = (request, response, next) => { - const id = request.params.subfamilia_id; - - const callback = transaction => - Promise.resolve() - .then(() => - Subfamilia.findOne({ - where: { - id, - ativo: 1, - }, - transaction, - }) - ) - .then(encontrado => { - if (!encontrado) { - throw new BadRequestExeption(520); - } - }) - .then(() => - Promise.all([Tombo.count({ where: { sub_familia_id: id }, transaction })]) - ) - .then(([tombosCount]) => { - if (tombosCount > 0) { - throw new BadRequestExeption('A subfamília não pode ser excluída porque possui dependentes.'); - } - }) - .then(() => - Subfamilia.update( - { ativo: 0 }, - { - where: { - id, - }, - transaction, - } - ) - ); - - sequelize - .transaction(callback) - .then(() => { - response.status(codigos.DESATIVAR).send(); - }) - .catch(next); -}; - -export const editarSubfamilia = (request, response, next) => { - const { nome, familia_id: familiaId } = request.body; - const subfamiliaId = parseInt(request.params.subfamilia_id); - - const callback = transaction => Promise.resolve() - .then(() => Familia.findOne({ - where: { - id: familiaId, - }, - transaction, - })) - .then(familiaEncontrada => { - if (!familiaEncontrada) { - throw new BadRequestExeption(516); - } - }) - .then(() => Subfamilia.findOne({ - where: { - id: subfamiliaId, - }, - transaction, - })) - .then(subfEncontrado => { - if (!subfEncontrado) { - throw new BadRequestExeption(520); - } - }) - .then(() => Subfamilia.update({ nome, familia_id: familiaId }, { - where: { - id: subfamiliaId, - }, - transaction, - })); - sequelize.transaction(callback) - .then(subfCriado => { - if (!subfCriado) { - throw new BadRequestExeption(504); - } - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; - -// //////////////////////GENERO///////////////////// -export const cadastrarGenero = (request, response, next) => { - const { nome, familia_id: familiaId } = request.body; - - const callback = transaction => Promise.resolve() - .then(() => Genero.findOne({ - where: { - nome, - familia_id: familiaId, - }, - transaction, - })) - .then(generoEncontrado => { - if (generoEncontrado) { - throw new BadRequestExeption(505); - } - }) - .then(() => Familia.findOne({ - where: { - id: familiaId, - }, - transaction, - })) - .then(familiaEncontrada => { - if (!familiaEncontrada) { - throw new BadRequestExeption(516); - } - - return familiaEncontrada; - }) - .then(() => Genero.create({ nome, - familia_id: familiaId, - }, transaction)); - sequelize.transaction(callback) - .then(generoCriado => { - if (!generoCriado) { - throw new BadRequestExeption(506); - } - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; - -export const buscarGeneros = async (request, response, next) => { - try { - if (request.query.recaptchaToken) { - await verifyRecaptcha(request); - } - - const { limite, pagina, offset } = request.paginacao; - const { orderClause } = request.ordenacao; - const { genero, familia_id: familiaId, familia_nome: familiaNome } = request.query; - - const where = { ativo: 1 }; - if (genero) where.nome = { [Op.like]: `%${genero}%` }; - if (familiaId) where.familia_id = familiaId; - - const familiaWhere = {}; - if (familiaNome) familiaWhere.nome = { [Op.like]: `%${familiaNome}%` }; - - const result = await Genero.findAndCountAll({ - attributes: ['id', 'nome'], - order: orderClause, - limit: limite, - offset, - where, - include: [ - { model: Familia, attributes: ['id', 'nome'], where: familiaWhere }, - ], - }); - - return response.status(codigos.LISTAGEM).json({ - metadados: { total: result.count, pagina, limite }, - resultado: result.rows, - }); - } catch (err) { - next(err); - } - return true; -}; - -export const excluirGeneros = (request, response, next) => { - const id = request.params.genero_id; - - const callback = transaction => - Promise.resolve() - .then(() => - Genero.findOne({ - where: { - id, - ativo: 1, - }, - transaction, - }) - ) - .then(generoEncontrado => { - if (!generoEncontrado) { - throw new BadRequestExeption(519); - } - }) - .then(() => - Promise.all([ - Especie.count({ where: { genero_id: id }, transaction }), - Subespecie.count({ where: { genero_id: id }, transaction }), - Variedade.count({ where: { genero_id: id }, transaction }), - Tombo.count({ where: { genero_id: id }, transaction }), - ]) - ) - .then(([especiesCount, subEspeciesCount, variedadesCount, tombosCount]) => { - if (especiesCount > 0 || subEspeciesCount > 0 || variedadesCount > 0 || tombosCount > 0) { - throw new BadRequestExeption('O gênero não pode ser excluído porque possui dependentes.'); - } - }) - .then(() => - Genero.update( - { ativo: 0 }, - { - where: { - id, - }, - transaction, - } - ) - ); - - sequelize - .transaction(callback) - .then(() => { - response.status(codigos.DESATIVAR).send(); - }) - .catch(next); -}; - -export const editarGenero = (request, response, next) => { - const { nome, familia_id: familiaId } = request.body; - const generoId = parseInt(request.params.genero_id); - - const callback = transaction => Promise.resolve() - .then(() => Familia.findOne({ - where: { - id: familiaId, - }, - transaction, - })) - .then(familiaEncontrada => { - if (!familiaEncontrada) { - throw new BadRequestExeption(516); - } - }) - .then(() => Genero.findOne({ - where: { - id: generoId, - }, - transaction, - })) - .then(generoEncontrado => { - if (!generoEncontrado) { - throw new BadRequestExeption(519); - } - }) - .then(() => Genero.update({ nome, familia_id: familiaId }, { - where: { - id: generoId, - }, - transaction, - })); - sequelize.transaction(callback) - .then(generoCriado => { - if (!generoCriado) { - throw new BadRequestExeption(506); - } - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; -// ///////////////////////ESPECIE//////////////////////////// -export const cadastrarEspecie = (request, response, next) => { - const { nome, genero_id: generoId, autor_id: autorId } = request.body; - - const callback = transaction => Promise.resolve() - .then(() => { - if (!autorId) { - return undefined; - } - const where = { - ativo: true, - id: autorId, - }; - return Autor.findOne({ - where, - transaction, - }); - }) - .then(autor => { - if (autorId) { - if (!autor) { - throw new BadRequestExeption(532); - } - } - }) - .then(() => Especie.findOne({ - where: { - nome, - genero_id: generoId, - ativo: true, - }, - transaction, - })) - .then(especieEncontrada => { - if (especieEncontrada) { - throw new BadRequestExeption(507); - } - }) - .then(() => Genero.findOne({ - where: { - id: generoId, - }, - transaction, - })) - .then(generoEncontrado => { - if (!generoEncontrado) { - throw new BadRequestExeption(519); - } - return generoEncontrado; - }) - .then(genero => Especie.create( - { - nome, - genero_id: generoId, - familia_id: genero.familia_id, - autor_id: autorId, - }, - transaction - )); - sequelize.transaction(callback) - .then(especieCriada => { - if (!especieCriada) { - throw new BadRequestExeption(508); - } - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; - -export const buscarEspecies = async (request, response, next) => { - try { - if (request.query.recaptchaToken) { - await verifyRecaptcha(request); - } - - const { limite, pagina, offset } = request.paginacao; - const { orderClause } = request.ordenacao; - const { - especie, genero_id: generoId, - familia_nome: familiaNome, - genero_nome: generoNome, - } = request.query; - - const where = { ativo: 1 }; - if (especie) where.nome = { [Op.like]: `%${especie}%` }; - if (generoId) where.genero_id = generoId; - - const familiaWhere = {}; - if (familiaNome) familiaWhere.nome = { [Op.like]: `%${familiaNome}%` }; - - const generoWhere = {}; - if (generoNome) generoWhere.nome = { [Op.like]: `%${generoNome}%` }; - - const result = await Especie.findAndCountAll({ - attributes: ['id', 'nome'], - order: orderClause, - limit: limite, - offset, - where, - include: [ - { model: Familia, attributes: ['id', 'nome'], where: familiaWhere }, - { model: Genero, attributes: ['id', 'nome'], where: generoWhere }, - { model: Autor, attributes: ['id', 'nome'], as: 'autor' }, - ], - }); - - return response.status(codigos.LISTAGEM).json({ - metadados: { total: result.count, pagina, limite }, - resultado: result.rows, - }); - } catch (err) { - next(err); - } - return true; -}; - -export const excluirEspecies = (request, response, next) => { - const id = request.params.especie_id; - - const callback = transaction => - Promise.resolve() - .then(() => - Especie.findOne({ - where: { - id, - ativo: 1, - }, - transaction, - }) - ) - .then(encontrado => { - if (!encontrado) { - throw new BadRequestExeption(521); - } - }) - .then(() => - Promise.all([ - Subespecie.count({ where: { especie_id: id }, transaction }), - Variedade.count({ where: { especie_id: id }, transaction }), - Tombo.count({ where: { especie_id: id }, transaction }), - ]) - ) - .then(([subEspeciesCount, variedadesCount, tombosCount]) => { - if (subEspeciesCount > 0 || variedadesCount > 0 || tombosCount > 0) { - throw new BadRequestExeption('A espécie não pode ser excluída porque possui dependentes.'); - } - }) - .then(() => - Especie.update( - { ativo: 0 }, - { - where: { - id, - }, - transaction, - } - ) - ); - - sequelize - .transaction(callback) - .then(() => { - response.status(codigos.DESATIVAR).send(); - }) - .catch(next); -}; - -export const editarEspecie = (request, response, next) => { - const { nome, genero_id: generoId, autor_id: autorId } = request.body; - const especieId = parseInt(request.params.especie_id); - - const callback = transaction => Promise.resolve() - .then(() => Genero.findOne({ - where: { - id: generoId, - }, - transaction, - })) - .then(generoEncontrado => { - if (!generoEncontrado) { - throw new BadRequestExeption(519); - } - }) - .then(() => Especie.findOne({ - where: { - id: especieId, - }, - transaction, - })) - .then(especieEncontrado => { - if (!especieEncontrado) { - throw new BadRequestExeption(521); - } - }) - .then(() => { - if (!autorId) { - return undefined; - } - const where = { - ativo: true, - id: autorId, - }; - return Autor.findOne({ - where, - transaction, - }); - }) - .then(autor => { - if (autorId) { - if (!autor) { - throw new BadRequestExeption(532); - } - } - }) - .then(() => Especie.update({ nome, genero_id: generoId, autor_id: autorId }, { - where: { - id: especieId, - }, - transaction, - })); - sequelize.transaction(callback) - .then(especieCriado => { - if (!especieCriado) { - throw new BadRequestExeption(522); - } - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; -// ////////////////////SUBESPECIE/////////////////////////// -export const cadastrarSubespecie = (request, response, next) => { - const { nome, especie_id: especieId, autor_id: autorId } = request.body; - - const callback = transaction => Promise.resolve() - .then(() => { - if (!autorId) { - return undefined; - } - const where = { - ativo: true, - id: autorId, - }; - return Autor.findOne({ - where, - transaction, - }); - }) - .then(autor => { - if (autorId) { - if (!autor) { - throw new BadRequestExeption(532); - } - } - }) - .then(() => Subespecie.findOne({ - where: { - nome, - especie_id: especieId, - }, - transaction, - })) - .then(encontrado => { - if (encontrado) { - throw new BadRequestExeption(509); - } - }) - .then(() => Especie.findOne({ - where: { - id: especieId, - }, - transaction, - })) - .then(encontrado => { - if (!encontrado) { - throw new BadRequestExeption(521); - } - return encontrado; - }) - .then(especie => Subespecie.create({ - nome, - genero_id: especie.genero_id, - especie_id: especieId, - familia_id: especie.familia_id, - autor_id: autorId, - }, transaction)); - sequelize.transaction(callback) - .then(subespecieCriada => { - if (!subespecieCriada) { - throw new BadRequestExeption(524); - } - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; - -export const buscarSubespecies = async (request, response, next) => { - try { - if (request.query.recaptchaToken) { - await verifyRecaptcha(request); - } - - const { limite, pagina, offset } = request.paginacao; - const { orderClause } = request.ordenacao; - const { - subespecie, - especie_id: especieId, - familia_nome: familiaNome, - genero_nome: generoNome, - especie_nome: especieNome, - } = request.query; - - const where = { ativo: 1 }; - if (subespecie) where.nome = { [Op.like]: `%${subespecie}%` }; - if (especieId) where.especie_id = especieId; - - const familiaWhere = {}; - if (familiaNome) familiaWhere.nome = { [Op.like]: `%${familiaNome}%` }; - - const generoWhere = {}; - if (generoNome) generoWhere.nome = { [Op.like]: `%${generoNome}%` }; - - const especieWhere = {}; - if (especieNome) especieWhere.nome = { [Op.like]: `%${especieNome}%` }; - - const result = await Subespecie.findAndCountAll({ - attributes: ['id', 'nome'], - order: orderClause, - limit: limite, - offset, - where, - include: [ - { model: Familia, attributes: ['id', 'nome'], where: familiaWhere }, - { model: Genero, attributes: ['id', 'nome'], where: generoWhere }, - { model: Especie, attributes: ['id', 'nome'], where: especieWhere, as: 'especie' }, - { model: Autor, attributes: ['id', 'nome'], as: 'autor' }, - ], - }); - - return response.status(codigos.LISTAGEM).json({ - metadados: { total: result.count, pagina, limite }, - resultado: result.rows, - }); - } catch (err) { - next(err); - } - return true; -}; - -export const excluirSubespecies = (request, response, next) => { - const id = request.params.subespecie_id; - - const callback = transaction => - Promise.resolve() - .then(() => - Subespecie.findOne({ - where: { - id, - ativo: 1, - }, - transaction, - }) - ) - .then(encontrado => { - if (!encontrado) { - throw new BadRequestExeption(525); - } - }) - .then(() => - Promise.all([Tombo.count({ where: { sub_especie_id: id }, transaction })]) - ) - .then(([tombosCount]) => { - if (tombosCount > 0) { - throw new BadRequestExeption('A subespécie não pode ser excluída porque possui dependentes.'); - } - }) - .then(() => - Subespecie.update( - { ativo: 0 }, - { - where: { - id, - }, - transaction, - } - ) - ); - - sequelize - .transaction(callback) - .then(() => { - response.status(codigos.DESATIVAR).send(); - }) - .catch(next); -}; - -export const editarSubespecie = (request, response, next) => { - const { nome, especie_id: especieId, autor_id: autorId } = request.body; - const subespecieId = parseInt(request.params.subespecie_id); - - const callback = transaction => Promise.resolve() - .then(() => Subespecie.findOne({ - where: { - id: subespecieId, - }, - transaction, - })) - .then(encontrado => { - if (!encontrado) { - throw new BadRequestExeption(525); - } - }) - .then(() => { - if (!autorId) { - return undefined; - } - const where = { - ativo: true, - id: autorId, - }; - return Autor.findOne({ - where, - transaction, - }); - }) - .then(autor => { - if (autorId) { - if (!autor) { - throw new BadRequestExeption(532); - } - } - }) - .then(() => Especie.findOne({ - where: { - id: especieId, - }, - transaction, - })) - .then(encontrado => { - if (!encontrado) { - throw new BadRequestExeption(521); - } - return encontrado; - }) - .then(especie => Subespecie.update({ - nome, - especie_id: especieId, - genero_id: especie.genero_id, - familia_id: especie.familia_id, - autor_id: autorId, - }, { - where: { - id: subespecieId, - }, - transaction, - })); - sequelize.transaction(callback) - .then(especieCriado => { - if (!especieCriado) { - throw new BadRequestExeption(522); - } - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; - -// //////////////////////VARIEDADE///////////////////////////// -export const cadastrarVariedade = (request, response, next) => { - const { nome, especie_id: especieId, autor_id: autorId } = request.body; - - const callback = transaction => Promise.resolve() - .then(() => { - if (!autorId) { - return undefined; - } - const where = { - ativo: true, - id: autorId, - }; - return Autor.findOne({ - where, - transaction, - }); - }) - .then(autor => { - if (autorId) { - if (!autor) { - throw new BadRequestExeption(532); - } - } - }) - .then(() => Variedade.findOne({ - where: { - nome, - especie_id: especieId, - }, - transaction, - })) - .then(encontrado => { - if (encontrado) { - throw new BadRequestExeption(511); - } - }) - .then(() => Especie.findOne({ - where: { - id: especieId, - }, - transaction, - })) - .then(encontrado => { - if (!encontrado) { - throw new BadRequestExeption(521); - } - return encontrado; - }) - .then(especie => Variedade.create( - { - nome, - genero_id: especie.genero_id, - especie_id: especieId, - familia_id: especie.familia_id, - autor_id: autorId, - }, - transaction - )); - sequelize.transaction(callback) - .then(variedadeCriada => { - if (!variedadeCriada) { - throw new BadRequestExeption(512); - } - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; - -export const buscarVariedades = async (request, response, next) => { - try { - if (request.query.recaptchaToken) { - await verifyRecaptcha(request); - } - - const { limite, pagina, offset } = request.paginacao; - const { orderClause } = request.ordenacao; - const { - variedade, - especie_id: especieId, - familia_nome: familiaNome, - genero_nome: generoNome, - especie_nome: especieNome, - } = request.query; - - const where = { ativo: 1 }; - if (variedade) where.nome = { [Op.like]: `%${variedade}%` }; - if (especieId) where.especie_id = especieId; - - const familiaWhere = {}; - if (familiaNome) familiaWhere.nome = { [Op.like]: `%${familiaNome}%` }; - - const generoWhere = {}; - if (generoNome) generoWhere.nome = { [Op.like]: `%${generoNome}%` }; - - const especieWhere = {}; - if (especieNome) especieWhere.nome = { [Op.like]: `%${especieNome}%` }; - - const result = await Variedade.findAndCountAll({ - attributes: ['id', 'nome'], - order: orderClause, - limit: limite, - offset, - where, - include: [ - { model: Familia, attributes: ['id', 'nome'], where: familiaWhere }, - { model: Genero, attributes: ['id', 'nome'], where: generoWhere }, - { model: Especie, attributes: ['id', 'nome'], where: especieWhere, as: 'especie' }, - { model: Autor, attributes: ['id', 'nome'], as: 'autor' }, - ], - }); - - return response.status(codigos.LISTAGEM).json({ - metadados: { total: result.count, pagina, limite }, - resultado: result.rows, - }); - } catch (err) { - next(err); - } - return true; -}; - -export const excluirVariedades = (request, response, next) => { - const id = request.params.variedade_id; - - const callback = transaction => Promise.resolve() - .then(() => Variedade.findOne({ - where: { - id, - ativo: 1, - }, - transaction, - })) - .then(encontrado => { - if (!encontrado) { - throw new BadRequestExeption(526); - } - }) - .then(() => Variedade.update({ ativo: 0 }, { - where: { - id, - }, - transaction, - })); - sequelize.transaction(callback) - .then(() => { - response.status(codigos.DESATIVAR).send(); - }) - .catch(next); -}; - -export const editarVariedade = (request, response, next) => { - const { nome, especie_id: especieId, autor_id: autorId } = request.body; - const variedadeId = parseInt(request.params.variedade_id); - - const callback = transaction => Promise.resolve() - .then(() => { - if (!autorId) { - return undefined; - } - const where = { - ativo: true, - id: autorId, - }; - return Autor.findOne({ - where, - transaction, - }); - }) - .then(autor => { - if (autorId) { - if (!autor) { - throw new BadRequestExeption(532); - } - } - }) - .then(() => Variedade.findOne({ - where: { - id: variedadeId, - }, - transaction, - })) - .then(encontrado => { - if (!encontrado) { - throw new BadRequestExeption(526); - } - }) - .then(() => Especie.findOne({ - where: { - id: especieId, - }, - transaction, - })) - .then(encontrado => { - if (!encontrado) { - throw new BadRequestExeption(521); - } - return encontrado; - }) - .then(especie => Variedade.update({ - nome, - especie_id: especieId, - genero_id: especie.genero_id, - familia_id: especie.familia_id, - autor_id: autorId, - }, { - where: { - id: variedadeId, - }, - transaction, - })); - sequelize.transaction(callback) - .then(variedade => { - if (!variedade) { - throw new BadRequestExeption(527); - } - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; - -// //////////////////AUTORES////////////////// -export const cadastrarAutores = (request, response, next) => { - const { nome, iniciais } = request.body; - - const callback = transaction => Promise.resolve() - .then(() => Autor.findOne({ - where: { - nome, - }, - transaction, - })) - .then(autorEncontrado => { - if (autorEncontrado) { - throw new BadRequestExeption(513); - } - }) - .then(() => Autor.create({ nome, iniciais }, transaction)); - sequelize.transaction(callback) - .then(autorCriado => { - if (!autorCriado) { - throw new BadRequestExeption(514); - } - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; - -export const buscarAutores = async (request, response, next) => { - try { - if (request.query.recaptchaToken) { - await verifyRecaptcha(request); - } - - const { limite, pagina, offset } = request.paginacao; - const { autor } = request.query; - const { orderClause } = request.ordenacao; - - const where = { ativo: 1 }; - if (autor) where.nome = { [Op.like]: `%${autor}%` }; - - const result = await Autor.findAndCountAll({ - attributes: ['id', 'nome', 'iniciais'], - order: orderClause, - limit: limite, - offset, - where, - }); - - return response.status(codigos.LISTAGEM).json({ - metadados: { total: result.count, pagina, limite }, - resultado: result.rows, - }); - } catch (err) { - next(err); - } - return true; -}; - -export const excluirAutores = (request, response, next) => { - const id = request.params.autor_id; - - const callback = transaction => - Promise.resolve() - .then(() => - Autor.findOne({ - where: { - id, - ativo: 1, - }, - transaction, - }) - ) - .then(encontrado => { - if (!encontrado) { - throw new BadRequestExeption(517); - } - }) - .then(() => - Promise.all([ - Subfamilia.count({ where: { autor_id: id }, transaction }), - Subespecie.count({ where: { autor_id: id }, transaction }), - Especie.count({ where: { autor_id: id }, transaction }), - Variedade.count({ where: { autor_id: id }, transaction }), - ]) - ) - .then(([subFamiliasCount, subEspeciesCount, especiesCount, variedadesCount]) => { - if (subFamiliasCount > 0 || subEspeciesCount > 0 || especiesCount > 0 || variedadesCount > 0) { - throw new BadRequestExeption('O autor não pode ser excluído porque possui dependentes.'); - } - }) - .then(() => - Autor.update( - { ativo: 0 }, - { - where: { - id, - }, - transaction, - } - ) - ); - - sequelize - .transaction(callback) - .then(() => { - response.status(codigos.DESATIVAR).send(); - }) - .catch(next); -}; - -export const editarAutores = (request, response, next) => { - const { nome, iniciais } = request.body; - const autorId = parseInt(request.params.autor_id); - - const callback = transaction => Promise.resolve() - .then(() => Autor.findOne({ - where: { - id: autorId, - }, - transaction, - })) - .then(autorEncontrado => { - if (!autorEncontrado) { - throw new BadRequestExeption(517); - } - }) - .then(() => Autor.update({ nome, iniciais }, { - where: { - id: autorId, - }, - transaction, - })); - sequelize.transaction(callback) - .then(autorAtualizado => { - if (!autorAtualizado) { - throw new BadRequestExeption(523); - } - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; -// ////////////////////////////////////////////// -export const listagem = (request, response, next) => { - - const sequelizeQueryTaxonomias = (limite, offset) => new Promise((resolve, reject) => { - - const type = Sequelize.QueryTypes.SELECT; - sequelize.query(listaTaxonomiasSQL(true, limite, offset), { type }) - .then(resultadoCount => { - let count = 0; - if (Array.isArray(resultadoCount) && resultadoCount.length > 0) { - count = resultadoCount[0].count; // eslint-disable-line - } - - const retorno = { count }; - - return sequelize.query(listaTaxonomiasSQL(false, limite, offset), { type }) - .then(resultado => ({ - ...retorno, - rows: resultado, - })); - }) - .then(resolve) - .catch(reject); - }); - - const { limite, pagina, offset } = request.paginacao; - - Promise.resolve() - .then(() => sequelizeQueryTaxonomias(limite, offset)) - .then(resultado => { - response.status(200) - .json({ - metadados: { - total: resultado.count, - pagina, - limite, - }, - resultado: resultado.rows, - }); - }) - .catch(next); -}; - -export default {}; +import BadRequestExeption from '../errors/bad-request-exception'; +import models from '../models'; +import codigos from '../resources/codigos-http'; +import listaTaxonomiasSQL from '../resources/sqls/lista-taxonomias'; +import verifyRecaptcha from '../utils/verify-recaptcha'; + +const { + sequelize, Sequelize: { Op }, Sequelize, Reino, Familia, Genero, Subfamilia, Especie, Variedade, Subespecie, Autor, Tombo, +} = models; +// ////////////////////FAMILIA/////////////////////////// +export const cadastrarFamilia = (request, response, next) => { + const { nome, reinoId } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => Familia.findOne({ + where: { + nome, + ativo: 1, + }, + transaction, + })) + .then(familiaEncontrada => { + if (familiaEncontrada) { + throw new BadRequestExeption(501); + } + }) + .then(() => Familia.create({ nome, reino_id: reinoId }, transaction)); + sequelize.transaction(callback) + .then(familiaCriada => { + console.log(familiaCriada); // eslint-disable-line + if (!familiaCriada) { + throw new BadRequestExeption(502); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const cadastrarReino = (request, response, next) => { + const { nome } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => Reino.findOne({ + where: { + nome, + }, + transaction, + })) + .then(reinoEncontrado => { + if (reinoEncontrado) { + throw new BadRequestExeption(501); + } + }) + .then(() => Reino.create({ nome }, transaction)); + sequelize.transaction(callback) + .then(reinoCriado => { + console.log(reinoCriado); // eslint-disable-line + if (!reinoCriado) { + throw new BadRequestExeption(502); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const editarReino = (request, response, next) => { + const id = request.params.reino_id; + const { nome } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => Reino.findOne({ + where: { + id, + }, + transaction, + })) + .then(reinoEncontrado => { + if (!reinoEncontrado) { + throw new BadRequestExeption(516); + } + }) + .then(() => Reino.update({ nome }, { + where: { + id, + }, + transaction, + })); + sequelize.transaction(callback) + .then(reinoEditado => { + console.log(reinoEditado); // eslint-disable-line + if (!reinoEditado) { + throw new BadRequestExeption(502); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarReinos = async (request, response, next) => { + try { + if (request.query.recaptchaToken) { + await verifyRecaptcha(request); + } + + const { limite, pagina, offset } = request.paginacao; + const { orderClause } = request.ordenacao; + const { reino, reinoId } = request.query; + + let where; + if (reino) { + where = { nome: { [Op.like]: `%${reino}%` } }; + } + if (reinoId) { + where = { ...where, reino_id: reinoId }; + } + + const resultado = await Reino.findAndCountAll({ + attributes: ['id', 'nome'], + order: orderClause, + limit: limite, + offset, + where, + }); + + response.status(codigos.LISTAGEM).json({ + metadados: { + total: resultado.count, + pagina, + limite, + }, + resultado: resultado.rows, + }); + } catch (err) { + next(err); + } + return true; +}; + +export const buscarFamilias = async (request, response, next) => { + try { + if (request.query.recaptchaToken) { + await verifyRecaptcha(request); + } + + const { limite, pagina, offset } = request.paginacao; + const { orderClause } = request.ordenacao; + const { familia, reino_id: reinoId } = request.query; + + const where = { ativo: 1 }; + if (familia) where.nome = { [Op.like]: `%${familia}%` }; + if (reinoId) where.reino_id = reinoId; + + const result = await Familia.findAndCountAll({ + attributes: ['id', 'nome'], + order: orderClause, + limit: limite, + offset, + where, + include: [{ model: Reino, attributes: ['id', 'nome'] }], + }); + + return response.status(codigos.LISTAGEM).json({ + metadados: { total: result.count, pagina, limite }, + resultado: result.rows, + }); + } catch (err) { + next(err); + } + return true; +}; + +export const editarFamilia = (request, response, next) => { + const id = request.params.familia_id; + const { nome } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => Familia.findOne({ + where: { + id, + ativo: 1, + }, + transaction, + })) + .then(familiaEncontrada => { + if (!familiaEncontrada) { + throw new BadRequestExeption(516); + } + }) + .then(() => Familia.update({ nome }, { + where: { + id, + }, + transaction, + })); + sequelize.transaction(callback) + .then(familiaCriada => { + console.log(familiaCriada); // eslint-disable-line + if (!familiaCriada) { + throw new BadRequestExeption(502); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const excluirFamilia = (request, response, next) => { + const id = request.params.familia_id; + + const callback = transaction => + Promise.resolve() + .then(() => + Familia.findOne({ + where: { + id, + ativo: 1, + }, + transaction, + }) + ) + .then(familiaEncontrada => { + if (!familiaEncontrada) { + throw new BadRequestExeption(516); + } + }) + .then(() => + Promise.all([ + Genero.count({ where: { familia_id: id }, transaction }), + Especie.count({ where: { familia_id: id }, transaction }), + Subespecie.count({ where: { familia_id: id }, transaction }), + Variedade.count({ where: { familia_id: id }, transaction }), + Subfamilia.count({ where: { familia_id: id }, transaction }), + Tombo.count({ where: { familia_id: id }, transaction }), + ]) + ) + .then(([generosCount, especiesCount, subEspeciesCount, variedadesCount, subFamiliasCount, tombosCount]) => { + if (generosCount > 0 || especiesCount > 0 || subEspeciesCount > 0 || variedadesCount > 0 || subFamiliasCount > 0 || tombosCount > 0) { + throw new BadRequestExeption('A família não pode ser excluída porque possui dependentes.'); + } + }) + .then(() => + Familia.update( + { ativo: 0 }, + { + where: { + id, + }, + transaction, + } + ) + ); + + sequelize + .transaction(callback) + .then(() => { + response.status(codigos.DESATIVAR).send(); + }) + .catch(next); +}; +// /////////////////////SUBFAMILIA///////////////////////// +export const cadastrarSubfamilia = (request, response, next) => { + const { nome, familia_id: familiaId } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => Subfamilia.findOne({ + where: { + nome, + familia_id: familiaId, + }, + transaction, + })) + .then(subfamiliaEncontrada => { + if (subfamiliaEncontrada) { + throw new BadRequestExeption(503); + } + }) + .then(() => Familia.findOne({ + where: { + id: familiaId, + }, + transaction, + })) + .then(familiaEncontrada => { + if (!familiaEncontrada) { + throw new BadRequestExeption(516); + } + + return familiaEncontrada; + }) + .then(() => Subfamilia.create({ nome, + familia_id: familiaId, + }, transaction)); + sequelize.transaction(callback) + .then(subfamiliaCriado => { + if (!subfamiliaCriado) { + throw new BadRequestExeption(504); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarSubfamilia = async (req, res, next) => { + try { + if (req.query.recaptchaToken) { + await verifyRecaptcha(req); + } + + const { limite, pagina, offset } = req.paginacao; + const { orderClause } = req.ordenacao; + + const { + subfamilia: nomeFiltro, + familia_id: familiaIdRaw, + familia_nome: familiaNomeFiltro, + } = req.query; + + const where = { ativo: 1 }; + if (nomeFiltro) { + where.nome = { [Op.like]: `%${nomeFiltro}%` }; + } + if (familiaIdRaw) { + const familiaId = parseInt(familiaIdRaw, 10); + if (!Number.isNaN(familiaId)) { + where.familia_id = familiaId; + } + } + + const familiaWhere = {}; + if (familiaNomeFiltro) { + familiaWhere.nome = { [Op.like]: `%${familiaNomeFiltro}%` }; + } + + const { count, rows } = await Subfamilia.findAndCountAll({ + attributes: ['id', 'nome'], + where, + order: orderClause, + limit: parseInt(limite, 10), + offset: parseInt(offset, 10), + include: [ + { model: Familia, attributes: ['id', 'nome'], where: familiaWhere }, + { model: Autor, attributes: ['id', 'nome'], as: 'autor' }, + ], + }); + + return res.status(codigos.LISTAGEM).json({ + metadados: { + total: count, + pagina: parseInt(pagina, 10), + limite: parseInt(limite, 10), + }, + resultado: rows, + }); + } catch (err) { + return next(err); + } +}; + +export const excluirSubfamilia = (request, response, next) => { + const id = request.params.subfamilia_id; + + const callback = transaction => + Promise.resolve() + .then(() => + Subfamilia.findOne({ + where: { + id, + ativo: 1, + }, + transaction, + }) + ) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(520); + } + }) + .then(() => + Promise.all([Tombo.count({ where: { sub_familia_id: id }, transaction })]) + ) + .then(([tombosCount]) => { + if (tombosCount > 0) { + throw new BadRequestExeption('A subfamília não pode ser excluída porque possui dependentes.'); + } + }) + .then(() => + Subfamilia.update( + { ativo: 0 }, + { + where: { + id, + }, + transaction, + } + ) + ); + + sequelize + .transaction(callback) + .then(() => { + response.status(codigos.DESATIVAR).send(); + }) + .catch(next); +}; + +export const editarSubfamilia = (request, response, next) => { + const { nome, familia_id: familiaId } = request.body; + const subfamiliaId = parseInt(request.params.subfamilia_id); + + const callback = transaction => Promise.resolve() + .then(() => Familia.findOne({ + where: { + id: familiaId, + }, + transaction, + })) + .then(familiaEncontrada => { + if (!familiaEncontrada) { + throw new BadRequestExeption(516); + } + }) + .then(() => Subfamilia.findOne({ + where: { + id: subfamiliaId, + }, + transaction, + })) + .then(subfEncontrado => { + if (!subfEncontrado) { + throw new BadRequestExeption(520); + } + }) + .then(() => Subfamilia.update({ nome, familia_id: familiaId }, { + where: { + id: subfamiliaId, + }, + transaction, + })); + sequelize.transaction(callback) + .then(subfCriado => { + if (!subfCriado) { + throw new BadRequestExeption(504); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +// //////////////////////GENERO///////////////////// +export const cadastrarGenero = (request, response, next) => { + const { nome, familia_id: familiaId } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => Genero.findOne({ + where: { + nome, + familia_id: familiaId, + }, + transaction, + })) + .then(generoEncontrado => { + if (generoEncontrado) { + throw new BadRequestExeption(505); + } + }) + .then(() => Familia.findOne({ + where: { + id: familiaId, + }, + transaction, + })) + .then(familiaEncontrada => { + if (!familiaEncontrada) { + throw new BadRequestExeption(516); + } + + return familiaEncontrada; + }) + .then(() => Genero.create({ nome, + familia_id: familiaId, + }, transaction)); + sequelize.transaction(callback) + .then(generoCriado => { + if (!generoCriado) { + throw new BadRequestExeption(506); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarGeneros = async (request, response, next) => { + try { + if (request.query.recaptchaToken) { + await verifyRecaptcha(request); + } + + const { limite, pagina, offset } = request.paginacao; + const { orderClause } = request.ordenacao; + const { genero, familia_id: familiaId, familia_nome: familiaNome } = request.query; + + const where = { ativo: 1 }; + if (genero) where.nome = { [Op.like]: `%${genero}%` }; + if (familiaId) where.familia_id = familiaId; + + const familiaWhere = {}; + if (familiaNome) familiaWhere.nome = { [Op.like]: `%${familiaNome}%` }; + + const result = await Genero.findAndCountAll({ + attributes: ['id', 'nome'], + order: orderClause, + limit: limite, + offset, + where, + include: [ + { model: Familia, attributes: ['id', 'nome'], where: familiaWhere }, + ], + }); + + return response.status(codigos.LISTAGEM).json({ + metadados: { total: result.count, pagina, limite }, + resultado: result.rows, + }); + } catch (err) { + next(err); + } + return true; +}; + +export const excluirGeneros = (request, response, next) => { + const id = request.params.genero_id; + + const callback = transaction => + Promise.resolve() + .then(() => + Genero.findOne({ + where: { + id, + ativo: 1, + }, + transaction, + }) + ) + .then(generoEncontrado => { + if (!generoEncontrado) { + throw new BadRequestExeption(519); + } + }) + .then(() => + Promise.all([ + Especie.count({ where: { genero_id: id }, transaction }), + Subespecie.count({ where: { genero_id: id }, transaction }), + Variedade.count({ where: { genero_id: id }, transaction }), + Tombo.count({ where: { genero_id: id }, transaction }), + ]) + ) + .then(([especiesCount, subEspeciesCount, variedadesCount, tombosCount]) => { + if (especiesCount > 0 || subEspeciesCount > 0 || variedadesCount > 0 || tombosCount > 0) { + throw new BadRequestExeption('O gênero não pode ser excluído porque possui dependentes.'); + } + }) + .then(() => + Genero.update( + { ativo: 0 }, + { + where: { + id, + }, + transaction, + } + ) + ); + + sequelize + .transaction(callback) + .then(() => { + response.status(codigos.DESATIVAR).send(); + }) + .catch(next); +}; + +export const editarGenero = (request, response, next) => { + const { nome, familia_id: familiaId } = request.body; + const generoId = parseInt(request.params.genero_id); + + const callback = transaction => Promise.resolve() + .then(() => Familia.findOne({ + where: { + id: familiaId, + }, + transaction, + })) + .then(familiaEncontrada => { + if (!familiaEncontrada) { + throw new BadRequestExeption(516); + } + }) + .then(() => Genero.findOne({ + where: { + id: generoId, + }, + transaction, + })) + .then(generoEncontrado => { + if (!generoEncontrado) { + throw new BadRequestExeption(519); + } + }) + .then(() => Genero.update({ nome, familia_id: familiaId }, { + where: { + id: generoId, + }, + transaction, + })); + sequelize.transaction(callback) + .then(generoCriado => { + if (!generoCriado) { + throw new BadRequestExeption(506); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; +// ///////////////////////ESPECIE//////////////////////////// +export const cadastrarEspecie = (request, response, next) => { + const { nome, genero_id: generoId, autor_id: autorId } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => { + if (!autorId) { + return undefined; + } + const where = { + ativo: true, + id: autorId, + }; + return Autor.findOne({ + where, + transaction, + }); + }) + .then(autor => { + if (autorId) { + if (!autor) { + throw new BadRequestExeption(532); + } + } + }) + .then(() => Especie.findOne({ + where: { + nome, + genero_id: generoId, + ativo: true, + }, + transaction, + })) + .then(especieEncontrada => { + if (especieEncontrada) { + throw new BadRequestExeption(507); + } + }) + .then(() => Genero.findOne({ + where: { + id: generoId, + }, + transaction, + })) + .then(generoEncontrado => { + if (!generoEncontrado) { + throw new BadRequestExeption(519); + } + return generoEncontrado; + }) + .then(genero => Especie.create( + { + nome, + genero_id: generoId, + familia_id: genero.familia_id, + autor_id: autorId, + }, + transaction + )); + sequelize.transaction(callback) + .then(especieCriada => { + if (!especieCriada) { + throw new BadRequestExeption(508); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarEspecies = async (request, response, next) => { + try { + if (request.query.recaptchaToken) { + await verifyRecaptcha(request); + } + + const { limite, pagina, offset } = request.paginacao; + const { orderClause } = request.ordenacao; + const { + especie, genero_id: generoId, + familia_nome: familiaNome, + genero_nome: generoNome, + } = request.query; + + const where = { ativo: 1 }; + if (especie) where.nome = { [Op.like]: `%${especie}%` }; + if (generoId) where.genero_id = generoId; + + const familiaWhere = {}; + if (familiaNome) familiaWhere.nome = { [Op.like]: `%${familiaNome}%` }; + + const generoWhere = {}; + if (generoNome) generoWhere.nome = { [Op.like]: `%${generoNome}%` }; + + const result = await Especie.findAndCountAll({ + attributes: ['id', 'nome'], + order: orderClause, + limit: limite, + offset, + where, + include: [ + { model: Familia, attributes: ['id', 'nome'], where: familiaWhere }, + { model: Genero, attributes: ['id', 'nome'], where: generoWhere }, + { model: Autor, attributes: ['id', 'nome'], as: 'autor' }, + ], + }); + + return response.status(codigos.LISTAGEM).json({ + metadados: { total: result.count, pagina, limite }, + resultado: result.rows, + }); + } catch (err) { + next(err); + } + return true; +}; + +export const excluirEspecies = (request, response, next) => { + const id = request.params.especie_id; + + const callback = transaction => + Promise.resolve() + .then(() => + Especie.findOne({ + where: { + id, + ativo: 1, + }, + transaction, + }) + ) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(521); + } + }) + .then(() => + Promise.all([ + Subespecie.count({ where: { especie_id: id }, transaction }), + Variedade.count({ where: { especie_id: id }, transaction }), + Tombo.count({ where: { especie_id: id }, transaction }), + ]) + ) + .then(([subEspeciesCount, variedadesCount, tombosCount]) => { + if (subEspeciesCount > 0 || variedadesCount > 0 || tombosCount > 0) { + throw new BadRequestExeption('A espécie não pode ser excluída porque possui dependentes.'); + } + }) + .then(() => + Especie.update( + { ativo: 0 }, + { + where: { + id, + }, + transaction, + } + ) + ); + + sequelize + .transaction(callback) + .then(() => { + response.status(codigos.DESATIVAR).send(); + }) + .catch(next); +}; + +export const editarEspecie = (request, response, next) => { + const { nome, genero_id: generoId, autor_id: autorId } = request.body; + const especieId = parseInt(request.params.especie_id); + + const callback = transaction => Promise.resolve() + .then(() => Genero.findOne({ + where: { + id: generoId, + }, + transaction, + })) + .then(generoEncontrado => { + if (!generoEncontrado) { + throw new BadRequestExeption(519); + } + }) + .then(() => Especie.findOne({ + where: { + id: especieId, + }, + transaction, + })) + .then(especieEncontrado => { + if (!especieEncontrado) { + throw new BadRequestExeption(521); + } + }) + .then(() => { + if (!autorId) { + return undefined; + } + const where = { + ativo: true, + id: autorId, + }; + return Autor.findOne({ + where, + transaction, + }); + }) + .then(autor => { + if (autorId) { + if (!autor) { + throw new BadRequestExeption(532); + } + } + }) + .then(() => Especie.update({ nome, genero_id: generoId, autor_id: autorId }, { + where: { + id: especieId, + }, + transaction, + })); + sequelize.transaction(callback) + .then(especieCriado => { + if (!especieCriado) { + throw new BadRequestExeption(522); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; +// ////////////////////SUBESPECIE/////////////////////////// +export const cadastrarSubespecie = (request, response, next) => { + const { nome, especie_id: especieId, autor_id: autorId } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => { + if (!autorId) { + return undefined; + } + const where = { + ativo: true, + id: autorId, + }; + return Autor.findOne({ + where, + transaction, + }); + }) + .then(autor => { + if (autorId) { + if (!autor) { + throw new BadRequestExeption(532); + } + } + }) + .then(() => Subespecie.findOne({ + where: { + nome, + especie_id: especieId, + }, + transaction, + })) + .then(encontrado => { + if (encontrado) { + throw new BadRequestExeption(509); + } + }) + .then(() => Especie.findOne({ + where: { + id: especieId, + }, + transaction, + })) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(521); + } + return encontrado; + }) + .then(especie => Subespecie.create({ + nome, + genero_id: especie.genero_id, + especie_id: especieId, + familia_id: especie.familia_id, + autor_id: autorId, + }, transaction)); + sequelize.transaction(callback) + .then(subespecieCriada => { + if (!subespecieCriada) { + throw new BadRequestExeption(524); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarSubespecies = async (request, response, next) => { + try { + if (request.query.recaptchaToken) { + await verifyRecaptcha(request); + } + + const { limite, pagina, offset } = request.paginacao; + const { orderClause } = request.ordenacao; + const { + subespecie, + especie_id: especieId, + familia_nome: familiaNome, + genero_nome: generoNome, + especie_nome: especieNome, + } = request.query; + + const where = { ativo: 1 }; + if (subespecie) where.nome = { [Op.like]: `%${subespecie}%` }; + if (especieId) where.especie_id = especieId; + + const familiaWhere = {}; + if (familiaNome) familiaWhere.nome = { [Op.like]: `%${familiaNome}%` }; + + const generoWhere = {}; + if (generoNome) generoWhere.nome = { [Op.like]: `%${generoNome}%` }; + + const especieWhere = {}; + if (especieNome) especieWhere.nome = { [Op.like]: `%${especieNome}%` }; + + const result = await Subespecie.findAndCountAll({ + attributes: ['id', 'nome'], + order: orderClause, + limit: limite, + offset, + where, + include: [ + { model: Familia, attributes: ['id', 'nome'], where: familiaWhere }, + { model: Genero, attributes: ['id', 'nome'], where: generoWhere }, + { model: Especie, attributes: ['id', 'nome'], where: especieWhere, as: 'especie' }, + { model: Autor, attributes: ['id', 'nome'], as: 'autor' }, + ], + }); + + return response.status(codigos.LISTAGEM).json({ + metadados: { total: result.count, pagina, limite }, + resultado: result.rows, + }); + } catch (err) { + next(err); + } + return true; +}; + +export const excluirSubespecies = (request, response, next) => { + const id = request.params.subespecie_id; + + const callback = transaction => + Promise.resolve() + .then(() => + Subespecie.findOne({ + where: { + id, + ativo: 1, + }, + transaction, + }) + ) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(525); + } + }) + .then(() => + Promise.all([Tombo.count({ where: { sub_especie_id: id }, transaction })]) + ) + .then(([tombosCount]) => { + if (tombosCount > 0) { + throw new BadRequestExeption('A subespécie não pode ser excluída porque possui dependentes.'); + } + }) + .then(() => + Subespecie.update( + { ativo: 0 }, + { + where: { + id, + }, + transaction, + } + ) + ); + + sequelize + .transaction(callback) + .then(() => { + response.status(codigos.DESATIVAR).send(); + }) + .catch(next); +}; + +export const editarSubespecie = (request, response, next) => { + const { nome, especie_id: especieId, autor_id: autorId } = request.body; + const subespecieId = parseInt(request.params.subespecie_id); + + const callback = transaction => Promise.resolve() + .then(() => Subespecie.findOne({ + where: { + id: subespecieId, + }, + transaction, + })) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(525); + } + }) + .then(() => { + if (!autorId) { + return undefined; + } + const where = { + ativo: true, + id: autorId, + }; + return Autor.findOne({ + where, + transaction, + }); + }) + .then(autor => { + if (autorId) { + if (!autor) { + throw new BadRequestExeption(532); + } + } + }) + .then(() => Especie.findOne({ + where: { + id: especieId, + }, + transaction, + })) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(521); + } + return encontrado; + }) + .then(especie => Subespecie.update({ + nome, + especie_id: especieId, + genero_id: especie.genero_id, + familia_id: especie.familia_id, + autor_id: autorId, + }, { + where: { + id: subespecieId, + }, + transaction, + })); + sequelize.transaction(callback) + .then(especieCriado => { + if (!especieCriado) { + throw new BadRequestExeption(522); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +// //////////////////////VARIEDADE///////////////////////////// +export const cadastrarVariedade = (request, response, next) => { + const { nome, especie_id: especieId, autor_id: autorId } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => { + if (!autorId) { + return undefined; + } + const where = { + ativo: true, + id: autorId, + }; + return Autor.findOne({ + where, + transaction, + }); + }) + .then(autor => { + if (autorId) { + if (!autor) { + throw new BadRequestExeption(532); + } + } + }) + .then(() => Variedade.findOne({ + where: { + nome, + especie_id: especieId, + }, + transaction, + })) + .then(encontrado => { + if (encontrado) { + throw new BadRequestExeption(511); + } + }) + .then(() => Especie.findOne({ + where: { + id: especieId, + }, + transaction, + })) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(521); + } + return encontrado; + }) + .then(especie => Variedade.create( + { + nome, + genero_id: especie.genero_id, + especie_id: especieId, + familia_id: especie.familia_id, + autor_id: autorId, + }, + transaction + )); + sequelize.transaction(callback) + .then(variedadeCriada => { + if (!variedadeCriada) { + throw new BadRequestExeption(512); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarVariedades = async (request, response, next) => { + try { + if (request.query.recaptchaToken) { + await verifyRecaptcha(request); + } + + const { limite, pagina, offset } = request.paginacao; + const { orderClause } = request.ordenacao; + const { + variedade, + especie_id: especieId, + familia_nome: familiaNome, + genero_nome: generoNome, + especie_nome: especieNome, + } = request.query; + + const where = { ativo: 1 }; + if (variedade) where.nome = { [Op.like]: `%${variedade}%` }; + if (especieId) where.especie_id = especieId; + + const familiaWhere = {}; + if (familiaNome) familiaWhere.nome = { [Op.like]: `%${familiaNome}%` }; + + const generoWhere = {}; + if (generoNome) generoWhere.nome = { [Op.like]: `%${generoNome}%` }; + + const especieWhere = {}; + if (especieNome) especieWhere.nome = { [Op.like]: `%${especieNome}%` }; + + const result = await Variedade.findAndCountAll({ + attributes: ['id', 'nome'], + order: orderClause, + limit: limite, + offset, + where, + include: [ + { model: Familia, attributes: ['id', 'nome'], where: familiaWhere }, + { model: Genero, attributes: ['id', 'nome'], where: generoWhere }, + { model: Especie, attributes: ['id', 'nome'], where: especieWhere, as: 'especie' }, + { model: Autor, attributes: ['id', 'nome'], as: 'autor' }, + ], + }); + + return response.status(codigos.LISTAGEM).json({ + metadados: { total: result.count, pagina, limite }, + resultado: result.rows, + }); + } catch (err) { + next(err); + } + return true; +}; + +export const excluirVariedades = (request, response, next) => { + const id = request.params.variedade_id; + + const callback = transaction => Promise.resolve() + .then(() => Variedade.findOne({ + where: { + id, + ativo: 1, + }, + transaction, + })) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(526); + } + }) + .then(() => Variedade.update({ ativo: 0 }, { + where: { + id, + }, + transaction, + })); + sequelize.transaction(callback) + .then(() => { + response.status(codigos.DESATIVAR).send(); + }) + .catch(next); +}; + +export const editarVariedade = (request, response, next) => { + const { nome, especie_id: especieId, autor_id: autorId } = request.body; + const variedadeId = parseInt(request.params.variedade_id); + + const callback = transaction => Promise.resolve() + .then(() => { + if (!autorId) { + return undefined; + } + const where = { + ativo: true, + id: autorId, + }; + return Autor.findOne({ + where, + transaction, + }); + }) + .then(autor => { + if (autorId) { + if (!autor) { + throw new BadRequestExeption(532); + } + } + }) + .then(() => Variedade.findOne({ + where: { + id: variedadeId, + }, + transaction, + })) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(526); + } + }) + .then(() => Especie.findOne({ + where: { + id: especieId, + }, + transaction, + })) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(521); + } + return encontrado; + }) + .then(especie => Variedade.update({ + nome, + especie_id: especieId, + genero_id: especie.genero_id, + familia_id: especie.familia_id, + autor_id: autorId, + }, { + where: { + id: variedadeId, + }, + transaction, + })); + sequelize.transaction(callback) + .then(variedade => { + if (!variedade) { + throw new BadRequestExeption(527); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +// //////////////////AUTORES////////////////// +export const cadastrarAutores = (request, response, next) => { + const { nome, iniciais } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => Autor.findOne({ + where: { + nome, + }, + transaction, + })) + .then(autorEncontrado => { + if (autorEncontrado) { + throw new BadRequestExeption(513); + } + }) + .then(() => Autor.create({ nome, iniciais }, transaction)); + sequelize.transaction(callback) + .then(autorCriado => { + if (!autorCriado) { + throw new BadRequestExeption(514); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarAutores = async (request, response, next) => { + try { + if (request.query.recaptchaToken) { + await verifyRecaptcha(request); + } + + const { limite, pagina, offset } = request.paginacao; + const { autor } = request.query; + const { orderClause } = request.ordenacao; + + const where = { ativo: 1 }; + if (autor) where.nome = { [Op.like]: `%${autor}%` }; + + const result = await Autor.findAndCountAll({ + attributes: ['id', 'nome', 'iniciais'], + order: orderClause, + limit: limite, + offset, + where, + }); + + return response.status(codigos.LISTAGEM).json({ + metadados: { total: result.count, pagina, limite }, + resultado: result.rows, + }); + } catch (err) { + next(err); + } + return true; +}; + +export const excluirAutores = (request, response, next) => { + const id = request.params.autor_id; + + const callback = transaction => + Promise.resolve() + .then(() => + Autor.findOne({ + where: { + id, + ativo: 1, + }, + transaction, + }) + ) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(517); + } + }) + .then(() => + Promise.all([ + Subfamilia.count({ where: { autor_id: id }, transaction }), + Subespecie.count({ where: { autor_id: id }, transaction }), + Especie.count({ where: { autor_id: id }, transaction }), + Variedade.count({ where: { autor_id: id }, transaction }), + ]) + ) + .then(([subFamiliasCount, subEspeciesCount, especiesCount, variedadesCount]) => { + if (subFamiliasCount > 0 || subEspeciesCount > 0 || especiesCount > 0 || variedadesCount > 0) { + throw new BadRequestExeption('O autor não pode ser excluído porque possui dependentes.'); + } + }) + .then(() => + Autor.update( + { ativo: 0 }, + { + where: { + id, + }, + transaction, + } + ) + ); + + sequelize + .transaction(callback) + .then(() => { + response.status(codigos.DESATIVAR).send(); + }) + .catch(next); +}; + +export const editarAutores = (request, response, next) => { + const { nome, iniciais } = request.body; + const autorId = parseInt(request.params.autor_id); + + const callback = transaction => Promise.resolve() + .then(() => Autor.findOne({ + where: { + id: autorId, + }, + transaction, + })) + .then(autorEncontrado => { + if (!autorEncontrado) { + throw new BadRequestExeption(517); + } + }) + .then(() => Autor.update({ nome, iniciais }, { + where: { + id: autorId, + }, + transaction, + })); + sequelize.transaction(callback) + .then(autorAtualizado => { + if (!autorAtualizado) { + throw new BadRequestExeption(523); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; +// ////////////////////////////////////////////// +export const listagem = (request, response, next) => { + + const sequelizeQueryTaxonomias = (limite, offset) => new Promise((resolve, reject) => { + + const type = Sequelize.QueryTypes.SELECT; + sequelize.query(listaTaxonomiasSQL(true, limite, offset), { type }) + .then(resultadoCount => { + let count = 0; + if (Array.isArray(resultadoCount) && resultadoCount.length > 0) { + count = resultadoCount[0].count; // eslint-disable-line + } + + const retorno = { count }; + + return sequelize.query(listaTaxonomiasSQL(false, limite, offset), { type }) + .then(resultado => ({ + ...retorno, + rows: resultado, + })); + }) + .then(resolve) + .catch(reject); + }); + + const { limite, pagina, offset } = request.paginacao; + + Promise.resolve() + .then(() => sequelizeQueryTaxonomias(limite, offset)) + .then(resultado => { + response.status(200) + .json({ + metadados: { + total: resultado.count, + pagina, + limite, + }, + resultado: resultado.rows, + }); + }) + .catch(next); +}; + +export default {}; diff --git a/src/controllers/tombos-controller.js b/src/controllers/tombos-controller.js index 0738252..c6dee65 100644 --- a/src/controllers/tombos-controller.js +++ b/src/controllers/tombos-controller.js @@ -1,1657 +1,1657 @@ -/* eslint-disable quotes */ -// @ts-nocheck -import { ForeignKeyConstraintError } from 'sequelize'; - -import { padronizarNomeDarwincore } from '~/helpers/padroniza-nome-darwincore'; - -import BadRequestExeption from '../errors/bad-request-exception'; -import NotFoundException from '../errors/not-found-exception'; -import { - converteParaDecimal, converteDecimalParaGraus, converteDecimalParaGMSGrau, converteDecimalParaGMSMinutos, converteDecimalParaGMSSegundos, -} from '../helpers/coordenadas'; -import pick from '../helpers/pick'; -import { converteInteiroParaRomano } from '../helpers/tombo'; -import models from '../models'; -import codigos from '../resources/codigos-http'; -import verifyRecaptcha from '../utils/verify-recaptcha'; -import { aprovarPendencia } from './pendencias-controller'; - -const { - Solo, Relevo, Cidade, Estado, Vegetacao, FaseSucessional, Pais, Tipo, LocalColeta, Familia, sequelize, - Genero, Subfamilia, Autor, Coletor, Variedade, Subespecie, TomboFoto, Identificador, - ColecaoAnexa, Especie, Herbario, Tombo, Alteracao, TomboIdentificador, ColetorComplementar, Sequelize: { Op }, -} = models; - -function parseDataTombo(valor) { - const partes = valor.split(/[-]/).map(p => p.trim()); - if (partes.length >= 3) { - const [anoStr, mesStr, diaStr] = partes; - const dia = parseInt(diaStr, 10); - const mes = parseInt(mesStr, 10) - 1; - const ano = parseInt(anoStr, 10); - if (!Number.isNaN(dia) && !Number.isNaN(mes) && !Number.isNaN(ano)) { - return new Date(ano, mes, dia, 12, 0, 0, 0); - } - return null; - } - return null; -} - -export const cadastro = (request, response, next) => { - const { - principal, - taxonomia, - localidade, - paisagem, - identificacao, - coletor, - // eslint-disable-next-line @typescript-eslint/naming-convention - coletor_complementar, - colecoes_anexas: colecoesAnexas, - observacoes, - unicata, - } = request.body.json; - let tomboCriado = null; - - const callback = transaction => - Promise.resolve() - .then(() => { - if (!paisagem || !paisagem.solo_id) { - return undefined; - } - - const where = { - id: paisagem.solo_id, - }; - - return Solo.findOne({ where, transaction }); - }) - .then(solo => { - if (paisagem && paisagem.solo_id) { - if (!solo) { - throw new BadRequestExeption(528); - } - } - if (paisagem && paisagem.relevo_id) { - return Relevo.findOne({ - where: { - id: paisagem.relevo_id, - }, - transaction, - }); - } - return undefined; - }) - .then(relevo => { - if (paisagem && paisagem.relevo_id) { - if (!relevo) { - throw new BadRequestExeption(529); - } - } - if (paisagem && paisagem.vegetacao_id) { - return Vegetacao.findOne({ - where: { - id: paisagem.vegetacao_id, - }, - transaction, - }); - } - return undefined; - }) - .then(vegetacao => { - if (paisagem && paisagem.vegetacao_id) { - if (!vegetacao) { - throw new BadRequestExeption(530); - } - } - if (paisagem && paisagem.fase_sucessional_id) { - return FaseSucessional.findOne({ - where: { - numero: paisagem.fase_sucessional_id, - }, - transaction, - }); - } - return undefined; - }) - .then(fase => { - if (paisagem && paisagem.fase_sucessional_id) { - if (!fase) { - throw new BadRequestExeption(531); - } - } - return undefined; - }) - .then(() => { - if (!localidade?.local_coleta_id) { - throw new BadRequestExeption(400); - } - return LocalColeta.findOne({ - where: { - id: localidade.local_coleta_id, - }, - transaction, - }); - }) - .then(localColeta => { - if (!localColeta) { - throw new BadRequestExeption(533); - } - return undefined; - }) - // //////////////CRIA COLECOES ANEXAS/////////// - .then(() => { - if (colecoesAnexas) { - const object = pick(colecoesAnexas, ['tipo', 'observacoes']); - return ColecaoAnexa.create(object, { transaction }); - } - return undefined; - }) - .then(colecao => { - if (colecoesAnexas) { - if (!colecao) { - throw new BadRequestExeption(401); - } - colecoesAnexas.id = colecao.id; - } - return undefined; - }) - // ///////// VALIDA A TAXONOMIA E A INSERE NO NOME CIENTIFICO ////////// - .then(() => { - if (taxonomia && taxonomia.familia_id) { - return Familia.findOne({ - where: { - id: taxonomia.familia_id, - }, - transaction, - }); - } - return undefined; - }) - .then(familia => { - if (taxonomia && taxonomia.familia_id) { - if (!familia) { - throw new BadRequestExeption(402); - } - } - return undefined; - }) - .then(() => { - if (taxonomia && taxonomia.sub_familia_id) { - return Subfamilia.findOne({ - where: { - id: taxonomia.sub_familia_id, - familia_id: taxonomia.familia_id, - }, - transaction, - }); - } - return undefined; - }) - .then(subfamilia => { - if (taxonomia && taxonomia.sub_familia_id) { - if (!subfamilia) { - throw new BadRequestExeption(403); - } - } - return undefined; - }) - .then(() => { - if (taxonomia && taxonomia.genero_id) { - return Genero.findOne({ - where: { - id: taxonomia.genero_id, - familia_id: taxonomia.familia_id, - }, - transaction, - }); - } - return undefined; - }) - .then(genero => { - if (taxonomia && taxonomia.genero_id) { - if (!genero) { - throw new BadRequestExeption(404); - } - taxonomia.nome_cientifico = genero.nome; - } - return undefined; - }) - .then(() => { - if (taxonomia && taxonomia.especie_id) { - return Especie.findOne({ - where: { - id: taxonomia.especie_id, - genero_id: taxonomia.genero_id, - }, - transaction, - }); - } - return undefined; - }) - .then(especie => { - if (taxonomia && taxonomia.especie_id) { - if (!especie) { - throw new BadRequestExeption(405); - } - taxonomia.nome_cientifico += ` ${especie.nome}`; - } - return undefined; - }) - .then(() => { - if (taxonomia && taxonomia.sub_especie_id) { - return Subespecie.findOne({ - where: { - id: taxonomia.sub_especie_id, - especie_id: taxonomia.especie_id, - }, - transaction, - }); - } - return undefined; - }) - .then(subespecie => { - if (taxonomia && taxonomia.sub_especie_id) { - if (!subespecie) { - throw new BadRequestExeption(406); - } - } - return undefined; - }) - .then(() => { - if (taxonomia && taxonomia.variedade_id) { - return Variedade.findOne({ - where: { - id: taxonomia.variedade_id, - especie_id: taxonomia.especie_id, - }, - transaction, - }); - } - return undefined; - }) - .then(variedade => { - if (taxonomia && taxonomia.variedade_id) { - if (!variedade) { - throw new BadRequestExeption(407); - } - } - return undefined; - }) - // /////////// CADASTRA TOMBO ///////////// - .then(() => { - let jsonTombo = { - data_coleta_dia: principal.data_coleta.dia, - data_coleta_mes: principal.data_coleta.mes, - data_coleta_ano: principal.data_coleta.ano, - numero_coleta: principal.numero_coleta, - local_coleta_id: localidade.local_coleta_id, - cor: principal.cor || null, - coletor_id: coletor, - data_tombo: parseDataTombo(principal.data_tombo), - }; - - if (paisagem?.descricao) { - jsonTombo.descricao = paisagem.descricao; - } - - if (observacoes) { - jsonTombo.observacao = observacoes; - } - if (unicata !== undefined) { - jsonTombo.unicata = unicata; - } - if (principal.nome_popular) { - jsonTombo.nomes_populares = principal.nome_popular; - } - if (localidade.latitude) { - jsonTombo.latitude = converteParaDecimal(localidade.latitude); - } - if (localidade.longitude) { - jsonTombo.longitude = converteParaDecimal(localidade.longitude); - } - if (localidade.altitude) { - jsonTombo.altitude = localidade.altitude; - } - if (identificacao) { - jsonTombo.data_identificacao_dia = identificacao.data_identificacao?.dia; - jsonTombo.data_identificacao_mes = identificacao.data_identificacao?.mes; - jsonTombo.data_identificacao_ano = identificacao.data_identificacao?.ano; - } - if (paisagem) { - jsonTombo.solo_id = paisagem.solo_id; - jsonTombo.relevo_id = paisagem.relevo_id; - jsonTombo.vegetacao_id = paisagem.vegetacao_id; - } - jsonTombo = { - ...jsonTombo, - ...pick(principal, ['entidade_id', 'tipo_id', 'taxon_id']), - }; - if (taxonomia) { - jsonTombo = { - ...jsonTombo, - // eslint-disable-next-line max-len - ...pick(taxonomia, ['nome_cientifico', 'variedade_id', 'especie_id', 'genero_id', 'familia_id', 'sub_familia_id', 'sub_especie_id']), - }; - } - if (colecoesAnexas && colecoesAnexas.id) { - jsonTombo.colecao_anexa_id = colecoesAnexas.id; - } - if (request.usuario.tipo_usuario_id === 2 || request.usuario.tipo_usuario_id === 3) { - jsonTombo.rascunho = true; - } - return Tombo.create(jsonTombo, { transaction }); - }) - // //////////// CADASTRA A ALTERACAO /////////// - .then(tombo => { - if (!tombo) { - throw new BadRequestExeption(408); - } - let status = 'ESPERANDO'; - principal.hcf = tombo.hcf; - if (request.usuario.tipo_usuario_id === 1) { - status = 'APROVADO'; - } - - const dadosComplementares = coletor_complementar?.complementares || ''; - - const tomboData = { ...tombo.toJSON(), complementares: dadosComplementares, colecoes_anexas_tipo: colecoesAnexas?.tipo || null, colecoes_anexas_observacoes: colecoesAnexas?.observacoes || null }; - - if (identificacao?.identificadores && identificacao.identificadores.length > 0) { - tomboData.identificadores = identificacao.identificadores; - } - - const dados = { - tombo_hcf: tombo.hcf, - usuario_id: request.usuario.id, - status, - tombo_json: JSON.stringify(tomboData), - ativo: true, - identificacao: 0, - }; - tomboCriado = tombo; - - return Alteracao.create(dados, { transaction }).then(alteracaoTomboCriado => { - if (!alteracaoTomboCriado) { - throw new BadRequestExeption(409); - } - - if (coletor_complementar && coletor_complementar.complementares) { - const jsonColetorComplementar = { - hcf: principal.hcf, - complementares: coletor_complementar.complementares, - }; - - return ColetorComplementar.create(jsonColetorComplementar, { transaction }); - } - - return alteracaoTomboCriado; - }); - }) - // /////////////// CADASTRA O INDETIFICADOR /////////////// - .then(alteracaoTomboCriado => { - if (!alteracaoTomboCriado) { - throw new BadRequestExeption(409); - } - if (tomboCriado !== null) { - if (identificacao && identificacao.identificadores && identificacao.identificadores.length > 0) { - const promises = identificacao.identificadores.map((identificador_id, index) => { - const isPrincipal = index === 0; - const dadosIdentificadores = { - identificador_id, - tombo_hcf: tomboCriado.hcf, - ordem: index + 1, - principal: isPrincipal, - }; - return TomboIdentificador.create(dadosIdentificadores, { - transaction, - }); - }); - return Promise.all(promises); - } - } - return undefined; - }); - - sequelize.transaction(callback) - .then(() => { - response.status(codigos.CADASTRO_RETORNO).json({ - hcf: principal.hcf, - }); - }) - .catch(next); -}; - -function alteracaoIdentificador(request, transaction) { - const { - familia_id: familiaId, subfamilia_id: subfamiliaId, genero_id: generoId, - especie_id: especieId, subespecie_id: subespecieId, variedade_id: variedadeId, - } = request.body; - const { tombo_id: tomboId } = request.params; - const update = {}; - - if (familiaId !== undefined) { - update.familia_id = familiaId; - } - if (subfamiliaId !== undefined) { - update.subfamilia_id = subfamiliaId; - } - if (generoId !== undefined) { - update.genero_id = generoId; - } - if (especieId !== undefined) { - update.especie_id = especieId; - } - if (subespecieId !== undefined) { - update.subespecie_id = subespecieId; - } - if (variedadeId !== undefined) { - update.variedade_id = variedadeId; - } - - return Promise.resolve() - .then(() => Alteracao.create({ - tombo_hcf: tomboId, - usuario_id: request.usuario.id, - status: 'ESPERANDO', - tombo_json: JSON.stringify(update), - ativo: true, - identificacao: 1, - }, { transaction })) - .then(alteracaoIdent => { - if (request.usuario.tipo_usuario_id === 3) { - if (!alteracaoIdent) { - throw new BadRequestExeption(421); - } - } - }); -} - -function alteracaoCuradorouOperador(request, response, transaction) { - const { body } = request; - const update = {}; - - const nomePopular = body?.principal?.nome_popular; - if (nomePopular !== undefined) update.nomes_populares = nomePopular; - - const entidadeId = body?.principal?.entidade_id; - if (entidadeId !== undefined) update.entidade_id = entidadeId; - - const numeroColeta = body?.principal?.numero_coleta; - if (numeroColeta !== undefined) update.numero_coleta = numeroColeta; - - const dataColeta = body?.principal?.data_coleta; - if (dataColeta?.dia !== undefined) update.data_coleta_dia = dataColeta.dia; - if (dataColeta?.mes !== undefined) update.data_coleta_mes = dataColeta.mes; - if (dataColeta?.ano !== undefined) update.data_coleta_ano = dataColeta.ano; - - const tipoId = body?.principal?.tipo_id; - if (tipoId !== undefined) update.tipo_id = tipoId; - - const { cor } = body.principal || {}; - if (cor !== undefined) update.cor = cor; - - const dataTombo = body?.principal?.data_tombo; - if (dataTombo !== undefined) update.data_tombo = parseDataTombo(dataTombo); - - const familiaId = body?.taxonomia?.familia_id; - if (familiaId !== undefined) update.familia_id = familiaId; - - const subfamiliaId = body?.taxonomia?.sub_familia_id; - if (subfamiliaId !== undefined) update.sub_familia_id = subfamiliaId; - - const generoId = body?.taxonomia?.genero_id; - if (generoId !== undefined) update.genero_id = generoId; - - const especieId = body?.taxonomia?.especie_id; - if (especieId !== undefined) update.especie_id = especieId; - - const subespecieId = body?.taxonomia?.sub_especie_id; - if (subespecieId !== undefined) update.sub_especie_id = subespecieId; - - const variedadeId = body?.taxonomia?.variedade_id; - if (variedadeId !== undefined) update.variedade_id = variedadeId; - - const latitude = body?.localidade?.latitude; - if (latitude !== undefined) { - update.latitude = latitude ? converteParaDecimal(latitude) : null; - } - - const longitude = body?.localidade?.longitude; - if (longitude !== undefined) { - update.longitude = longitude ? converteParaDecimal(longitude) : null; - } - - const altitude = body?.localidade?.altitude; - if (altitude !== undefined) update.altitude = altitude; - - const localColeta = body?.localidade?.local_coleta_id; - if (localColeta !== undefined) update.local_coleta_id = localColeta; - - const soloId = body?.paisagem?.solo_id; - if (soloId !== undefined) update.solo_id = soloId; - - const relevoId = body?.paisagem?.relevo_id; - if (relevoId !== undefined) update.relevo_id = relevoId; - - const vegetacaoId = body?.paisagem?.vegetacao_id; - if (vegetacaoId !== undefined) update.vegetacao_id = vegetacaoId; - - const descricao = body?.paisagem?.descricao; - if (descricao !== undefined) update.descricao = descricao; - - const unicata = body?.unicata; - if (unicata !== undefined) update.unicata = unicata; - - const faseSucessionalId = body?.paisagem?.fase_sucessional_id; - if (faseSucessionalId !== undefined) update.fase_sucessional_id = faseSucessionalId; - - const identificadores = body?.identificacao?.identificadores; - if (identificadores !== undefined) update.identificadores = identificadores; - - const dataIdentificacao = body?.identificacao?.data_identificacao; - if (dataIdentificacao?.dia !== undefined) update.data_identificacao_dia = dataIdentificacao.dia; - if (dataIdentificacao?.mes !== undefined) update.data_identificacao_mes = dataIdentificacao.mes; - if (dataIdentificacao?.ano !== undefined) update.data_identificacao_ano = dataIdentificacao.ano; - if (dataIdentificacao === null) { - update.data_identificacao_dia = null; - update.data_identificacao_mes = null; - update.data_identificacao_ano = null; - } - - const coletor = body?.coletor; - if (coletor !== undefined) update.coletor_id = coletor; - - const complementares = body?.coletor_complementar?.complementares; - if (complementares !== undefined) update.complementares = complementares; - - const colecoesAnexasTipo = body?.colecoes_anexas?.tipo; - if (colecoesAnexasTipo !== undefined) update.colecoes_anexas_tipo = colecoesAnexasTipo; - - const colecoesAnexasObservacoes = body?.colecoes_anexas?.observacoes; - if (colecoesAnexasObservacoes !== undefined) update.colecoes_anexas_observacoes = colecoesAnexasObservacoes; - - const { observacoes } = body || {}; - if (observacoes !== undefined) update.observacao = observacoes; - - const { tombo_id: tomboId } = request.params; - - return Alteracao.create({ - tombo_hcf: tomboId, - usuario_id: request.usuario.id, - status: 'ESPERANDO', - tombo_json: JSON.stringify(update), - ativo: true, - identificacao: 1, - }, { transaction }) - .then(alteracaoCriada => { - if (request.usuario.tipo_usuario_id === 1) { - return aprovarPendencia(update, tomboId, transaction) - .then(() => Alteracao.update({ status: 'APROVADO' }, { - where: { id: alteracaoCriada.id }, - transaction, - })) - .then(() => alteracaoCriada.toJSON()); - } if (request.usuario.tipo_usuario_id !== 2) { - throw new BadRequestExeption(421); - } - return alteracaoCriada.toJSON(); - }); -} - -export function alteracao(request, response, next) { - return sequelize.transaction(transaction => { - if (request.usuario.tipo_usuario_id === 3) { - return alteracaoIdentificador(request, transaction); - } if (request.usuario.tipo_usuario_id === 1 || request.usuario.tipo_usuario_id === 2) { - return alteracaoCuradorouOperador(request, response, transaction); - } - throw new BadRequestExeption(421); - - }) - .then(() => { - response.status(codigos.EDITAR_SEM_RETORNO).send(); - }) - .catch(next); -} - -export const desativar = (request, response, next) => { - const { params } = request; - - Promise.resolve() - .then(() => { - const where = { - ativo: true, - hcf: params.tombo_id, - }; - - return Tombo.findOne({ where }); - }) - .then(tombo => { - if (!tombo) { - throw new NotFoundException(416); - } - - const where = { - ativo: true, - hcf: params.tombo_id, - }; - - return Tombo.update({ ativo: false }, { where }); - }) - .then(() => { - response.status(204) - .send(); - }) - .catch(next); -}; - -export const listagem = (request, response, next) => { - const { pagina, limite, offset } = request.paginacao; - const { - nome_cientifico: nomeCientifico, hcf, tipo, nome_popular: nomePopular, situacao, - } = request.query; - let where = { - ativo: true, - rascunho: 0, - }; - - if (nomeCientifico) { - where = { - ...where, - nome_cientifico: { [Op.like]: `%${nomeCientifico}%` }, - }; - } - - if (hcf) { - where = { - ...where, - hcf, - }; - } - - if (tipo) { - where = { - ...where, - tipo_id: tipo, - }; - } - - if (nomePopular) { - where = { - ...where, - nomes_populares: { [Op.like]: `%${nomePopular}%` }, - }; - } - - if (situacao) { - where = { - ...where, - situacao, - }; - } - - let retorno = { // eslint-disable-line - metadados: { - total: 0, - pagina, - limite, - }, - tombos: [], - }; - Promise.resolve() - .then(() => Tombo.count({ where })) - .then(total => { - retorno.metadados.total = total; - }) - .then(() => Tombo.findAndCountAll({ - attributes: [ - 'hcf', - 'nomes_populares', - 'nome_cientifico', - 'data_coleta_dia', - 'data_coleta_mes', - 'data_coleta_ano', - 'created_at', - ], - include: { - // required: true, - model: Coletor, - attributes: ['id', 'nome'], - }, - where, - order: [['hcf', 'DESC']], - limit: limite, - offset, - })) - .then(listaTombos => { - retorno.tombos = listaTombos.rows; - response.status(codigos.LISTAGEM) - .json(retorno); - }) - .catch(next); -}; - -export const getDadosCadTombo = (request, response, next) => { - const retorno = {}; - const callback = transaction => Promise.resolve() - .then(() => Tombo.findAndCountAll({ - attributes: ['hcf', 'numero_coleta'], - order: [['numero_coleta', 'DESC']], - transaction, - })) - .then(tombos => { - if (!tombos) { - throw new BadRequestExeption(202); - } - retorno.numero_coleta = (tombos.rows[0].numero_coleta) + 1; - }) - .then(() => Herbario.findAndCountAll({ - attributes: ['id', 'nome', 'sigla'], - where: { - ativo: true, - }, - order: [['nome', 'ASC']], - transaction, - })) - .then(herbario => { - if (!herbario) { - throw new BadRequestExeption(203); - } - retorno.herbarios = herbario.rows; - }) - .then(() => Tipo.findAndCountAll({ - attributes: ['id', 'nome'], - order: [['nome', 'ASC']], - transaction, - })) - .then(tipos => { - if (!tipos) { - throw new BadRequestExeption(204); - } - retorno.tipos = tipos.rows; - }) - .then(() => Pais.findAndCountAll({ - order: [['nome', 'ASC']], - transaction, - })) - .then(paises => { - if (!paises) { - throw new BadRequestExeption(205); - } - retorno.paises = paises.rows; - }) - .then(() => Familia.findAndCountAll({ - attributes: ['id', 'nome'], - order: [['nome', 'ASC']], - where: { - ativo: true, - }, - transaction, - })) - .then(familias => { - if (!familias) { - throw new BadRequestExeption(206); - } - retorno.familias = familias.rows; - }) - .then(() => Solo.findAndCountAll({ - attributes: ['id', 'nome'], - order: [['nome', 'ASC']], - transaction, - })) - .then(solos => { - if (!solos) { - throw new BadRequestExeption(207); - } - retorno.solos = solos.rows; - }) - .then(() => Relevo.findAndCountAll({ - attributes: ['id', 'nome'], - order: [['nome', 'ASC']], - transaction, - })) - .then(relevos => { - if (!relevos) { - throw new BadRequestExeption(208); - } - retorno.relevos = relevos.rows; - }) - .then(() => Vegetacao.findAndCountAll({ - attributes: ['id', 'nome'], - order: [['nome', 'ASC']], - transaction, - })) - .then(vegetacoes => { - if (!vegetacoes) { - throw new BadRequestExeption(209); - } - retorno.vegetacoes = vegetacoes.rows; - }) - .then(() => FaseSucessional.findAndCountAll({ - attributes: ['numero', 'nome'], - order: [['nome', 'ASC']], - transaction, - })) - .then(fases => { - if (!fases) { - throw new BadRequestExeption(210); - } - retorno.fases = fases.rows; - }) - .then(() => Autor.findAndCountAll({ - attributes: ['id', 'nome'], - order: [['nome', 'ASC']], - where: { - ativo: true, - }, - transaction, - })) - .then(autores => { - if (!autores) { - throw new BadRequestExeption(213); - } - retorno.autores = autores.rows; - return retorno; - }); - sequelize.transaction(callback) - .then(() => { - response.status(codigos.BUSCAR_VARIOS_ITENS) - .json(retorno); - - }) - .catch(next); -}; - -export const cadastrarTipo = (request, response, next) => { - const callback = transaction => Promise.resolve() - .then(() => Tipo.findOne({ - where: { - nome: request.body.nome, - }, - transaction, - })) - .then(tipoEncontrado => { - if (tipoEncontrado) { - throw new BadRequestExeption(412); - } - }) - .then(() => Tipo.create( - { - nome: request.body.nome, - }, - transaction - )); - sequelize.transaction(callback) - .then(() => { - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; - -export const buscarTipos = (request, response, next) => { - Promise.resolve() - .then(() => Tipo.findAndCountAll({ - attributes: ['id', 'nome'], - })) - .then(tipos => { - response.status(codigos.LISTAGEM).json(tipos.rows); - }) - .catch(next); -}; - -export const cadastrarColetores = (request, response, next) => { - const callback = transaction => Promise.resolve() - .then(() => Coletor.findOne({ - where: { - nome: request.body.nome, - email: request.body.email, - }, - transaction, - })) - .then(coletorEncontrado => { - if (coletorEncontrado) { - throw new BadRequestExeption(413); - } - }) - .then(() => Coletor.create({ - nome: request.body.nome, - email: request.body.email, - }, transaction)); - sequelize.transaction(callback) - .then(coletor => { - if (!coletor) { - throw new BadRequestExeption(414); - } - response.status(codigos.CADASTRO_SEM_RETORNO).send(); - }) - .catch(next); -}; - -export const buscarColetores = (request, response, next) => { - let where = { - ativo: 1, - }; - let limit = 10; - const { limite, nome } = request.query; - - if (limite) { - limit = parseInt(limite); - } - - if (nome) { - where = { - ...where, - nome: { [Op.like]: `%${nome}%` }, - }; - } - - Promise.resolve() - .then(() => Coletor.findAndCountAll({ - attributes: ['id', 'nome', 'email', 'numero'], - where, - limit, - })) - .then(coletores => { - if (!coletores) { - throw new BadRequestExeption(415); - } - response.status(codigos.LISTAGEM).json(coletores.rows); - }) - .catch(next); -}; - -export const obterTombo = async (request, response, next) => { - try { - if (request.query.recaptchaToken) { - await verifyRecaptcha(request); - } - const id = request.params.tombo_id; - - let resposta = {}; - let dadosTombo = {}; - Promise.resolve() - .then(() => - Tombo.findOne({ - where: { - hcf: id, - ativo: true, - rascunho: 0, - }, - attributes: [ - 'cor', - 'data_coleta_mes', - 'data_coleta_ano', - 'situacao', - 'nome_cientifico', - 'hcf', - 'data_tombo', - 'data_coleta_dia', - 'observacao', - 'nomes_populares', - 'numero_coleta', - 'latitude', - 'longitude', - 'altitude', - 'ativo', - 'rascunho', - 'data_identificacao_dia', - 'data_identificacao_mes', - 'data_identificacao_ano', - 'descricao', - 'unicata', - ], - include: [ - { - model: Herbario, - }, - { - as: 'identificadores', - model: Identificador, - }, - { - model: Solo, - attributes: { - exclude: ['updated_at', 'created_at'], - }, - }, - { - model: Relevo, - attributes: { - exclude: ['updated_at', 'created_at'], - }, - }, - { - model: Vegetacao, - attributes: { - exclude: ['updated_at', 'created_at'], - }, - }, - { - model: LocalColeta, - include: [ - { - model: Cidade, - include: [ - { - model: Estado, - include: [ - { - model: Pais, - }, - ], - }, - ], - }, - { - model: FaseSucessional, - attributes: { - exclude: ['updated_at', 'created_at'], - }, - }, - ], - }, - { - model: Variedade, - include: { - model: Autor, - attributes: { - exclude: ['updated_at', 'created_at', 'ativo'], - }, - as: 'autor', - }, - }, - { - model: Tipo, - attributes: ['id', 'nome'], - }, - { - model: Especie, - include: { - model: Autor, - attributes: { - exclude: ['updated_at', 'created_at', 'ativo'], - }, - as: 'autor', - }, - }, - { - model: ColecaoAnexa, - }, - { - model: Coletor, - attributes: ['id', 'nome'], - }, - { - model: ColetorComplementar, - as: 'coletor_complementar', - attributes: ['complementares'], - }, - { - model: Genero, - }, - { - model: Familia, - }, - { - model: Subfamilia, - }, - { - model: Subespecie, - include: { - model: Autor, - attributes: { - exclude: ['updated_at', 'created_at', 'ativo'], - }, - as: 'autor', - }, - }, - ], - }) - ) - .then(tombo => { - if (!tombo) { - throw new BadRequestExeption(416); - } - - dadosTombo = tombo; - - resposta = { - herbarioInicial: tombo.herbario !== null ? tombo.herbario?.id : '', - localidadeInicial: tombo.cor !== null ? tombo?.cor : '', - tipoInicial: tombo.tipo !== null ? tombo.tipo?.id : '', - paisInicial: tombo.locais_coletum.cidade?.estado?.paise !== null ? tombo.locais_coletum.cidade?.estado?.paise?.id : '', - estadoInicial: tombo.locais_coletum.cidade?.estado !== null ? tombo.locais_coletum.cidade?.estado?.id : '', - cidadeInicial: tombo.locais_coletum.cidade !== null ? tombo.locais_coletum?.cidade?.id : '', - reinoInicial: tombo.reino !== null ? tombo.reino?.id : '', - familiaInicial: tombo.familia !== null ? tombo.familia?.id : '', - subfamiliaInicial: tombo.sub_familia !== null ? tombo.sub_familia?.id : '', - generoInicial: tombo.genero !== null ? tombo.genero?.id : '', - especieInicial: tombo.especy !== null ? tombo.especy?.id : '', - subespecieInicial: tombo.sub_especy !== null ? tombo.sub_especy?.id : '', - variedadeInicial: tombo.variedade !== null ? tombo.variedade?.id : '', - idSoloInicial: tombo.solo !== null ? tombo.solo?.id : '', - soloInicial: tombo.solo !== null ? tombo.solo?.nome : '', - idRelevoInicial: tombo.relevo !== null ? tombo.relevo?.id : '', - relevoInicial: tombo.relevo !== null ? tombo.relevo?.nome : '', - idVegetacaoInicial: tombo.vegetaco !== null ? tombo.vegetaco?.id : '', - vegetacaoInicial: tombo.vegetaco !== null ? tombo.vegetaco?.nome : '', - faseInicial: - tombo.locais_coletum !== null && tombo.locais_coletum?.fase_sucessional !== null ? tombo.locais_coletum?.fase_sucessional?.numero : '', - coletor: tombo.coletore - ? { - id: tombo.coletore?.id, - nome: tombo.coletore?.nome, - } - : null, - colecaoInicial: tombo.colecoes_anexa !== null ? tombo.colecoes_anexa?.tipo : '', - complementoInicial: tombo.localizacao !== null && tombo.localizacao !== undefined ? tombo.localizacao?.complemento : '', - hcf: tombo.hcf, - situacao: tombo.situacao, - data_tombo: tombo.data_tombo, - observacao: tombo.observacao !== null ? tombo.observacao : '', - tipo: tombo.tipo !== null ? tombo.tipo?.nome : '', - numero_coleta: tombo.numero_coleta, - descricao: tombo.descricao !== null ? tombo.descricao : '', - herbario: tombo.herbario !== null ? `${tombo.herbario?.sigla} - ${tombo.herbario?.nome}` : '', - localizacao: { - latitude: tombo.latitude !== null ? tombo.latitude : '', - longitude: tombo.longitude !== null ? tombo.longitude : '', - latitude_graus: tombo.latitude !== null ? converteDecimalParaGraus(tombo.latitude, true).replace('.', ',') : '', - lat_grau: tombo.latitude !== null ? converteDecimalParaGMSGrau(tombo.latitude, true) : '', - latitude_min: tombo.latitude !== null ? converteDecimalParaGMSMinutos(tombo.latitude, true) : '', - latitude_sec: tombo.latitude !== null ? converteDecimalParaGMSSegundos(tombo.latitude, true) : '', - longitude_graus: tombo.longitude !== null ? converteDecimalParaGraus(tombo.longitude, false).replace('.', ',') : '', - long_graus: tombo.longitude !== null ? converteDecimalParaGMSGrau(tombo.longitude, false) : '', - long_min: tombo.longitude !== null ? converteDecimalParaGMSMinutos(tombo.longitude, false) : '', - long_sec: tombo.longitude !== null ? converteDecimalParaGMSSegundos(tombo.longitude, false) : '', - altitude: tombo.altitude !== null ? tombo.altitude : '', - cidade: tombo.locais_coletum !== null && tombo.locais_coletum.cidade !== null ? tombo.locais_coletum?.cidade?.nome : '', - estado: tombo.locais_coletum !== null && tombo.locais_coletum.cidade !== null ? tombo.locais_coletum.cidade?.estado?.nome : '', - pais: tombo.locais_coletum !== null && tombo.locais_coletum.cidade !== null ? tombo.locais_coletum.cidade.estado?.paise?.nome : '', - cor: tombo.cor !== null ? tombo.cor : '', - complemento: tombo.locais_coletum?.complemento !== null ? tombo.locais_coletum?.complemento : '', - }, - local_coleta: { - id: tombo.locais_coletum !== null ? tombo.locais_coletum?.id : '', - descricao: tombo.locais_coletum !== null && tombo.locais_coletum?.descricao !== null ? tombo.locais_coletum.descricao : '', - solo: tombo.solo !== null ? tombo.solo?.nome : '', - relevo: tombo.relevo !== null ? tombo.relevo?.nome : '', - vegetacao: tombo.vegetaco !== null ? tombo.vegetaco?.nome : '', - fase_sucessional: - tombo.locais_coletum !== null && tombo.locais_coletum?.fase_sucessional !== null ? tombo.locais_coletum?.fase_sucessional : '', - }, - taxonomia: { - nome_cientifico: tombo.nome_cientifico !== null ? tombo.nome_cientifico : '', - nome_popular: tombo.nomes_populares !== null ? tombo.nomes_populares : '', - reino: tombo.reino !== null ? tombo.reino?.nome : '', - familia: tombo.familia !== null ? tombo.familia?.nome : '', - sub_familia: tombo.sub_familia !== null ? tombo.sub_familia?.nome : '', - genero: tombo.genero !== null ? tombo.genero?.nome : '', - especie: { - nome: tombo.especy !== null ? tombo.especy?.nome : '', - autor: tombo.especy !== null && tombo.especy?.autor !== null ? tombo.especy?.autor?.nome : '', - }, - sub_especie: { - nome: tombo.sub_especy !== null ? tombo.sub_especy?.nome : '', - autor: tombo.sub_especy !== null && tombo.sub_especy?.autor !== null ? tombo.sub_especy?.autor?.nome : '', - }, - variedade: { - nome: tombo.variedade !== null ? tombo.variedade?.nome : '', - autor: tombo.variedade !== null && tombo.variedade?.autor !== null ? tombo.variedade?.autor?.nome : '', - }, - }, - colecao_anexa: { - tipo: tombo.colecoes_anexa !== null ? tombo.colecoes_anexa?.tipo : '', - observacao: tombo.colecoes_anexa !== null ? tombo.colecoes_anexa?.observacoes : '', - }, - unicata: tombo.unicata ?? null, - }; - let dataCol = ''; - let dataIdent = ''; - - const [tomboIdentificador] = tombo.identificadores; - - if (tombo.data_identificacao_dia !== null) { - dataIdent = `${tombo.data_identificacao_dia}/`; - resposta.data_identificacao_dia = tombo.data_identificacao_dia; - } - if (tombo.data_identificacao_mes !== null) { - dataIdent += `${converteInteiroParaRomano(tombo.data_identificacao_mes)}/`; - resposta.data_identificacao_mes = tombo.data_identificacao_mes; - } - if (tombo.data_identificacao_ano !== null) { - dataIdent += `${tombo.data_identificacao_ano}`; - resposta.data_identificacao_ano = tombo.data_identificacao_ano; - } - - if (tomboIdentificador) { - resposta.identificador_nome = padronizarNomeDarwincore(tomboIdentificador?.nome); - resposta.identificadorInicial = `${tomboIdentificador.id}`; - } else { - resposta.identificadorInicial = ''; - } - - if (tombo.data_coleta_dia !== null) { - dataCol = tombo.data_coleta_dia; - resposta.data_coleta_dia = tombo.data_coleta_dia; - } - if (tombo.data_coleta_mes !== null) { - dataCol += `/${converteInteiroParaRomano(tombo.data_coleta_mes)}`; - resposta.data_coleta_mes = tombo.data_coleta_mes; - } - if (tombo.data_coleta_ano !== null) { - dataCol += `/${tombo.data_coleta_ano}`; - resposta.data_coleta_ano = tombo.data_coleta_ano; - } - - resposta.data_coleta = dataCol; - resposta.data_identificacao = dataIdent === 'undefined' ? '' : dataIdent; - - if (tombo.coletores != null) { - resposta.coletores = tombo.coletores; - } - resposta.retorno = tombo; - return resposta; - }) - .then(() => - Estado.findAll({ - where: { - pais_id: dadosTombo.locais_coletum.cidade?.estado?.paise?.id, - }, - }) - ) - // eslint-disable-next-line no-return-assign - .then(estados => (resposta.estados = estados)) - .then(() => - Cidade.findAll({ - where: { - estado_id: dadosTombo.locais_coletum.cidade?.estado?.id, - }, - }) - ) - // eslint-disable-next-line no-return-assign - .then(cidades => (resposta.cidades = cidades)) - .then(() => - Familia.findAll({ - where: { - id: dadosTombo.familia?.id, - }, - }) - ) - .then(familias => { - resposta.familias = familias; - }) - .then(() => { - if (dadosTombo.familia) { - return Subfamilia.findAll({ - where: { - familia_id: dadosTombo.familia?.id, - }, - include: [ - { - model: Autor, - attributes: ['id', 'nome'], - as: 'autor', - }, - ], - }); - } - return undefined; - }) - .then(subfamilias => { - if (subfamilias) { - resposta.subfamilias = subfamilias; - } else { - resposta.subfamilias = []; - } - }) - .then(() => { - if (dadosTombo.familia) { - return Genero.findAll({ - where: { - familia_id: dadosTombo.familia?.id, - }, - }); - } - return undefined; - }) - .then(generos => { - if (generos) { - resposta.generos = generos; - } else { - resposta.generos = []; - } - }) - .then(() => { - if (dadosTombo.genero) { - return Especie.findAll({ - where: { - genero_id: dadosTombo.genero?.id, - }, - include: [ - { - model: Autor, - attributes: ['id', 'nome'], - as: 'autor', - }, - ], - }); - } - return undefined; - }) - .then(especies => { - if (especies) { - resposta.especies = especies; - } else { - resposta.especies = []; - } - }) - .then(() => { - if (dadosTombo.especy) { - return Subespecie.findAll({ - where: { - especie_id: dadosTombo.especy?.id, - }, - include: [ - { - model: Autor, - attributes: ['id', 'nome'], - as: 'autor', - }, - ], - }); - } - return undefined; - }) - .then(subespecies => { - if (subespecies) { - resposta.subespecies = subespecies; - } else { - resposta.subespecies = []; - } - }) - .then(() => { - if (dadosTombo.especy) { - return Variedade.findAll({ - where: { - especie_id: dadosTombo.especy?.id, - }, - include: [ - { - model: Autor, - attributes: ['id', 'nome'], - as: 'autor', - }, - ], - }); - } - return undefined; - }) - .then(variedades => { - if (variedades) { - resposta.variedades = variedades; - } else { - resposta.variedades = []; - } - }) - .then(() => - Alteracao.findOne({ - where: { - tombo_hcf: dadosTombo.hcf, - status: 'APROVADO', - identificacao: true, - }, - order: [['created_at', 'DESC']], - }) - ) - .then(alter => { - if (alter) { - resposta.identificacao = alter; - } - }) - .then(() => - TomboFoto.findAll({ - where: { - tombo_hcf: id, - ativo: 1, - }, - attributes: ['id', 'caminho_foto', 'em_vivo'], - }) - ) - .then(fotos => { - const formatoFotos = []; - const fotosExsicata = []; - const fotosEmVivo = []; - - // eslint-disable-next-line no-plusplus - for (let i = 0; i < fotos.length; i++) { - if (!fotos[i].em_vivo) { - fotosExsicata.push({ - id: fotos[i].id, - original: fotos[i].caminho_foto, - thumbnail: fotos[i].caminho_foto, - }); - } else { - fotosEmVivo.push({ - id: fotos[i].id, - original: fotos[i].caminho_foto, - thumbnail: fotos[i].caminho_foto, - }); - } - } - resposta.fotos_exsicata = fotosExsicata; - resposta.fotos_vivo = fotosEmVivo; - fotos.map(foto => - formatoFotos.push({ - id: foto.id, - original: foto.caminho_foto, - thumbnail: foto.caminho_foto, - }) - ); - resposta.fotos = formatoFotos; - response.status(codigos.BUSCAR_UM_ITEM).json(resposta); - }) - .catch(next); - } catch (err) { - next(err); - } -}; - -export const getNumeroTombo = (request, response, next) => { - const { id } = request.params; - Promise.resolve() - .then(() => Tombo.findAll({ - where: { - hcf: { [Op.like]: `%${id}%` }, - }, - attributes: [ - 'hcf', - ], - })) - .then(tombos => { - response.status(codigos.BUSCAR_UM_ITEM) - .json(tombos); - }) - .catch(next); -}; - -export const getNumeroColetor = (request, response, next) => { - const { idColetor } = request.params; - - Promise.resolve() - .then(() => - Tombo.findAll({ - where: { - coletor_id: idColetor, - }, - attributes: ['hcf', 'numero_coleta'], - }) - ) - .then(tombos => { - response.status(codigos.BUSCAR_UM_ITEM).json(tombos); - }) - .catch(next); -}; - -export const getUltimoNumeroTombo = (request, response, next) => { - Promise.resolve() - .then(() => Tombo.findAll({ - attributes: [ - 'hcf', - ], - })) - .then(tombos => { - const maximo = Math.max(...tombos.map(e => e.hcf)); - const tombo = {}; - tombo.hcf = maximo; - Tombo.findOne({ - where: { - hcf: maximo, - }, - attributes: [ - 'hcf', - 'data_tombo', - ], - }).then(tomboDate => { - response.status(codigos.BUSCAR_UM_ITEM) - .json(tomboDate); - }); - }) - .catch(next); -}; - -export async function deletarCodigoBarras(request, response, next) { - try { - const count = await TomboFoto.destroy({ - where: { num_barra: request.params.codigo }, - }); - - if (count === 0) { - return response.status(404).json({ error: 'Código de barras não encontrado' }); - } - return response.status(204).end(); - } catch (err) { - return next(err); - } -} - -export const getUltimoCodigoBarra = async (req, res, next) => { - try { - const row = await TomboFoto.findOne({ - attributes: ['id', 'codigo_barra', 'num_barra', 'caminho_foto'], - order: [ - ['tombo_hcf', 'DESC'], - ['num_barra', 'DESC'], - ['id', 'DESC'], - ], - }); - return res.status(codigos.BUSCAR_UM_ITEM).json(row || null); - } catch (err) { - return next(err); - } -}; - -const toHCFFormat = codigo => { - const codigoStr = String(codigo || '').padStart(9, '0'); - return `HCF${codigoStr}`; -}; - -export const postCodigoBarraTombo = (request, response, next) => { - const criarTransacaoCodigoBarra = transaction => - Promise.resolve().then(() => { - const { hcf, codigo_barra: codigoBarra } = request.body || {}; - - const formattedCodigoBarra = toHCFFormat(codigoBarra); - if (!formattedCodigoBarra) { - throw new BadRequestExeption(417); - } - - const payload = { - tombo_hcf: hcf, - em_vivo: true, - codigo_barra: formattedCodigoBarra, - num_barra: codigoBarra, - caminho_foto: null, - }; - - return TomboFoto.create(payload, { transaction }); - }); - - return sequelize - .transaction(criarTransacaoCodigoBarra) - .then(foto => response.status(201).json(foto)) - .catch(err => { - if (err instanceof ForeignKeyConstraintError) { - return response.status(400).json({ error: 'Violação de chave estrangeira.' }); - } - return next(err); - }); -}; - -export const getUltimoNumeroCodigoBarras = (request, response, next) => { - const { emVivo } = request.params; - Promise.resolve() - .then(() => TomboFoto.findAll({ - where: { - em_vivo: emVivo, - }, - attributes: [ - 'id', - 'codigo_barra', - 'num_barra', - 'caminho_foto', - ], - })) - .then(codBarras => { - const maximoCodBarras = Math.max(...codBarras.map(e => e.id)); - response.status(codigos.BUSCAR_UM_ITEM) - .json(maximoCodBarras); - }) - .catch(next); -}; - -export const getCodigoBarraTombo = (request, response, next) => { - const { idTombo } = request.params; - Promise.resolve() - .then(() => TomboFoto.findAll({ - where: { - tombo_hcf: idTombo, - }, - attributes: [ - 'id', - 'codigo_barra', - 'num_barra', - 'caminho_foto', - ], - })) - .then(tombos => { - response.status(codigos.BUSCAR_UM_ITEM) - .json(tombos); - }) - .catch(next); -}; - -export const atualizaCodigoBarra = (codBarra, novoCod) => TomboFoto.update({ - num_barra: novoCod.numBarra, - codigo_barra: novoCod.codBarra, -}, { - where: { - codigo_barra: codBarra, - }, -}); - -export const editarCodigoBarra = (request, response, next) => { - const { body } = request; - Promise.resolve() - .then(() => atualizaCodigoBarra(body.codBarra, body.novoCod)) - .then(retorno => { - if (!retorno) { - throw new BadRequestExeption(111); - } - response.status(codigos.EDITAR_SEM_RETORNO).send(); - }) - .catch(next); -}; - -export default {}; +/* eslint-disable quotes */ +// @ts-nocheck +import { ForeignKeyConstraintError } from 'sequelize'; + +import { padronizarNomeDarwincore } from '~/helpers/padroniza-nome-darwincore'; + +import BadRequestExeption from '../errors/bad-request-exception'; +import NotFoundException from '../errors/not-found-exception'; +import { + converteParaDecimal, converteDecimalParaGraus, converteDecimalParaGMSGrau, converteDecimalParaGMSMinutos, converteDecimalParaGMSSegundos, +} from '../helpers/coordenadas'; +import pick from '../helpers/pick'; +import { converteInteiroParaRomano } from '../helpers/tombo'; +import models from '../models'; +import codigos from '../resources/codigos-http'; +import verifyRecaptcha from '../utils/verify-recaptcha'; +import { aprovarPendencia } from './pendencias-controller'; + +const { + Solo, Relevo, Cidade, Estado, Vegetacao, FaseSucessional, Pais, Tipo, LocalColeta, Familia, sequelize, + Genero, Subfamilia, Autor, Coletor, Variedade, Subespecie, TomboFoto, Identificador, + ColecaoAnexa, Especie, Herbario, Tombo, Alteracao, TomboIdentificador, ColetorComplementar, Sequelize: { Op }, +} = models; + +function parseDataTombo(valor) { + const partes = valor.split(/[-]/).map(p => p.trim()); + if (partes.length >= 3) { + const [anoStr, mesStr, diaStr] = partes; + const dia = parseInt(diaStr, 10); + const mes = parseInt(mesStr, 10) - 1; + const ano = parseInt(anoStr, 10); + if (!Number.isNaN(dia) && !Number.isNaN(mes) && !Number.isNaN(ano)) { + return new Date(ano, mes, dia, 12, 0, 0, 0); + } + return null; + } + return null; +} + +export const cadastro = (request, response, next) => { + const { + principal, + taxonomia, + localidade, + paisagem, + identificacao, + coletor, + // eslint-disable-next-line @typescript-eslint/naming-convention + coletor_complementar, + colecoes_anexas: colecoesAnexas, + observacoes, + unicata, + } = request.body.json; + let tomboCriado = null; + + const callback = transaction => + Promise.resolve() + .then(() => { + if (!paisagem || !paisagem.solo_id) { + return undefined; + } + + const where = { + id: paisagem.solo_id, + }; + + return Solo.findOne({ where, transaction }); + }) + .then(solo => { + if (paisagem && paisagem.solo_id) { + if (!solo) { + throw new BadRequestExeption(528); + } + } + if (paisagem && paisagem.relevo_id) { + return Relevo.findOne({ + where: { + id: paisagem.relevo_id, + }, + transaction, + }); + } + return undefined; + }) + .then(relevo => { + if (paisagem && paisagem.relevo_id) { + if (!relevo) { + throw new BadRequestExeption(529); + } + } + if (paisagem && paisagem.vegetacao_id) { + return Vegetacao.findOne({ + where: { + id: paisagem.vegetacao_id, + }, + transaction, + }); + } + return undefined; + }) + .then(vegetacao => { + if (paisagem && paisagem.vegetacao_id) { + if (!vegetacao) { + throw new BadRequestExeption(530); + } + } + if (paisagem && paisagem.fase_sucessional_id) { + return FaseSucessional.findOne({ + where: { + numero: paisagem.fase_sucessional_id, + }, + transaction, + }); + } + return undefined; + }) + .then(fase => { + if (paisagem && paisagem.fase_sucessional_id) { + if (!fase) { + throw new BadRequestExeption(531); + } + } + return undefined; + }) + .then(() => { + if (!localidade?.local_coleta_id) { + throw new BadRequestExeption(400); + } + return LocalColeta.findOne({ + where: { + id: localidade.local_coleta_id, + }, + transaction, + }); + }) + .then(localColeta => { + if (!localColeta) { + throw new BadRequestExeption(533); + } + return undefined; + }) + // //////////////CRIA COLECOES ANEXAS/////////// + .then(() => { + if (colecoesAnexas) { + const object = pick(colecoesAnexas, ['tipo', 'observacoes']); + return ColecaoAnexa.create(object, { transaction }); + } + return undefined; + }) + .then(colecao => { + if (colecoesAnexas) { + if (!colecao) { + throw new BadRequestExeption(401); + } + colecoesAnexas.id = colecao.id; + } + return undefined; + }) + // ///////// VALIDA A TAXONOMIA E A INSERE NO NOME CIENTIFICO ////////// + .then(() => { + if (taxonomia && taxonomia.familia_id) { + return Familia.findOne({ + where: { + id: taxonomia.familia_id, + }, + transaction, + }); + } + return undefined; + }) + .then(familia => { + if (taxonomia && taxonomia.familia_id) { + if (!familia) { + throw new BadRequestExeption(402); + } + } + return undefined; + }) + .then(() => { + if (taxonomia && taxonomia.sub_familia_id) { + return Subfamilia.findOne({ + where: { + id: taxonomia.sub_familia_id, + familia_id: taxonomia.familia_id, + }, + transaction, + }); + } + return undefined; + }) + .then(subfamilia => { + if (taxonomia && taxonomia.sub_familia_id) { + if (!subfamilia) { + throw new BadRequestExeption(403); + } + } + return undefined; + }) + .then(() => { + if (taxonomia && taxonomia.genero_id) { + return Genero.findOne({ + where: { + id: taxonomia.genero_id, + familia_id: taxonomia.familia_id, + }, + transaction, + }); + } + return undefined; + }) + .then(genero => { + if (taxonomia && taxonomia.genero_id) { + if (!genero) { + throw new BadRequestExeption(404); + } + taxonomia.nome_cientifico = genero.nome; + } + return undefined; + }) + .then(() => { + if (taxonomia && taxonomia.especie_id) { + return Especie.findOne({ + where: { + id: taxonomia.especie_id, + genero_id: taxonomia.genero_id, + }, + transaction, + }); + } + return undefined; + }) + .then(especie => { + if (taxonomia && taxonomia.especie_id) { + if (!especie) { + throw new BadRequestExeption(405); + } + taxonomia.nome_cientifico += ` ${especie.nome}`; + } + return undefined; + }) + .then(() => { + if (taxonomia && taxonomia.sub_especie_id) { + return Subespecie.findOne({ + where: { + id: taxonomia.sub_especie_id, + especie_id: taxonomia.especie_id, + }, + transaction, + }); + } + return undefined; + }) + .then(subespecie => { + if (taxonomia && taxonomia.sub_especie_id) { + if (!subespecie) { + throw new BadRequestExeption(406); + } + } + return undefined; + }) + .then(() => { + if (taxonomia && taxonomia.variedade_id) { + return Variedade.findOne({ + where: { + id: taxonomia.variedade_id, + especie_id: taxonomia.especie_id, + }, + transaction, + }); + } + return undefined; + }) + .then(variedade => { + if (taxonomia && taxonomia.variedade_id) { + if (!variedade) { + throw new BadRequestExeption(407); + } + } + return undefined; + }) + // /////////// CADASTRA TOMBO ///////////// + .then(() => { + let jsonTombo = { + data_coleta_dia: principal.data_coleta.dia, + data_coleta_mes: principal.data_coleta.mes, + data_coleta_ano: principal.data_coleta.ano, + numero_coleta: principal.numero_coleta, + local_coleta_id: localidade.local_coleta_id, + cor: principal.cor || null, + coletor_id: coletor, + data_tombo: parseDataTombo(principal.data_tombo), + }; + + if (paisagem?.descricao) { + jsonTombo.descricao = paisagem.descricao; + } + + if (observacoes) { + jsonTombo.observacao = observacoes; + } + if (unicata !== undefined) { + jsonTombo.unicata = unicata; + } + if (principal.nome_popular) { + jsonTombo.nomes_populares = principal.nome_popular; + } + if (localidade.latitude) { + jsonTombo.latitude = converteParaDecimal(localidade.latitude); + } + if (localidade.longitude) { + jsonTombo.longitude = converteParaDecimal(localidade.longitude); + } + if (localidade.altitude) { + jsonTombo.altitude = localidade.altitude; + } + if (identificacao) { + jsonTombo.data_identificacao_dia = identificacao.data_identificacao?.dia; + jsonTombo.data_identificacao_mes = identificacao.data_identificacao?.mes; + jsonTombo.data_identificacao_ano = identificacao.data_identificacao?.ano; + } + if (paisagem) { + jsonTombo.solo_id = paisagem.solo_id; + jsonTombo.relevo_id = paisagem.relevo_id; + jsonTombo.vegetacao_id = paisagem.vegetacao_id; + } + jsonTombo = { + ...jsonTombo, + ...pick(principal, ['entidade_id', 'tipo_id', 'taxon_id']), + }; + if (taxonomia) { + jsonTombo = { + ...jsonTombo, + // eslint-disable-next-line max-len + ...pick(taxonomia, ['nome_cientifico', 'variedade_id', 'especie_id', 'genero_id', 'familia_id', 'sub_familia_id', 'sub_especie_id']), + }; + } + if (colecoesAnexas && colecoesAnexas.id) { + jsonTombo.colecao_anexa_id = colecoesAnexas.id; + } + if (request.usuario.tipo_usuario_id === 2 || request.usuario.tipo_usuario_id === 3) { + jsonTombo.rascunho = true; + } + return Tombo.create(jsonTombo, { transaction }); + }) + // //////////// CADASTRA A ALTERACAO /////////// + .then(tombo => { + if (!tombo) { + throw new BadRequestExeption(408); + } + let status = 'ESPERANDO'; + principal.hcf = tombo.hcf; + if (request.usuario.tipo_usuario_id === 1) { + status = 'APROVADO'; + } + + const dadosComplementares = coletor_complementar?.complementares || ''; + + const tomboData = { ...tombo.toJSON(), complementares: dadosComplementares, colecoes_anexas_tipo: colecoesAnexas?.tipo || null, colecoes_anexas_observacoes: colecoesAnexas?.observacoes || null }; + + if (identificacao?.identificadores && identificacao.identificadores.length > 0) { + tomboData.identificadores = identificacao.identificadores; + } + + const dados = { + tombo_hcf: tombo.hcf, + usuario_id: request.usuario.id, + status, + tombo_json: JSON.stringify(tomboData), + ativo: true, + identificacao: 0, + }; + tomboCriado = tombo; + + return Alteracao.create(dados, { transaction }).then(alteracaoTomboCriado => { + if (!alteracaoTomboCriado) { + throw new BadRequestExeption(409); + } + + if (coletor_complementar && coletor_complementar.complementares) { + const jsonColetorComplementar = { + hcf: principal.hcf, + complementares: coletor_complementar.complementares, + }; + + return ColetorComplementar.create(jsonColetorComplementar, { transaction }); + } + + return alteracaoTomboCriado; + }); + }) + // /////////////// CADASTRA O INDETIFICADOR /////////////// + .then(alteracaoTomboCriado => { + if (!alteracaoTomboCriado) { + throw new BadRequestExeption(409); + } + if (tomboCriado !== null) { + if (identificacao && identificacao.identificadores && identificacao.identificadores.length > 0) { + const promises = identificacao.identificadores.map((identificador_id, index) => { + const isPrincipal = index === 0; + const dadosIdentificadores = { + identificador_id, + tombo_hcf: tomboCriado.hcf, + ordem: index + 1, + principal: isPrincipal, + }; + return TomboIdentificador.create(dadosIdentificadores, { + transaction, + }); + }); + return Promise.all(promises); + } + } + return undefined; + }); + + sequelize.transaction(callback) + .then(() => { + response.status(codigos.CADASTRO_RETORNO).json({ + hcf: principal.hcf, + }); + }) + .catch(next); +}; + +function alteracaoIdentificador(request, transaction) { + const { + familia_id: familiaId, subfamilia_id: subfamiliaId, genero_id: generoId, + especie_id: especieId, subespecie_id: subespecieId, variedade_id: variedadeId, + } = request.body; + const { tombo_id: tomboId } = request.params; + const update = {}; + + if (familiaId !== undefined) { + update.familia_id = familiaId; + } + if (subfamiliaId !== undefined) { + update.subfamilia_id = subfamiliaId; + } + if (generoId !== undefined) { + update.genero_id = generoId; + } + if (especieId !== undefined) { + update.especie_id = especieId; + } + if (subespecieId !== undefined) { + update.subespecie_id = subespecieId; + } + if (variedadeId !== undefined) { + update.variedade_id = variedadeId; + } + + return Promise.resolve() + .then(() => Alteracao.create({ + tombo_hcf: tomboId, + usuario_id: request.usuario.id, + status: 'ESPERANDO', + tombo_json: JSON.stringify(update), + ativo: true, + identificacao: 1, + }, { transaction })) + .then(alteracaoIdent => { + if (request.usuario.tipo_usuario_id === 3) { + if (!alteracaoIdent) { + throw new BadRequestExeption(421); + } + } + }); +} + +function alteracaoCuradorouOperador(request, response, transaction) { + const { body } = request; + const update = {}; + + const nomePopular = body?.principal?.nome_popular; + if (nomePopular !== undefined) update.nomes_populares = nomePopular; + + const entidadeId = body?.principal?.entidade_id; + if (entidadeId !== undefined) update.entidade_id = entidadeId; + + const numeroColeta = body?.principal?.numero_coleta; + if (numeroColeta !== undefined) update.numero_coleta = numeroColeta; + + const dataColeta = body?.principal?.data_coleta; + if (dataColeta?.dia !== undefined) update.data_coleta_dia = dataColeta.dia; + if (dataColeta?.mes !== undefined) update.data_coleta_mes = dataColeta.mes; + if (dataColeta?.ano !== undefined) update.data_coleta_ano = dataColeta.ano; + + const tipoId = body?.principal?.tipo_id; + if (tipoId !== undefined) update.tipo_id = tipoId; + + const { cor } = body.principal || {}; + if (cor !== undefined) update.cor = cor; + + const dataTombo = body?.principal?.data_tombo; + if (dataTombo !== undefined) update.data_tombo = parseDataTombo(dataTombo); + + const familiaId = body?.taxonomia?.familia_id; + if (familiaId !== undefined) update.familia_id = familiaId; + + const subfamiliaId = body?.taxonomia?.sub_familia_id; + if (subfamiliaId !== undefined) update.sub_familia_id = subfamiliaId; + + const generoId = body?.taxonomia?.genero_id; + if (generoId !== undefined) update.genero_id = generoId; + + const especieId = body?.taxonomia?.especie_id; + if (especieId !== undefined) update.especie_id = especieId; + + const subespecieId = body?.taxonomia?.sub_especie_id; + if (subespecieId !== undefined) update.sub_especie_id = subespecieId; + + const variedadeId = body?.taxonomia?.variedade_id; + if (variedadeId !== undefined) update.variedade_id = variedadeId; + + const latitude = body?.localidade?.latitude; + if (latitude !== undefined) { + update.latitude = latitude ? converteParaDecimal(latitude) : null; + } + + const longitude = body?.localidade?.longitude; + if (longitude !== undefined) { + update.longitude = longitude ? converteParaDecimal(longitude) : null; + } + + const altitude = body?.localidade?.altitude; + if (altitude !== undefined) update.altitude = altitude; + + const localColeta = body?.localidade?.local_coleta_id; + if (localColeta !== undefined) update.local_coleta_id = localColeta; + + const soloId = body?.paisagem?.solo_id; + if (soloId !== undefined) update.solo_id = soloId; + + const relevoId = body?.paisagem?.relevo_id; + if (relevoId !== undefined) update.relevo_id = relevoId; + + const vegetacaoId = body?.paisagem?.vegetacao_id; + if (vegetacaoId !== undefined) update.vegetacao_id = vegetacaoId; + + const descricao = body?.paisagem?.descricao; + if (descricao !== undefined) update.descricao = descricao; + + const unicata = body?.unicata; + if (unicata !== undefined) update.unicata = unicata; + + const faseSucessionalId = body?.paisagem?.fase_sucessional_id; + if (faseSucessionalId !== undefined) update.fase_sucessional_id = faseSucessionalId; + + const identificadores = body?.identificacao?.identificadores; + if (identificadores !== undefined) update.identificadores = identificadores; + + const dataIdentificacao = body?.identificacao?.data_identificacao; + if (dataIdentificacao?.dia !== undefined) update.data_identificacao_dia = dataIdentificacao.dia; + if (dataIdentificacao?.mes !== undefined) update.data_identificacao_mes = dataIdentificacao.mes; + if (dataIdentificacao?.ano !== undefined) update.data_identificacao_ano = dataIdentificacao.ano; + if (dataIdentificacao === null) { + update.data_identificacao_dia = null; + update.data_identificacao_mes = null; + update.data_identificacao_ano = null; + } + + const coletor = body?.coletor; + if (coletor !== undefined) update.coletor_id = coletor; + + const complementares = body?.coletor_complementar?.complementares; + if (complementares !== undefined) update.complementares = complementares; + + const colecoesAnexasTipo = body?.colecoes_anexas?.tipo; + if (colecoesAnexasTipo !== undefined) update.colecoes_anexas_tipo = colecoesAnexasTipo; + + const colecoesAnexasObservacoes = body?.colecoes_anexas?.observacoes; + if (colecoesAnexasObservacoes !== undefined) update.colecoes_anexas_observacoes = colecoesAnexasObservacoes; + + const { observacoes } = body || {}; + if (observacoes !== undefined) update.observacao = observacoes; + + const { tombo_id: tomboId } = request.params; + + return Alteracao.create({ + tombo_hcf: tomboId, + usuario_id: request.usuario.id, + status: 'ESPERANDO', + tombo_json: JSON.stringify(update), + ativo: true, + identificacao: 1, + }, { transaction }) + .then(alteracaoCriada => { + if (request.usuario.tipo_usuario_id === 1) { + return aprovarPendencia(update, tomboId, transaction) + .then(() => Alteracao.update({ status: 'APROVADO' }, { + where: { id: alteracaoCriada.id }, + transaction, + })) + .then(() => alteracaoCriada.toJSON()); + } if (request.usuario.tipo_usuario_id !== 2) { + throw new BadRequestExeption(421); + } + return alteracaoCriada.toJSON(); + }); +} + +export function alteracao(request, response, next) { + return sequelize.transaction(transaction => { + if (request.usuario.tipo_usuario_id === 3) { + return alteracaoIdentificador(request, transaction); + } if (request.usuario.tipo_usuario_id === 1 || request.usuario.tipo_usuario_id === 2) { + return alteracaoCuradorouOperador(request, response, transaction); + } + throw new BadRequestExeption(421); + + }) + .then(() => { + response.status(codigos.EDITAR_SEM_RETORNO).send(); + }) + .catch(next); +} + +export const desativar = (request, response, next) => { + const { params } = request; + + Promise.resolve() + .then(() => { + const where = { + ativo: true, + hcf: params.tombo_id, + }; + + return Tombo.findOne({ where }); + }) + .then(tombo => { + if (!tombo) { + throw new NotFoundException(416); + } + + const where = { + ativo: true, + hcf: params.tombo_id, + }; + + return Tombo.update({ ativo: false }, { where }); + }) + .then(() => { + response.status(204) + .send(); + }) + .catch(next); +}; + +export const listagem = (request, response, next) => { + const { pagina, limite, offset } = request.paginacao; + const { + nome_cientifico: nomeCientifico, hcf, tipo, nome_popular: nomePopular, situacao, + } = request.query; + let where = { + ativo: true, + rascunho: 0, + }; + + if (nomeCientifico) { + where = { + ...where, + nome_cientifico: { [Op.like]: `%${nomeCientifico}%` }, + }; + } + + if (hcf) { + where = { + ...where, + hcf, + }; + } + + if (tipo) { + where = { + ...where, + tipo_id: tipo, + }; + } + + if (nomePopular) { + where = { + ...where, + nomes_populares: { [Op.like]: `%${nomePopular}%` }, + }; + } + + if (situacao) { + where = { + ...where, + situacao, + }; + } + + let retorno = { // eslint-disable-line + metadados: { + total: 0, + pagina, + limite, + }, + tombos: [], + }; + Promise.resolve() + .then(() => Tombo.count({ where })) + .then(total => { + retorno.metadados.total = total; + }) + .then(() => Tombo.findAndCountAll({ + attributes: [ + 'hcf', + 'nomes_populares', + 'nome_cientifico', + 'data_coleta_dia', + 'data_coleta_mes', + 'data_coleta_ano', + 'created_at', + ], + include: { + // required: true, + model: Coletor, + attributes: ['id', 'nome'], + }, + where, + order: [['hcf', 'DESC']], + limit: limite, + offset, + })) + .then(listaTombos => { + retorno.tombos = listaTombos.rows; + response.status(codigos.LISTAGEM) + .json(retorno); + }) + .catch(next); +}; + +export const getDadosCadTombo = (request, response, next) => { + const retorno = {}; + const callback = transaction => Promise.resolve() + .then(() => Tombo.findAndCountAll({ + attributes: ['hcf', 'numero_coleta'], + order: [['numero_coleta', 'DESC']], + transaction, + })) + .then(tombos => { + if (!tombos) { + throw new BadRequestExeption(202); + } + retorno.numero_coleta = (tombos.rows[0].numero_coleta) + 1; + }) + .then(() => Herbario.findAndCountAll({ + attributes: ['id', 'nome', 'sigla'], + where: { + ativo: true, + }, + order: [['nome', 'ASC']], + transaction, + })) + .then(herbario => { + if (!herbario) { + throw new BadRequestExeption(203); + } + retorno.herbarios = herbario.rows; + }) + .then(() => Tipo.findAndCountAll({ + attributes: ['id', 'nome'], + order: [['nome', 'ASC']], + transaction, + })) + .then(tipos => { + if (!tipos) { + throw new BadRequestExeption(204); + } + retorno.tipos = tipos.rows; + }) + .then(() => Pais.findAndCountAll({ + order: [['nome', 'ASC']], + transaction, + })) + .then(paises => { + if (!paises) { + throw new BadRequestExeption(205); + } + retorno.paises = paises.rows; + }) + .then(() => Familia.findAndCountAll({ + attributes: ['id', 'nome'], + order: [['nome', 'ASC']], + where: { + ativo: true, + }, + transaction, + })) + .then(familias => { + if (!familias) { + throw new BadRequestExeption(206); + } + retorno.familias = familias.rows; + }) + .then(() => Solo.findAndCountAll({ + attributes: ['id', 'nome'], + order: [['nome', 'ASC']], + transaction, + })) + .then(solos => { + if (!solos) { + throw new BadRequestExeption(207); + } + retorno.solos = solos.rows; + }) + .then(() => Relevo.findAndCountAll({ + attributes: ['id', 'nome'], + order: [['nome', 'ASC']], + transaction, + })) + .then(relevos => { + if (!relevos) { + throw new BadRequestExeption(208); + } + retorno.relevos = relevos.rows; + }) + .then(() => Vegetacao.findAndCountAll({ + attributes: ['id', 'nome'], + order: [['nome', 'ASC']], + transaction, + })) + .then(vegetacoes => { + if (!vegetacoes) { + throw new BadRequestExeption(209); + } + retorno.vegetacoes = vegetacoes.rows; + }) + .then(() => FaseSucessional.findAndCountAll({ + attributes: ['numero', 'nome'], + order: [['nome', 'ASC']], + transaction, + })) + .then(fases => { + if (!fases) { + throw new BadRequestExeption(210); + } + retorno.fases = fases.rows; + }) + .then(() => Autor.findAndCountAll({ + attributes: ['id', 'nome'], + order: [['nome', 'ASC']], + where: { + ativo: true, + }, + transaction, + })) + .then(autores => { + if (!autores) { + throw new BadRequestExeption(213); + } + retorno.autores = autores.rows; + return retorno; + }); + sequelize.transaction(callback) + .then(() => { + response.status(codigos.BUSCAR_VARIOS_ITENS) + .json(retorno); + + }) + .catch(next); +}; + +export const cadastrarTipo = (request, response, next) => { + const callback = transaction => Promise.resolve() + .then(() => Tipo.findOne({ + where: { + nome: request.body.nome, + }, + transaction, + })) + .then(tipoEncontrado => { + if (tipoEncontrado) { + throw new BadRequestExeption(412); + } + }) + .then(() => Tipo.create( + { + nome: request.body.nome, + }, + transaction + )); + sequelize.transaction(callback) + .then(() => { + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarTipos = (request, response, next) => { + Promise.resolve() + .then(() => Tipo.findAndCountAll({ + attributes: ['id', 'nome'], + })) + .then(tipos => { + response.status(codigos.LISTAGEM).json(tipos.rows); + }) + .catch(next); +}; + +export const cadastrarColetores = (request, response, next) => { + const callback = transaction => Promise.resolve() + .then(() => Coletor.findOne({ + where: { + nome: request.body.nome, + email: request.body.email, + }, + transaction, + })) + .then(coletorEncontrado => { + if (coletorEncontrado) { + throw new BadRequestExeption(413); + } + }) + .then(() => Coletor.create({ + nome: request.body.nome, + email: request.body.email, + }, transaction)); + sequelize.transaction(callback) + .then(coletor => { + if (!coletor) { + throw new BadRequestExeption(414); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarColetores = (request, response, next) => { + let where = { + ativo: 1, + }; + let limit = 10; + const { limite, nome } = request.query; + + if (limite) { + limit = parseInt(limite); + } + + if (nome) { + where = { + ...where, + nome: { [Op.like]: `%${nome}%` }, + }; + } + + Promise.resolve() + .then(() => Coletor.findAndCountAll({ + attributes: ['id', 'nome', 'email', 'numero'], + where, + limit, + })) + .then(coletores => { + if (!coletores) { + throw new BadRequestExeption(415); + } + response.status(codigos.LISTAGEM).json(coletores.rows); + }) + .catch(next); +}; + +export const obterTombo = async (request, response, next) => { + try { + if (request.query.recaptchaToken) { + await verifyRecaptcha(request); + } + const id = request.params.tombo_id; + + let resposta = {}; + let dadosTombo = {}; + Promise.resolve() + .then(() => + Tombo.findOne({ + where: { + hcf: id, + ativo: true, + rascunho: 0, + }, + attributes: [ + 'cor', + 'data_coleta_mes', + 'data_coleta_ano', + 'situacao', + 'nome_cientifico', + 'hcf', + 'data_tombo', + 'data_coleta_dia', + 'observacao', + 'nomes_populares', + 'numero_coleta', + 'latitude', + 'longitude', + 'altitude', + 'ativo', + 'rascunho', + 'data_identificacao_dia', + 'data_identificacao_mes', + 'data_identificacao_ano', + 'descricao', + 'unicata', + ], + include: [ + { + model: Herbario, + }, + { + as: 'identificadores', + model: Identificador, + }, + { + model: Solo, + attributes: { + exclude: ['updated_at', 'created_at'], + }, + }, + { + model: Relevo, + attributes: { + exclude: ['updated_at', 'created_at'], + }, + }, + { + model: Vegetacao, + attributes: { + exclude: ['updated_at', 'created_at'], + }, + }, + { + model: LocalColeta, + include: [ + { + model: Cidade, + include: [ + { + model: Estado, + include: [ + { + model: Pais, + }, + ], + }, + ], + }, + { + model: FaseSucessional, + attributes: { + exclude: ['updated_at', 'created_at'], + }, + }, + ], + }, + { + model: Variedade, + include: { + model: Autor, + attributes: { + exclude: ['updated_at', 'created_at', 'ativo'], + }, + as: 'autor', + }, + }, + { + model: Tipo, + attributes: ['id', 'nome'], + }, + { + model: Especie, + include: { + model: Autor, + attributes: { + exclude: ['updated_at', 'created_at', 'ativo'], + }, + as: 'autor', + }, + }, + { + model: ColecaoAnexa, + }, + { + model: Coletor, + attributes: ['id', 'nome'], + }, + { + model: ColetorComplementar, + as: 'coletor_complementar', + attributes: ['complementares'], + }, + { + model: Genero, + }, + { + model: Familia, + }, + { + model: Subfamilia, + }, + { + model: Subespecie, + include: { + model: Autor, + attributes: { + exclude: ['updated_at', 'created_at', 'ativo'], + }, + as: 'autor', + }, + }, + ], + }) + ) + .then(tombo => { + if (!tombo) { + throw new BadRequestExeption(416); + } + + dadosTombo = tombo; + + resposta = { + herbarioInicial: tombo.herbario !== null ? tombo.herbario?.id : '', + localidadeInicial: tombo.cor !== null ? tombo?.cor : '', + tipoInicial: tombo.tipo !== null ? tombo.tipo?.id : '', + paisInicial: tombo.locais_coletum.cidade?.estado?.paise !== null ? tombo.locais_coletum.cidade?.estado?.paise?.id : '', + estadoInicial: tombo.locais_coletum.cidade?.estado !== null ? tombo.locais_coletum.cidade?.estado?.id : '', + cidadeInicial: tombo.locais_coletum.cidade !== null ? tombo.locais_coletum?.cidade?.id : '', + reinoInicial: tombo.reino !== null ? tombo.reino?.id : '', + familiaInicial: tombo.familia !== null ? tombo.familia?.id : '', + subfamiliaInicial: tombo.sub_familia !== null ? tombo.sub_familia?.id : '', + generoInicial: tombo.genero !== null ? tombo.genero?.id : '', + especieInicial: tombo.especy !== null ? tombo.especy?.id : '', + subespecieInicial: tombo.sub_especy !== null ? tombo.sub_especy?.id : '', + variedadeInicial: tombo.variedade !== null ? tombo.variedade?.id : '', + idSoloInicial: tombo.solo !== null ? tombo.solo?.id : '', + soloInicial: tombo.solo !== null ? tombo.solo?.nome : '', + idRelevoInicial: tombo.relevo !== null ? tombo.relevo?.id : '', + relevoInicial: tombo.relevo !== null ? tombo.relevo?.nome : '', + idVegetacaoInicial: tombo.vegetaco !== null ? tombo.vegetaco?.id : '', + vegetacaoInicial: tombo.vegetaco !== null ? tombo.vegetaco?.nome : '', + faseInicial: + tombo.locais_coletum !== null && tombo.locais_coletum?.fase_sucessional !== null ? tombo.locais_coletum?.fase_sucessional?.numero : '', + coletor: tombo.coletore + ? { + id: tombo.coletore?.id, + nome: tombo.coletore?.nome, + } + : null, + colecaoInicial: tombo.colecoes_anexa !== null ? tombo.colecoes_anexa?.tipo : '', + complementoInicial: tombo.localizacao !== null && tombo.localizacao !== undefined ? tombo.localizacao?.complemento : '', + hcf: tombo.hcf, + situacao: tombo.situacao, + data_tombo: tombo.data_tombo, + observacao: tombo.observacao !== null ? tombo.observacao : '', + tipo: tombo.tipo !== null ? tombo.tipo?.nome : '', + numero_coleta: tombo.numero_coleta, + descricao: tombo.descricao !== null ? tombo.descricao : '', + herbario: tombo.herbario !== null ? `${tombo.herbario?.sigla} - ${tombo.herbario?.nome}` : '', + localizacao: { + latitude: tombo.latitude !== null ? tombo.latitude : '', + longitude: tombo.longitude !== null ? tombo.longitude : '', + latitude_graus: tombo.latitude !== null ? converteDecimalParaGraus(tombo.latitude, true).replace('.', ',') : '', + lat_grau: tombo.latitude !== null ? converteDecimalParaGMSGrau(tombo.latitude, true) : '', + latitude_min: tombo.latitude !== null ? converteDecimalParaGMSMinutos(tombo.latitude, true) : '', + latitude_sec: tombo.latitude !== null ? converteDecimalParaGMSSegundos(tombo.latitude, true) : '', + longitude_graus: tombo.longitude !== null ? converteDecimalParaGraus(tombo.longitude, false).replace('.', ',') : '', + long_graus: tombo.longitude !== null ? converteDecimalParaGMSGrau(tombo.longitude, false) : '', + long_min: tombo.longitude !== null ? converteDecimalParaGMSMinutos(tombo.longitude, false) : '', + long_sec: tombo.longitude !== null ? converteDecimalParaGMSSegundos(tombo.longitude, false) : '', + altitude: tombo.altitude !== null ? tombo.altitude : '', + cidade: tombo.locais_coletum !== null && tombo.locais_coletum.cidade !== null ? tombo.locais_coletum?.cidade?.nome : '', + estado: tombo.locais_coletum !== null && tombo.locais_coletum.cidade !== null ? tombo.locais_coletum.cidade?.estado?.nome : '', + pais: tombo.locais_coletum !== null && tombo.locais_coletum.cidade !== null ? tombo.locais_coletum.cidade.estado?.paise?.nome : '', + cor: tombo.cor !== null ? tombo.cor : '', + complemento: tombo.locais_coletum?.complemento !== null ? tombo.locais_coletum?.complemento : '', + }, + local_coleta: { + id: tombo.locais_coletum !== null ? tombo.locais_coletum?.id : '', + descricao: tombo.locais_coletum !== null && tombo.locais_coletum?.descricao !== null ? tombo.locais_coletum.descricao : '', + solo: tombo.solo !== null ? tombo.solo?.nome : '', + relevo: tombo.relevo !== null ? tombo.relevo?.nome : '', + vegetacao: tombo.vegetaco !== null ? tombo.vegetaco?.nome : '', + fase_sucessional: + tombo.locais_coletum !== null && tombo.locais_coletum?.fase_sucessional !== null ? tombo.locais_coletum?.fase_sucessional : '', + }, + taxonomia: { + nome_cientifico: tombo.nome_cientifico !== null ? tombo.nome_cientifico : '', + nome_popular: tombo.nomes_populares !== null ? tombo.nomes_populares : '', + reino: tombo.reino !== null ? tombo.reino?.nome : '', + familia: tombo.familia !== null ? tombo.familia?.nome : '', + sub_familia: tombo.sub_familia !== null ? tombo.sub_familia?.nome : '', + genero: tombo.genero !== null ? tombo.genero?.nome : '', + especie: { + nome: tombo.especy !== null ? tombo.especy?.nome : '', + autor: tombo.especy !== null && tombo.especy?.autor !== null ? tombo.especy?.autor?.nome : '', + }, + sub_especie: { + nome: tombo.sub_especy !== null ? tombo.sub_especy?.nome : '', + autor: tombo.sub_especy !== null && tombo.sub_especy?.autor !== null ? tombo.sub_especy?.autor?.nome : '', + }, + variedade: { + nome: tombo.variedade !== null ? tombo.variedade?.nome : '', + autor: tombo.variedade !== null && tombo.variedade?.autor !== null ? tombo.variedade?.autor?.nome : '', + }, + }, + colecao_anexa: { + tipo: tombo.colecoes_anexa !== null ? tombo.colecoes_anexa?.tipo : '', + observacao: tombo.colecoes_anexa !== null ? tombo.colecoes_anexa?.observacoes : '', + }, + unicata: tombo.unicata ?? null, + }; + let dataCol = ''; + let dataIdent = ''; + + const [tomboIdentificador] = tombo.identificadores; + + if (tombo.data_identificacao_dia !== null) { + dataIdent = `${tombo.data_identificacao_dia}/`; + resposta.data_identificacao_dia = tombo.data_identificacao_dia; + } + if (tombo.data_identificacao_mes !== null) { + dataIdent += `${converteInteiroParaRomano(tombo.data_identificacao_mes)}/`; + resposta.data_identificacao_mes = tombo.data_identificacao_mes; + } + if (tombo.data_identificacao_ano !== null) { + dataIdent += `${tombo.data_identificacao_ano}`; + resposta.data_identificacao_ano = tombo.data_identificacao_ano; + } + + if (tomboIdentificador) { + resposta.identificador_nome = padronizarNomeDarwincore(tomboIdentificador?.nome); + resposta.identificadorInicial = `${tomboIdentificador.id}`; + } else { + resposta.identificadorInicial = ''; + } + + if (tombo.data_coleta_dia !== null) { + dataCol = tombo.data_coleta_dia; + resposta.data_coleta_dia = tombo.data_coleta_dia; + } + if (tombo.data_coleta_mes !== null) { + dataCol += `/${converteInteiroParaRomano(tombo.data_coleta_mes)}`; + resposta.data_coleta_mes = tombo.data_coleta_mes; + } + if (tombo.data_coleta_ano !== null) { + dataCol += `/${tombo.data_coleta_ano}`; + resposta.data_coleta_ano = tombo.data_coleta_ano; + } + + resposta.data_coleta = dataCol; + resposta.data_identificacao = dataIdent === 'undefined' ? '' : dataIdent; + + if (tombo.coletores != null) { + resposta.coletores = tombo.coletores; + } + resposta.retorno = tombo; + return resposta; + }) + .then(() => + Estado.findAll({ + where: { + pais_id: dadosTombo.locais_coletum.cidade?.estado?.paise?.id, + }, + }) + ) + // eslint-disable-next-line no-return-assign + .then(estados => (resposta.estados = estados)) + .then(() => + Cidade.findAll({ + where: { + estado_id: dadosTombo.locais_coletum.cidade?.estado?.id, + }, + }) + ) + // eslint-disable-next-line no-return-assign + .then(cidades => (resposta.cidades = cidades)) + .then(() => + Familia.findAll({ + where: { + id: dadosTombo.familia?.id, + }, + }) + ) + .then(familias => { + resposta.familias = familias; + }) + .then(() => { + if (dadosTombo.familia) { + return Subfamilia.findAll({ + where: { + familia_id: dadosTombo.familia?.id, + }, + include: [ + { + model: Autor, + attributes: ['id', 'nome'], + as: 'autor', + }, + ], + }); + } + return undefined; + }) + .then(subfamilias => { + if (subfamilias) { + resposta.subfamilias = subfamilias; + } else { + resposta.subfamilias = []; + } + }) + .then(() => { + if (dadosTombo.familia) { + return Genero.findAll({ + where: { + familia_id: dadosTombo.familia?.id, + }, + }); + } + return undefined; + }) + .then(generos => { + if (generos) { + resposta.generos = generos; + } else { + resposta.generos = []; + } + }) + .then(() => { + if (dadosTombo.genero) { + return Especie.findAll({ + where: { + genero_id: dadosTombo.genero?.id, + }, + include: [ + { + model: Autor, + attributes: ['id', 'nome'], + as: 'autor', + }, + ], + }); + } + return undefined; + }) + .then(especies => { + if (especies) { + resposta.especies = especies; + } else { + resposta.especies = []; + } + }) + .then(() => { + if (dadosTombo.especy) { + return Subespecie.findAll({ + where: { + especie_id: dadosTombo.especy?.id, + }, + include: [ + { + model: Autor, + attributes: ['id', 'nome'], + as: 'autor', + }, + ], + }); + } + return undefined; + }) + .then(subespecies => { + if (subespecies) { + resposta.subespecies = subespecies; + } else { + resposta.subespecies = []; + } + }) + .then(() => { + if (dadosTombo.especy) { + return Variedade.findAll({ + where: { + especie_id: dadosTombo.especy?.id, + }, + include: [ + { + model: Autor, + attributes: ['id', 'nome'], + as: 'autor', + }, + ], + }); + } + return undefined; + }) + .then(variedades => { + if (variedades) { + resposta.variedades = variedades; + } else { + resposta.variedades = []; + } + }) + .then(() => + Alteracao.findOne({ + where: { + tombo_hcf: dadosTombo.hcf, + status: 'APROVADO', + identificacao: true, + }, + order: [['created_at', 'DESC']], + }) + ) + .then(alter => { + if (alter) { + resposta.identificacao = alter; + } + }) + .then(() => + TomboFoto.findAll({ + where: { + tombo_hcf: id, + ativo: 1, + }, + attributes: ['id', 'caminho_foto', 'em_vivo'], + }) + ) + .then(fotos => { + const formatoFotos = []; + const fotosExsicata = []; + const fotosEmVivo = []; + + // eslint-disable-next-line no-plusplus + for (let i = 0; i < fotos.length; i++) { + if (!fotos[i].em_vivo) { + fotosExsicata.push({ + id: fotos[i].id, + original: fotos[i].caminho_foto, + thumbnail: fotos[i].caminho_foto, + }); + } else { + fotosEmVivo.push({ + id: fotos[i].id, + original: fotos[i].caminho_foto, + thumbnail: fotos[i].caminho_foto, + }); + } + } + resposta.fotos_exsicata = fotosExsicata; + resposta.fotos_vivo = fotosEmVivo; + fotos.map(foto => + formatoFotos.push({ + id: foto.id, + original: foto.caminho_foto, + thumbnail: foto.caminho_foto, + }) + ); + resposta.fotos = formatoFotos; + response.status(codigos.BUSCAR_UM_ITEM).json(resposta); + }) + .catch(next); + } catch (err) { + next(err); + } +}; + +export const getNumeroTombo = (request, response, next) => { + const { id } = request.params; + Promise.resolve() + .then(() => Tombo.findAll({ + where: { + hcf: { [Op.like]: `%${id}%` }, + }, + attributes: [ + 'hcf', + ], + })) + .then(tombos => { + response.status(codigos.BUSCAR_UM_ITEM) + .json(tombos); + }) + .catch(next); +}; + +export const getNumeroColetor = (request, response, next) => { + const { idColetor } = request.params; + + Promise.resolve() + .then(() => + Tombo.findAll({ + where: { + coletor_id: idColetor, + }, + attributes: ['hcf', 'numero_coleta'], + }) + ) + .then(tombos => { + response.status(codigos.BUSCAR_UM_ITEM).json(tombos); + }) + .catch(next); +}; + +export const getUltimoNumeroTombo = (request, response, next) => { + Promise.resolve() + .then(() => Tombo.findAll({ + attributes: [ + 'hcf', + ], + })) + .then(tombos => { + const maximo = Math.max(...tombos.map(e => e.hcf)); + const tombo = {}; + tombo.hcf = maximo; + Tombo.findOne({ + where: { + hcf: maximo, + }, + attributes: [ + 'hcf', + 'data_tombo', + ], + }).then(tomboDate => { + response.status(codigos.BUSCAR_UM_ITEM) + .json(tomboDate); + }); + }) + .catch(next); +}; + +export async function deletarCodigoBarras(request, response, next) { + try { + const count = await TomboFoto.destroy({ + where: { num_barra: request.params.codigo }, + }); + + if (count === 0) { + return response.status(404).json({ error: 'Código de barras não encontrado' }); + } + return response.status(204).end(); + } catch (err) { + return next(err); + } +} + +export const getUltimoCodigoBarra = async (req, res, next) => { + try { + const row = await TomboFoto.findOne({ + attributes: ['id', 'codigo_barra', 'num_barra', 'caminho_foto'], + order: [ + ['tombo_hcf', 'DESC'], + ['num_barra', 'DESC'], + ['id', 'DESC'], + ], + }); + return res.status(codigos.BUSCAR_UM_ITEM).json(row || null); + } catch (err) { + return next(err); + } +}; + +const toHCFFormat = codigo => { + const codigoStr = String(codigo || '').padStart(9, '0'); + return `HCF${codigoStr}`; +}; + +export const postCodigoBarraTombo = (request, response, next) => { + const criarTransacaoCodigoBarra = transaction => + Promise.resolve().then(() => { + const { hcf, codigo_barra: codigoBarra } = request.body || {}; + + const formattedCodigoBarra = toHCFFormat(codigoBarra); + if (!formattedCodigoBarra) { + throw new BadRequestExeption(417); + } + + const payload = { + tombo_hcf: hcf, + em_vivo: true, + codigo_barra: formattedCodigoBarra, + num_barra: codigoBarra, + caminho_foto: null, + }; + + return TomboFoto.create(payload, { transaction }); + }); + + return sequelize + .transaction(criarTransacaoCodigoBarra) + .then(foto => response.status(201).json(foto)) + .catch(err => { + if (err instanceof ForeignKeyConstraintError) { + return response.status(400).json({ error: 'Violação de chave estrangeira.' }); + } + return next(err); + }); +}; + +export const getUltimoNumeroCodigoBarras = (request, response, next) => { + const { emVivo } = request.params; + Promise.resolve() + .then(() => TomboFoto.findAll({ + where: { + em_vivo: emVivo, + }, + attributes: [ + 'id', + 'codigo_barra', + 'num_barra', + 'caminho_foto', + ], + })) + .then(codBarras => { + const maximoCodBarras = Math.max(...codBarras.map(e => e.id)); + response.status(codigos.BUSCAR_UM_ITEM) + .json(maximoCodBarras); + }) + .catch(next); +}; + +export const getCodigoBarraTombo = (request, response, next) => { + const { idTombo } = request.params; + Promise.resolve() + .then(() => TomboFoto.findAll({ + where: { + tombo_hcf: idTombo, + }, + attributes: [ + 'id', + 'codigo_barra', + 'num_barra', + 'caminho_foto', + ], + })) + .then(tombos => { + response.status(codigos.BUSCAR_UM_ITEM) + .json(tombos); + }) + .catch(next); +}; + +export const atualizaCodigoBarra = (codBarra, novoCod) => TomboFoto.update({ + num_barra: novoCod.numBarra, + codigo_barra: novoCod.codBarra, +}, { + where: { + codigo_barra: codBarra, + }, +}); + +export const editarCodigoBarra = (request, response, next) => { + const { body } = request; + Promise.resolve() + .then(() => atualizaCodigoBarra(body.codBarra, body.novoCod)) + .then(retorno => { + if (!retorno) { + throw new BadRequestExeption(111); + } + response.status(codigos.EDITAR_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export default {}; diff --git a/src/controllers/usuarios-controller.js b/src/controllers/usuarios-controller.js index 63bcdb3..9eeaa02 100644 --- a/src/controllers/usuarios-controller.js +++ b/src/controllers/usuarios-controller.js @@ -1,9 +1,10 @@ import { UserRegistrationDTO } from '../dtos/UserRegistrationDTO'; import BadRequestExeption from '../errors/bad-request-exception'; import { comparaSenha, gerarSenha } from '../helpers/senhas'; -import { constroiPayloadUsuario, geraTokenUsuario } from '../helpers/tokens'; +import { constroiPayloadUsuario, geraTokenUsuario, geraTokenResetSenha } from '../helpers/tokens'; import models from '../models'; import codigos from '../resources/codigos-http'; +import nodemailer from 'nodemailer'; const { Sequelize: { Op }, Usuario, TipoUsuario, Coletor, Identificador, @@ -305,4 +306,95 @@ export const atualizarSenha = (request, response, next) => { .catch(next); }; +export const solicitarResetSenha = async (request, response, next) => { + const { email } = request.body; + try { + const usuario = await encontraUsuarioAtivoPorEmail(email); + if (usuario) { + const token = geraTokenResetSenha(usuario.id); + const dataExpiracao = new Date(); + dataExpiracao.setMinutes(dataExpiracao.getMinutes() + 45); + + await Usuario.update({ + reset_token: token, + reset_token_expiration: dataExpiracao, + }, { where: { id: usuario.id } }); + + const transporter = nodemailer.createTransport({ + host: process.env.SMTP_HOST, + port: process.env.SMTP_PORT, + secure: false, + auth: { + user: process.env.SMTP_USER, + pass: process.env.SMTP_PASS, + }, + }); + + const link = `${process.env.URL_PAINEL}reset-senha?token=${token}`; + await transporter.sendMail({ + from: '"Sistema HCF" ', + to: email, + subject: 'Redefinição de senha', + html: ` +

Olá ${usuario.nome},

+

Você solicitou uma redefinição de senha.

+

Não compartilhe esse link.

+

Clique no link abaixo para criar uma nova senha (válido por 45 minutos):

+ ${link} + `, + }); + } + + return response.status(codigos.EDITAR_SEM_RETORNO).send(); + } catch (err) { + next(err); + } +}; + +export const redefinirSenhaComToken = async (request, response, next) => { + const { token, novaSenha } = request.body; + + try { + if (!token || !novaSenha) { + throw new BadRequestExeption(400, 'Token e nova senha são obrigatórios.'); + } + + const usuario = await Usuario.findOne({ + where: { + reset_token: token, + reset_token_expiration: { [Op.gt]: new Date() }, + ativo: true, + }, + }); + + if (!usuario) { + return response.status(400).json({ + sucesso: false, + mensagem: 'Token inválido ou expirado.', + }); + } + + const novaSenhaHash = gerarSenha(novaSenha); + await Usuario.update( + { + senha: novaSenhaHash, + reset_token: null, + reset_token_expiration: null, + }, + { where: { id: usuario.id } } + ); + + return response.status(200).json({ + sucesso: true, + mensagem: 'Senha redefinida com sucesso.', + }); + } catch (err) { + console.error('Erro ao redefinir senha:', err.message); + return response.status(500).json({ + sucesso: false, + mensagem: 'Erro interno ao redefinir senha.', + detalhe: process.env.NODE_ENV === 'development' ? err.message : undefined, + }); + } +}; export default {}; diff --git a/src/database/migration/20251001194607_fix-nome-cientifico.ts b/src/database/migration/20251001194607_fix-nome-cientifico.ts index 582fe7a..a1c20c9 100644 --- a/src/database/migration/20251001194607_fix-nome-cientifico.ts +++ b/src/database/migration/20251001194607_fix-nome-cientifico.ts @@ -1,43 +1,43 @@ -import { Knex } from 'knex' - -export async function run(knex: Knex): Promise { - await knex.transaction(async (trx) => { - const tombos = await trx('tombos') - .select('hcf', 'genero_id', 'especie_id') - .where('hcf', '>=', 42852) - - const updates = tombos.map(async (tombo) => { - let nomeCientifico = null - - if (tombo.genero_id) { - const genero = await trx('generos') - .select('nome') - .where('id', tombo.genero_id) - .first() - - if (genero) { - nomeCientifico = genero.nome - - if (tombo.especie_id) { - const especie = await trx('especies') - .select('nome') - .where('id', tombo.especie_id) - .first() - - if (especie) { - nomeCientifico = `${genero.nome} ${especie.nome}` - } - } - } - } - - return trx('tombos') - .where('hcf', tombo.hcf) - .update({ - nome_cientifico: nomeCientifico - }) - }) - - await Promise.all(updates) - }) -} +import { Knex } from 'knex' + +export async function run(knex: Knex): Promise { + await knex.transaction(async (trx) => { + const tombos = await trx('tombos') + .select('hcf', 'genero_id', 'especie_id') + .where('hcf', '>=', 42852) + + const updates = tombos.map(async (tombo) => { + let nomeCientifico = null + + if (tombo.genero_id) { + const genero = await trx('generos') + .select('nome') + .where('id', tombo.genero_id) + .first() + + if (genero) { + nomeCientifico = genero.nome + + if (tombo.especie_id) { + const especie = await trx('especies') + .select('nome') + .where('id', tombo.especie_id) + .first() + + if (especie) { + nomeCientifico = `${genero.nome} ${especie.nome}` + } + } + } + } + + return trx('tombos') + .where('hcf', tombo.hcf) + .update({ + nome_cientifico: nomeCientifico + }) + }) + + await Promise.all(updates) + }) +} diff --git a/src/database/migration/20251008193832_add-reset-token-to-usuarios.ts b/src/database/migration/20251008193832_add-reset-token-to-usuarios.ts new file mode 100644 index 0000000..ad5bd6b --- /dev/null +++ b/src/database/migration/20251008193832_add-reset-token-to-usuarios.ts @@ -0,0 +1,15 @@ +import { Knex } from 'knex'; + +export async function run(knex: Knex): Promise { + await knex.schema.alterTable('usuarios', table => { + table.string('reset_token').nullable(); + table.timestamp('reset_token_expiration').nullable(); + }); +} + +export async function down(knex: Knex): Promise { + await knex.schema.alterTable('usuarios', table => { + table.dropColumn('reset_token'); + table.dropColumn('reset_token_expiration'); + }); +} diff --git a/src/helpers/tokens.js b/src/helpers/tokens.js index 2525641..cdc91ed 100644 --- a/src/helpers/tokens.js +++ b/src/helpers/tokens.js @@ -26,4 +26,14 @@ export const constroiPayloadUsuario = usuario => { }; }; +export const geraTokenResetSenha = usuarioId => { + const payload = { id: usuarioId }; + const secretReset = secret + '-reset'; + const token = jwt.sign(payload, secretReset, { + expiresIn: '45m', + }); + + return token; +}; + export default {}; diff --git a/src/herbarium/specieslink/tombos.js b/src/herbarium/specieslink/tombos.js index a1e44a9..c30229a 100644 --- a/src/herbarium/specieslink/tombos.js +++ b/src/herbarium/specieslink/tombos.js @@ -1,278 +1,278 @@ -/* Evita o warning de excendo o tamanho da linha */ -/* eslint-disable max-len */ -import Q from 'q'; -import throttledQueue from 'throttled-queue'; - -import { - ehIgualFamilia, - ehIgualGenero, - ehIgualEspecie, - existeAlteracaoSugerida, -} from '../comparainformacao'; -import { - selectUmaInformacaoSpecieslink, - selectNroTomboNumBarra, - selectTombo, - atualizaJaComparouTabelaSpecieslink, - insereAlteracaoSugerida, - selectExisteServicoUsuario, - insereIdentificadorUsuario, -} from '../herbariumdatabase'; -import { - processaRespostaSpecieslink, - temResultadoRespostaSpecieslink, -} from './specieslink'; - -/** - * A função fazComparacaoInformacao, é comparado informações do banco de dados com as que - * estão no Specieslink. As informações a serem comparadas são: família, gênero, - * espécie, subespécie e variedade. Depois de comparar cada uma dessas informações - * quando encontrado divergência é adicionado em um JSON. Após realizar todas as comparações - * ele procurar na tabela de alterações e verifica se encontra um JSON parecido com o - * que está no banco de dados, se for encontrado um JSON igual não é adicionado, - * caso não seja encontrado é adicionado um novo registro na tabela de alterações. - * Além disso, alguns detalhes que vale a pena ressaltar é que não é comparado - * informação da subfamília, isso porque no JSON vindo do Specieslink não é retornado - * informação de subfamília. Foram vistos outros sete herbários (UNOP, HUCP, HUEM, - * DVPR, MBM, UNIP, HUFU) e também não retornam esse tipo de informação. - * Uma última coisa que vale a pena ressaltar é que o script feito pela Elaine para gerar o - * DarwinCore, não é feito consultas ao banco de dados referente a subfamília. - * @param {*} nroTombo, é o número do tombo para serem pesquisadas informações no banco de dados. - * @param {*} codBarra, é o código de barra relacionado ao tombo do HCF a qual será gerado o JSON - * de alteração. - * @param {*} informacaoSpecieslink, informação do tombo que irá ser comparado com as presentes no banco - * de dados. - * @return promessa.promise, como é assíncrono ele só retorna quando resolver, ou seja, - * quando acabar de realizar a comparação de informações. - */ -export async function geraJsonAlteracao(nroTombo, codBarra, informacaoSpecieslink) { - const promessa = Q.defer(); - selectTombo(nroTombo).then(async tomboBd => { - if (tomboBd.length === 0) { - promessa.resolve(); - } - let alteracaoInformacao = '{'; - const processaInformacaoBd = tomboBd[0].dataValues; - // família - if (processaInformacaoBd.familia_id !== null) { - await ehIgualFamilia(processaInformacaoBd.familia_id, informacaoSpecieslink.family).then(familia => { - if (familia !== -1) { - alteracaoInformacao += `"familia_nome": "${familia}", `; - alteracaoInformacao += `"autor": "${informacaoSpecieslink.scientificnameauthorship}", `; - } - }); - } - // gênero - if (processaInformacaoBd.genero_id !== null) { - await ehIgualGenero(processaInformacaoBd.genero_id, informacaoSpecieslink.genus).then(genero => { - if (genero !== -1) { - alteracaoInformacao += `"genero_nome": "${genero}", `; - alteracaoInformacao += `"autor": "${informacaoSpecieslink.scientificnameauthorship}", `; - } - }); - } - // espécie - if (processaInformacaoBd.especie_id !== null) { - await ehIgualEspecie(processaInformacaoBd.especie_id, informacaoSpecieslink.specificepithet).then(especie => { - if (especie !== -1) { - alteracaoInformacao += `"especie_nome": "${especie}", `; - alteracaoInformacao += `"autor": "${informacaoSpecieslink.scientificnameauthorship}", `; - } - }); - } - alteracaoInformacao = alteracaoInformacao.substring(0, alteracaoInformacao.lastIndexOf(',')); - alteracaoInformacao += '}'; - atualizaJaComparouTabelaSpecieslink(codBarra); - promessa.resolve(alteracaoInformacao); - }); - return promessa.promise; -} - -/** - * A função getDiaIdentificacao procura na data que foi passada por parâmetro, - * e verifica se existe um dia de identificação, caso exista a mesma é retornada, - * caso não ache é retornado nulo. - * @param {*} dataIdentificacao, é uma string na qual será procurado o dia de identificação. - * @return valorDiaIdentificacao ou null, retorna o dia que foi feita a identificação caso exista, - * caso contrário retorna nulo. - */ -export function getDiaIdentificacao(dataIdentificacao) { - // O s. d. significa sem determinação - if ((dataIdentificacao.length > 0) && (dataIdentificacao !== null) && (dataIdentificacao !== 's. d.')) { - if (dataIdentificacao.indexOf('/') !== dataIdentificacao.lastIndexOf('/')) { - const valorDiaIdentificacao = dataIdentificacao.substring(0, dataIdentificacao.indexOf('/')); - if (valorDiaIdentificacao.length === 0) { - return null; - } - if (Number.isNaN(parseInt(valorDiaIdentificacao))) { - return null; - } - if (parseInt(valorDiaIdentificacao) > 0 && parseInt(valorDiaIdentificacao) < 32) { - return parseInt(valorDiaIdentificacao); - } - return null; - } - } - return null; -} - -/** - * A função getMesIdentificacao procura na data que foi passada por parâmetro, - * e verifica se existe um mês de identificação, caso exista a mesma é retornada, - * caso não ache é retornado nulo. - * @param {*} dataIdentificacao, é uma string na qual será procurado o mês de identificação. - * @return valorDiaIdentificacao ou null, retorna o mês que foi feita a identificação caso exista, - * caso contrário retorna nulo. - */ -export function getMesIdentificacao(dataIdentificacao) { - // O s. d. significa sem determinação - if ((dataIdentificacao.length > 0) && (dataIdentificacao !== null) && (dataIdentificacao !== 's. d.')) { - if (dataIdentificacao.indexOf('/') !== dataIdentificacao.lastIndexOf('/')) { - const valorMesIdentificacao = dataIdentificacao.substring(dataIdentificacao.indexOf('/') + 1, dataIdentificacao.lastIndexOf('/')); - if (valorMesIdentificacao.length === 0) { - return null; - } - if (Number.isNaN(parseInt(valorMesIdentificacao))) { - return null; - } - return parseInt(valorMesIdentificacao); - } - if (dataIdentificacao.indexOf('/') === dataIdentificacao.lastIndexOf('/')) { - const valorMesIdentificacao = dataIdentificacao.substring(0, dataIdentificacao.lastIndexOf('/')); - if (valorMesIdentificacao.length === 0) { - return null; - } - if (Number.isNaN(parseInt(valorMesIdentificacao))) { - return null; - } - if (parseInt(valorMesIdentificacao) > 0 && parseInt(valorMesIdentificacao) < 13) { - return parseInt(valorMesIdentificacao); - } - return null; - } - } - return null; -} - -/** - * A função getAnoIdentificacao procura na data que foi passada por parâmetro, - * e verifica se existe um ano de identificação, caso exista a mesma é retornada, - * caso não ache é retornado nulo. - * @param {*} dataIdentificacao, é uma string na qual será procurado o ano de identificação. - * @return valorDiaIdentificacao ou null, retorna o ano que foi feita a identificação caso exista, - * caso contrário retorna nulo. - */ -export function getAnoIdentificacao(dataIdentificacao) { - // O s. d. significa sem determinação - if ((dataIdentificacao.length > 0) && (dataIdentificacao !== null) && (dataIdentificacao !== 's. d.')) { - const valorAnoIdentificacao = dataIdentificacao.substring(dataIdentificacao.lastIndexOf('/') + 1, dataIdentificacao.length); - if (valorAnoIdentificacao.length === 0) { - return null; - } - if (Number.isNaN(parseInt(valorAnoIdentificacao))) { - return null; - } - if (parseInt(valorAnoIdentificacao) > 0) { - return parseInt(valorAnoIdentificacao); - } - return null; - } - return null; -} - -/** - * A função fazComparacaoInformacao, primeiramente verifica se tem informações - * do Specieslink esperado. Se tem as informações esperada eu pego o número de tombo - * equivalente aquele tombo de código de barra, e com esse valor de número de tombo - * eu consigo pegar informações relacionadas a esse tombo. Comparando as informações - * vindas do Specieslink com as presentes no banco de dados, eu verifico se me gerou - * um JSON. Quando me retorna JSON, eu verifico se existe essa alteração no banco - * de dados se não existe eu insiro ela no banco de dados. - * @param {*} codBarra, é o código de barra relacionado ao tombo do HCF. - * @param {*} informacaoSpecieslink, informação do tombo que está exposta do Specieslink. - * @return promessa.promise, como é assíncrono ele só retorna quando resolver, ou seja, - * quando acabar de realizar a comparação de informações. - */ -export function fazComparacaoInformacao(codBarra, informacaoSpecieslink) { - const promessa = Q.defer(); - if (temResultadoRespostaSpecieslink(informacaoSpecieslink)) { - selectNroTomboNumBarra(codBarra).then(nroTombo => { - if (nroTombo.length > 0) { - const getNroTombo = nroTombo[0].dataValues.tombo_hcf; - const getInformacaoSpecieslink = informacaoSpecieslink.features[0].properties; - geraJsonAlteracao(getNroTombo, codBarra, getInformacaoSpecieslink).then(alteracao => { - if (alteracao.length > 2) { - existeAlteracaoSugerida(getNroTombo, alteracao).then(existe => { - if (!existe) { - const nomeIdentificador = getInformacaoSpecieslink.identifiedby ?? ''; - selectExisteServicoUsuario(nomeIdentificador).then(listaUsuario => { - if (listaUsuario.length === 0) { - insereIdentificadorUsuario(nomeIdentificador).then(idUsuario => { - const diaIdentificacao = getInformacaoSpecieslink.dayidentified; - const mesIdentificacao = getInformacaoSpecieslink.monthidentified; - const anoIdentificacao = getInformacaoSpecieslink.yearidentified; - insereAlteracaoSugerida(idUsuario, 'ESPERANDO', getNroTombo, alteracao, diaIdentificacao, mesIdentificacao, anoIdentificacao); - // eslint-disable-next-line no-console - console.log(getInformacaoSpecieslink.identifiedby); - // eslint-disable-next-line no-console - console.log(getInformacaoSpecieslink.dateidentified); - }); - } else { - const diaIdentificacao = getInformacaoSpecieslink.dayidentified; - const mesIdentificacao = getInformacaoSpecieslink.monthidentified; - const anoIdentificacao = getInformacaoSpecieslink.yearidentified; - const { id } = listaUsuario[0].dataValues; - insereAlteracaoSugerida(id, 'ESPERANDO', getNroTombo, alteracao, diaIdentificacao, mesIdentificacao, anoIdentificacao); - // eslint-disable-next-line no-console - console.log(getInformacaoSpecieslink.identifiedby); - // eslint-disable-next-line no-console - console.log(getInformacaoSpecieslink.dateidentified); - } - }); - promessa.resolve(); - } - promessa.resolve(); - }); - } - promessa.resolve(); - }); - } - }); - } else { - promessa.resolve(); - } - return promessa.promise; -} - -/** - * A função fazComparacaoTomboSpecieslink, faz um select na tabela do specieslink verificando - * se tem algum tombo que já foi comparado ou não. Se o resultado dessa requisição - * é maior que zero, então eu pego o json e começo a realizar as comparações, e depois - * marco que esse json já foi comparado. Após isso, eu chamo novamente essa função - * e faço isso até com que seja comparado todos os json. - * @return promessa.promise, como é assíncrono ele só retorna quando resolver, ou seja, - * quando acabar de realizar a recursão. - */ -export function fazComparacaoTomboSpecieslink() { - const promessa = Q.defer(); - const throttle = throttledQueue(1, 2000); - selectUmaInformacaoSpecieslink().then(informacaoSpecieslink => { - if (informacaoSpecieslink.length === 0) { - // eslint-disable-next-line no-console - console.log('akc'); - promessa.resolve(true); - } else { - // eslint-disable-next-line no-console - console.log('akd'); - const getCodBarra = informacaoSpecieslink[0].dataValues.cod_barra; - const getInformacaoSpecieslink = processaRespostaSpecieslink(informacaoSpecieslink[0].dataValues.tombo_json); - throttle(() => { - fazComparacaoInformacao(getCodBarra, getInformacaoSpecieslink).then(() => { - atualizaJaComparouTabelaSpecieslink(getCodBarra); - promessa.resolve(fazComparacaoTomboSpecieslink()); - }); - }); - } - }); - return promessa.promise; -} +/* Evita o warning de excendo o tamanho da linha */ +/* eslint-disable max-len */ +import Q from 'q'; +import throttledQueue from 'throttled-queue'; + +import { + ehIgualFamilia, + ehIgualGenero, + ehIgualEspecie, + existeAlteracaoSugerida, +} from '../comparainformacao'; +import { + selectUmaInformacaoSpecieslink, + selectNroTomboNumBarra, + selectTombo, + atualizaJaComparouTabelaSpecieslink, + insereAlteracaoSugerida, + selectExisteServicoUsuario, + insereIdentificadorUsuario, +} from '../herbariumdatabase'; +import { + processaRespostaSpecieslink, + temResultadoRespostaSpecieslink, +} from './specieslink'; + +/** + * A função fazComparacaoInformacao, é comparado informações do banco de dados com as que + * estão no Specieslink. As informações a serem comparadas são: família, gênero, + * espécie, subespécie e variedade. Depois de comparar cada uma dessas informações + * quando encontrado divergência é adicionado em um JSON. Após realizar todas as comparações + * ele procurar na tabela de alterações e verifica se encontra um JSON parecido com o + * que está no banco de dados, se for encontrado um JSON igual não é adicionado, + * caso não seja encontrado é adicionado um novo registro na tabela de alterações. + * Além disso, alguns detalhes que vale a pena ressaltar é que não é comparado + * informação da subfamília, isso porque no JSON vindo do Specieslink não é retornado + * informação de subfamília. Foram vistos outros sete herbários (UNOP, HUCP, HUEM, + * DVPR, MBM, UNIP, HUFU) e também não retornam esse tipo de informação. + * Uma última coisa que vale a pena ressaltar é que o script feito pela Elaine para gerar o + * DarwinCore, não é feito consultas ao banco de dados referente a subfamília. + * @param {*} nroTombo, é o número do tombo para serem pesquisadas informações no banco de dados. + * @param {*} codBarra, é o código de barra relacionado ao tombo do HCF a qual será gerado o JSON + * de alteração. + * @param {*} informacaoSpecieslink, informação do tombo que irá ser comparado com as presentes no banco + * de dados. + * @return promessa.promise, como é assíncrono ele só retorna quando resolver, ou seja, + * quando acabar de realizar a comparação de informações. + */ +export async function geraJsonAlteracao(nroTombo, codBarra, informacaoSpecieslink) { + const promessa = Q.defer(); + selectTombo(nroTombo).then(async tomboBd => { + if (tomboBd.length === 0) { + promessa.resolve(); + } + let alteracaoInformacao = '{'; + const processaInformacaoBd = tomboBd[0].dataValues; + // família + if (processaInformacaoBd.familia_id !== null) { + await ehIgualFamilia(processaInformacaoBd.familia_id, informacaoSpecieslink.family).then(familia => { + if (familia !== -1) { + alteracaoInformacao += `"familia_nome": "${familia}", `; + alteracaoInformacao += `"autor": "${informacaoSpecieslink.scientificnameauthorship}", `; + } + }); + } + // gênero + if (processaInformacaoBd.genero_id !== null) { + await ehIgualGenero(processaInformacaoBd.genero_id, informacaoSpecieslink.genus).then(genero => { + if (genero !== -1) { + alteracaoInformacao += `"genero_nome": "${genero}", `; + alteracaoInformacao += `"autor": "${informacaoSpecieslink.scientificnameauthorship}", `; + } + }); + } + // espécie + if (processaInformacaoBd.especie_id !== null) { + await ehIgualEspecie(processaInformacaoBd.especie_id, informacaoSpecieslink.specificepithet).then(especie => { + if (especie !== -1) { + alteracaoInformacao += `"especie_nome": "${especie}", `; + alteracaoInformacao += `"autor": "${informacaoSpecieslink.scientificnameauthorship}", `; + } + }); + } + alteracaoInformacao = alteracaoInformacao.substring(0, alteracaoInformacao.lastIndexOf(',')); + alteracaoInformacao += '}'; + atualizaJaComparouTabelaSpecieslink(codBarra); + promessa.resolve(alteracaoInformacao); + }); + return promessa.promise; +} + +/** + * A função getDiaIdentificacao procura na data que foi passada por parâmetro, + * e verifica se existe um dia de identificação, caso exista a mesma é retornada, + * caso não ache é retornado nulo. + * @param {*} dataIdentificacao, é uma string na qual será procurado o dia de identificação. + * @return valorDiaIdentificacao ou null, retorna o dia que foi feita a identificação caso exista, + * caso contrário retorna nulo. + */ +export function getDiaIdentificacao(dataIdentificacao) { + // O s. d. significa sem determinação + if ((dataIdentificacao.length > 0) && (dataIdentificacao !== null) && (dataIdentificacao !== 's. d.')) { + if (dataIdentificacao.indexOf('/') !== dataIdentificacao.lastIndexOf('/')) { + const valorDiaIdentificacao = dataIdentificacao.substring(0, dataIdentificacao.indexOf('/')); + if (valorDiaIdentificacao.length === 0) { + return null; + } + if (Number.isNaN(parseInt(valorDiaIdentificacao))) { + return null; + } + if (parseInt(valorDiaIdentificacao) > 0 && parseInt(valorDiaIdentificacao) < 32) { + return parseInt(valorDiaIdentificacao); + } + return null; + } + } + return null; +} + +/** + * A função getMesIdentificacao procura na data que foi passada por parâmetro, + * e verifica se existe um mês de identificação, caso exista a mesma é retornada, + * caso não ache é retornado nulo. + * @param {*} dataIdentificacao, é uma string na qual será procurado o mês de identificação. + * @return valorDiaIdentificacao ou null, retorna o mês que foi feita a identificação caso exista, + * caso contrário retorna nulo. + */ +export function getMesIdentificacao(dataIdentificacao) { + // O s. d. significa sem determinação + if ((dataIdentificacao.length > 0) && (dataIdentificacao !== null) && (dataIdentificacao !== 's. d.')) { + if (dataIdentificacao.indexOf('/') !== dataIdentificacao.lastIndexOf('/')) { + const valorMesIdentificacao = dataIdentificacao.substring(dataIdentificacao.indexOf('/') + 1, dataIdentificacao.lastIndexOf('/')); + if (valorMesIdentificacao.length === 0) { + return null; + } + if (Number.isNaN(parseInt(valorMesIdentificacao))) { + return null; + } + return parseInt(valorMesIdentificacao); + } + if (dataIdentificacao.indexOf('/') === dataIdentificacao.lastIndexOf('/')) { + const valorMesIdentificacao = dataIdentificacao.substring(0, dataIdentificacao.lastIndexOf('/')); + if (valorMesIdentificacao.length === 0) { + return null; + } + if (Number.isNaN(parseInt(valorMesIdentificacao))) { + return null; + } + if (parseInt(valorMesIdentificacao) > 0 && parseInt(valorMesIdentificacao) < 13) { + return parseInt(valorMesIdentificacao); + } + return null; + } + } + return null; +} + +/** + * A função getAnoIdentificacao procura na data que foi passada por parâmetro, + * e verifica se existe um ano de identificação, caso exista a mesma é retornada, + * caso não ache é retornado nulo. + * @param {*} dataIdentificacao, é uma string na qual será procurado o ano de identificação. + * @return valorDiaIdentificacao ou null, retorna o ano que foi feita a identificação caso exista, + * caso contrário retorna nulo. + */ +export function getAnoIdentificacao(dataIdentificacao) { + // O s. d. significa sem determinação + if ((dataIdentificacao.length > 0) && (dataIdentificacao !== null) && (dataIdentificacao !== 's. d.')) { + const valorAnoIdentificacao = dataIdentificacao.substring(dataIdentificacao.lastIndexOf('/') + 1, dataIdentificacao.length); + if (valorAnoIdentificacao.length === 0) { + return null; + } + if (Number.isNaN(parseInt(valorAnoIdentificacao))) { + return null; + } + if (parseInt(valorAnoIdentificacao) > 0) { + return parseInt(valorAnoIdentificacao); + } + return null; + } + return null; +} + +/** + * A função fazComparacaoInformacao, primeiramente verifica se tem informações + * do Specieslink esperado. Se tem as informações esperada eu pego o número de tombo + * equivalente aquele tombo de código de barra, e com esse valor de número de tombo + * eu consigo pegar informações relacionadas a esse tombo. Comparando as informações + * vindas do Specieslink com as presentes no banco de dados, eu verifico se me gerou + * um JSON. Quando me retorna JSON, eu verifico se existe essa alteração no banco + * de dados se não existe eu insiro ela no banco de dados. + * @param {*} codBarra, é o código de barra relacionado ao tombo do HCF. + * @param {*} informacaoSpecieslink, informação do tombo que está exposta do Specieslink. + * @return promessa.promise, como é assíncrono ele só retorna quando resolver, ou seja, + * quando acabar de realizar a comparação de informações. + */ +export function fazComparacaoInformacao(codBarra, informacaoSpecieslink) { + const promessa = Q.defer(); + if (temResultadoRespostaSpecieslink(informacaoSpecieslink)) { + selectNroTomboNumBarra(codBarra).then(nroTombo => { + if (nroTombo.length > 0) { + const getNroTombo = nroTombo[0].dataValues.tombo_hcf; + const getInformacaoSpecieslink = informacaoSpecieslink.features[0].properties; + geraJsonAlteracao(getNroTombo, codBarra, getInformacaoSpecieslink).then(alteracao => { + if (alteracao.length > 2) { + existeAlteracaoSugerida(getNroTombo, alteracao).then(existe => { + if (!existe) { + const nomeIdentificador = getInformacaoSpecieslink.identifiedby ?? ''; + selectExisteServicoUsuario(nomeIdentificador).then(listaUsuario => { + if (listaUsuario.length === 0) { + insereIdentificadorUsuario(nomeIdentificador).then(idUsuario => { + const diaIdentificacao = getInformacaoSpecieslink.dayidentified; + const mesIdentificacao = getInformacaoSpecieslink.monthidentified; + const anoIdentificacao = getInformacaoSpecieslink.yearidentified; + insereAlteracaoSugerida(idUsuario, 'ESPERANDO', getNroTombo, alteracao, diaIdentificacao, mesIdentificacao, anoIdentificacao); + // eslint-disable-next-line no-console + console.log(getInformacaoSpecieslink.identifiedby); + // eslint-disable-next-line no-console + console.log(getInformacaoSpecieslink.dateidentified); + }); + } else { + const diaIdentificacao = getInformacaoSpecieslink.dayidentified; + const mesIdentificacao = getInformacaoSpecieslink.monthidentified; + const anoIdentificacao = getInformacaoSpecieslink.yearidentified; + const { id } = listaUsuario[0].dataValues; + insereAlteracaoSugerida(id, 'ESPERANDO', getNroTombo, alteracao, diaIdentificacao, mesIdentificacao, anoIdentificacao); + // eslint-disable-next-line no-console + console.log(getInformacaoSpecieslink.identifiedby); + // eslint-disable-next-line no-console + console.log(getInformacaoSpecieslink.dateidentified); + } + }); + promessa.resolve(); + } + promessa.resolve(); + }); + } + promessa.resolve(); + }); + } + }); + } else { + promessa.resolve(); + } + return promessa.promise; +} + +/** + * A função fazComparacaoTomboSpecieslink, faz um select na tabela do specieslink verificando + * se tem algum tombo que já foi comparado ou não. Se o resultado dessa requisição + * é maior que zero, então eu pego o json e começo a realizar as comparações, e depois + * marco que esse json já foi comparado. Após isso, eu chamo novamente essa função + * e faço isso até com que seja comparado todos os json. + * @return promessa.promise, como é assíncrono ele só retorna quando resolver, ou seja, + * quando acabar de realizar a recursão. + */ +export function fazComparacaoTomboSpecieslink() { + const promessa = Q.defer(); + const throttle = throttledQueue(1, 2000); + selectUmaInformacaoSpecieslink().then(informacaoSpecieslink => { + if (informacaoSpecieslink.length === 0) { + // eslint-disable-next-line no-console + console.log('akc'); + promessa.resolve(true); + } else { + // eslint-disable-next-line no-console + console.log('akd'); + const getCodBarra = informacaoSpecieslink[0].dataValues.cod_barra; + const getInformacaoSpecieslink = processaRespostaSpecieslink(informacaoSpecieslink[0].dataValues.tombo_json); + throttle(() => { + fazComparacaoInformacao(getCodBarra, getInformacaoSpecieslink).then(() => { + atualizaJaComparouTabelaSpecieslink(getCodBarra); + promessa.resolve(fazComparacaoTomboSpecieslink()); + }); + }); + } + }); + return promessa.promise; +} diff --git a/src/models/Usuario.js b/src/models/Usuario.js index e5daf2f..ffad918 100644 --- a/src/models/Usuario.js +++ b/src/models/Usuario.js @@ -70,6 +70,14 @@ export default (Sequelize, DataTypes) => { allowNull: false, defaultValue: true, }, + reset_token: { + type: DataTypes.STRING, + allowNull: true, + }, + reset_token_expiration: { + type: DataTypes.DATE, + allowNull: true, + }, }; const options = { diff --git a/src/routes/usuarios.js b/src/routes/usuarios.js index b1073b8..01c4502 100644 --- a/src/routes/usuarios.js +++ b/src/routes/usuarios.js @@ -1,483 +1,557 @@ -import listagensMiddleware from '../middlewares/listagens-middleware'; -import tokensMiddleware, { TIPOS_USUARIOS } from '../middlewares/tokens-middleware'; -import validacoesMiddleware from '../middlewares/validacoes-middleware'; -import atualizarUsuarioEsquema from '../validators/usuario-atualiza'; -import atualizarSenhaEsquema from '../validators/usuario-atualiza-senha'; -import cadastrarUsuarioEsquema from '../validators/usuario-cadastro'; -import desativarUsuarioEsquema from '../validators/usuario-desativa'; -import listagemUsuarioEsquema from '../validators/usuario-listagem'; -import usuarioLoginEsquema from '../validators/usuario-login'; - -const controller = require('../controllers/usuarios-controller'); - -/** - * @swagger - * tags: - * name: Usuários - * description: Operações relacionadas aos usuários - */ -export default app => { - /** - * @swagger - * /login: - * post: - * summary: Realiza login do usuário - * tags: [Usuários] - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * email: - * type: string - * senha: - * type: string - * required: - * - email - * - senha - * example: - * email: "usuario@email.com" - * senha: "senha123" - * responses: - * 200: - * description: Login realizado com sucesso - * content: - * application/json: - * schema: - * type: object - * properties: - * token: - * type: string - * usuario: - * type: object - * properties: - * id: - * type: integer - * nome: - * type: string - * email: - * type: string - * tipo_usuario_id: - * type: integer - * '400': - * $ref: '#/components/responses/BadRequest' - * '401': - * $ref: '#/components/responses/Unauthorized' - * '500': - * $ref: '#/components/responses/InternalServerError' - */ - app.route('/login') - .post([ - validacoesMiddleware(usuarioLoginEsquema), - controller.login, - ]); - - /** - * @swagger - * /coletores-predicao: - * get: - * summary: Lista coletores para predição - * tags: [Usuários] - * responses: - * 200: - * description: Lista de coletores retornada com sucesso - * content: - * application/json: - * schema: - * type: array - * items: - * type: object - * properties: - * id: - * type: integer - * description: ID do coletor - * nome: - * type: string - * description: Nome do coletor - * '401': - * $ref: '#/components/responses/Unauthorized' - * '403': - * $ref: '#/components/responses/Forbidden' - * '500': - * $ref: '#/components/responses/InternalServerError' - */ - app.route('/coletores-predicao') - .get([ - tokensMiddleware([ - TIPOS_USUARIOS.CURADOR, - TIPOS_USUARIOS.OPERADOR, - ]), - controller.obtemColetores, - ]); - - /** - * @swagger - * /identificadores-predicao: - * get: - * summary: Lista identificadores para predição - * tags: [Usuários] - * responses: - * 200: - * description: Lista de identificadores retornada com sucesso - * content: - * application/json: - * schema: - * type: array - * items: - * type: object - * properties: - * id: - * type: integer - * description: ID do identificador - * nome: - * type: string - * description: Nome do identificador - * '401': - * $ref: '#/components/responses/Unauthorized' - * '403': - * $ref: '#/components/responses/Forbidden' - * '500': - * $ref: '#/components/responses/InternalServerError' - */ - app.route('/identificadores-predicao') - .get([ - tokensMiddleware([ - TIPOS_USUARIOS.CURADOR, - TIPOS_USUARIOS.OPERADOR, - TIPOS_USUARIOS.IDENTIFICADOR, - ]), - controller.obtemIdentificadores, - ]); - - /** - * @swagger - * /usuarios: - * get: - * summary: Lista todos os usuários - * tags: [Usuários] - * responses: - * 200: - * description: Lista de usuários retornada com sucesso - * content: - * application/json: - * schema: - * type: object - * properties: - * metadados: - * type: object - * properties: - * total: - * type: integer - * pagina: - * type: integer - * limite: - * type: integer - * usuarios: - * type: array - * items: - * type: object - * properties: - * id: - * type: integer - * nome: - * type: string - * telefone: - * type: string - * ra: - * type: string - * nullable: true - * email: - * type: string - * tipos_usuario: - * type: object - * properties: - * id: - * type: integer - * tipo: - * type: string - * created_at: - * type: string - * format: date-time - * '401': - * $ref: '#/components/responses/Unauthorized' - * '403': - * $ref: '#/components/responses/Forbidden' - * '500': - * $ref: '#/components/responses/InternalServerError' - * post: - * summary: Cadastra um novo usuário - * tags: [Usuários] - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * nome: - * type: string - * minLength: 1 - * email: - * type: string - * format: email - * minLength: 1 - * senha: - * type: string - * minLength: 1 - * tipo_usuario_id: - * type: integer - * herbario_id: - * type: integer - * required: - * - nome - * - email - * - senha - * - tipo_usuario_id - * - herbario_id - * example: - * nome: "Novo Usuário" - * email: "novo@email.com" - * senha: "senha123" - * tipo_usuario_id: 2 - * herbario_id: 1 - * responses: - * 201: - * description: Usuário cadastrado com sucesso - * content: - * application/json: - * schema: - * type: object - * example: - * id: 2 - * nome: "Novo Usuário" - * email: "novo@email.com" - * '400': - * $ref: '#/components/responses/BadRequest' - * '401': - * $ref: '#/components/responses/Unauthorized' - * '403': - * $ref: '#/components/responses/Forbidden' - * '500': - * $ref: '#/components/responses/InternalServerError' - */ - app.route('/usuarios') - .get([ - tokensMiddleware([ - TIPOS_USUARIOS.CURADOR, - ]), - validacoesMiddleware(listagemUsuarioEsquema), - listagensMiddleware, - controller.listagem, - ]) - .post([ - tokensMiddleware([ - TIPOS_USUARIOS.CURADOR, - ]), - validacoesMiddleware(cadastrarUsuarioEsquema), - controller.cadastro, - ]); - - /** - * @swagger - * /usuarios/{usuario_id}: - * put: - * summary: Edita um usuário - * tags: [Usuários] - * parameters: - * - in: path - * name: usuario_id - * required: true - * schema: - * type: integer - * description: ID do usuário - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * nome: - * type: string - * email: - * type: string - * required: - * - nome - * - email - * example: - * nome: "Usuário Editado" - * email: "editado@email.com" - * responses: - * 200: - * description: Usuário editado com sucesso - * content: - * application/json: - * schema: - * type: object - * example: - * id: 1 - * nome: "Usuário Editado" - * email: "editado@email.com" - * '400': - * $ref: '#/components/responses/BadRequest' - * '401': - * $ref: '#/components/responses/Unauthorized' - * '403': - * $ref: '#/components/responses/Forbidden' - * '404': - * $ref: '#/components/responses/NotFound' - * '500': - * $ref: '#/components/responses/InternalServerError' - * get: - * summary: Busca um usuário pelo ID - * tags: [Usuários] - * parameters: - * - in: path - * name: usuario_id - * required: true - * schema: - * type: integer - * description: ID do usuário - * responses: - * 200: - * description: Dados do usuário encontrados - * content: - * application/json: - * schema: - * type: object - * properties: - * id: - * type: integer - * nome: - * type: string - * telefone: - * type: string - * ra: - * type: string - * nullable: true - * email: - * type: string - * herbario_id: - * type: integer - * tipos_usuario: - * type: object - * properties: - * id: - * type: integer - * tipo: - * type: string - * '401': - * $ref: '#/components/responses/Unauthorized' - * '403': - * $ref: '#/components/responses/Forbidden' - * '404': - * $ref: '#/components/responses/NotFound' - * '500': - * $ref: '#/components/responses/InternalServerError' - * delete: - * summary: Remove um usuário - * tags: [Usuários] - * parameters: - * - in: path - * name: usuario_id - * required: true - * schema: - * type: integer - * description: ID do usuário - * responses: - * 204: - * description: Usuário removido com sucesso - * '401': - * $ref: '#/components/responses/Unauthorized' - * '403': - * $ref: '#/components/responses/Forbidden' - * '404': - * $ref: '#/components/responses/NotFound' - * '500': - * $ref: '#/components/responses/InternalServerError' - */ - app.route('/usuarios/:usuario_id') - .put([ - tokensMiddleware([ - TIPOS_USUARIOS.CURADOR, - TIPOS_USUARIOS.OPERADOR, - TIPOS_USUARIOS.IDENTIFICADOR, - ]), - validacoesMiddleware(atualizarUsuarioEsquema), - controller.editar, - ]) - .get([ - tokensMiddleware([ - TIPOS_USUARIOS.CURADOR, - TIPOS_USUARIOS.OPERADOR, - TIPOS_USUARIOS.IDENTIFICADOR, - ]), - controller.usuario, - ]) - .delete([ - tokensMiddleware([ - TIPOS_USUARIOS.CURADOR, - ]), - validacoesMiddleware(desativarUsuarioEsquema), - controller.desativar, - ]); - - /** - * @swagger - * /usuarios/{usuarioId}/senha: - * put: - * summary: Atualiza a senha de um usuário - * tags: [Usuários] - * parameters: - * - in: path - * name: usuarioId - * required: true - * schema: - * type: integer - * description: ID do usuário - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * senha: - * type: string - * required: - * - senha - * example: - * senha: "novaSenha123" - * responses: - * 200: - * description: Senha atualizada com sucesso - * content: - * application/json: - * schema: - * type: object - * example: - * sucesso: true - * '400': - * $ref: '#/components/responses/BadRequest' - * '401': - * $ref: '#/components/responses/Unauthorized' - * '403': - * $ref: '#/components/responses/Forbidden' - * '404': - * $ref: '#/components/responses/NotFound' - * '500': - * $ref: '#/components/responses/InternalServerError' - */ - app.route('/usuarios/:usuarioId/senha') - .put([ - tokensMiddleware([ - TIPOS_USUARIOS.CURADOR, - TIPOS_USUARIOS.OPERADOR, - TIPOS_USUARIOS.IDENTIFICADOR, - ]), - validacoesMiddleware(atualizarSenhaEsquema), - controller.atualizarSenha, - ]); -}; +import listagensMiddleware from '../middlewares/listagens-middleware'; +import tokensMiddleware, { TIPOS_USUARIOS } from '../middlewares/tokens-middleware'; +import validacoesMiddleware from '../middlewares/validacoes-middleware'; +import atualizarUsuarioEsquema from '../validators/usuario-atualiza'; +import atualizarSenhaEsquema from '../validators/usuario-atualiza-senha'; +import cadastrarUsuarioEsquema from '../validators/usuario-cadastro'; +import desativarUsuarioEsquema from '../validators/usuario-desativa'; +import listagemUsuarioEsquema from '../validators/usuario-listagem'; +import usuarioLoginEsquema from '../validators/usuario-login'; +import solicitarResetSenhaEsquema from '../validators/usuario-solicita-reset'; +import redefinirSenhaEsquema from '../validators/usuario-redefine-senha'; + +const controller = require('../controllers/usuarios-controller'); + +/** + * @swagger + * tags: + * name: Usuários + * description: Operações relacionadas aos usuários + */ +export default app => { + + /** + * @swagger + * /usuarios/redefinir-senha: + * put: + * summary: Redefine a senha do usuário usando um token válido + * tags: [Usuários] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * token: + * type: string + * novaSenha: + * type: string + * required: + * - token + * - novaSenha + * example: + * token: "a1b2c3d4e5f6..." + * novaSenha: "minhaNovaSenhaSuperSegura123" + * responses: + * '204': + * description: Senha atualizada com sucesso. + * '400': + * $ref: '#/components/responses/BadRequest' + * '500': + * $ref: '#/components/responses/InternalServerError' + */ + app.route('/usuarios/redefinir-senha') + .put([ + validacoesMiddleware(redefinirSenhaEsquema), + controller.redefinirSenhaComToken, + ]); + + /** +* @swagger +* /usuarios/solicitar-reset-senha: +* post: +* summary: Inicia o processo de reset de senha para um usuário +* tags: [Usuários] +* requestBody: +* required: true +* content: +* application/json: +* schema: +* type: object +* properties: +* email: +* type: string +* format: email +* required: +* - email +* example: +* email: "usuario@exemplo.com" +* responses: +* '204': +* description: Solicitação recebida. Se o e-mail estiver cadastrado, um link para reset de senha será enviado. +* '400': +* $ref: '#/components/responses/BadRequest' +* '500': +* $ref: '#/components/responses/InternalServerError' +*/ + app.route('/usuarios/solicitar-reset-senha') + .post([ + validacoesMiddleware(solicitarResetSenhaEsquema), + controller.solicitarResetSenha, + ]); + + /** + * @swagger + * /login: + * post: + * summary: Realiza login do usuário + * tags: [Usuários] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * email: + * type: string + * senha: + * type: string + * required: + * - email + * - senha + * example: + * email: "usuario@email.com" + * senha: "senha123" + * responses: + * 200: + * description: Login realizado com sucesso + * content: + * application/json: + * schema: + * type: object + * properties: + * token: + * type: string + * usuario: + * type: object + * properties: + * id: + * type: integer + * nome: + * type: string + * email: + * type: string + * tipo_usuario_id: + * type: integer + * '400': + * $ref: '#/components/responses/BadRequest' + * '401': + * $ref: '#/components/responses/Unauthorized' + * '500': + * $ref: '#/components/responses/InternalServerError' + */ + app.route('/login') + .post([ + validacoesMiddleware(usuarioLoginEsquema), + controller.login, + ]); + + /** + * @swagger + * /coletores-predicao: + * get: + * summary: Lista coletores para predição + * tags: [Usuários] + * responses: + * 200: + * description: Lista de coletores retornada com sucesso + * content: + * application/json: + * schema: + * type: array + * items: + * type: object + * properties: + * id: + * type: integer + * description: ID do coletor + * nome: + * type: string + * description: Nome do coletor + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '500': + * $ref: '#/components/responses/InternalServerError' + */ + app.route('/coletores-predicao') + .get([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + TIPOS_USUARIOS.OPERADOR, + ]), + controller.obtemColetores, + ]); + + /** + * @swagger + * /identificadores-predicao: + * get: + * summary: Lista identificadores para predição + * tags: [Usuários] + * responses: + * 200: + * description: Lista de identificadores retornada com sucesso + * content: + * application/json: + * schema: + * type: array + * items: + * type: object + * properties: + * id: + * type: integer + * description: ID do identificador + * nome: + * type: string + * description: Nome do identificador + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '500': + * $ref: '#/components/responses/InternalServerError' + */ + app.route('/identificadores-predicao') + .get([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + TIPOS_USUARIOS.OPERADOR, + TIPOS_USUARIOS.IDENTIFICADOR, + ]), + controller.obtemIdentificadores, + ]); + + /** + * @swagger + * /usuarios: + * get: + * summary: Lista todos os usuários + * tags: [Usuários] + * responses: + * 200: + * description: Lista de usuários retornada com sucesso + * content: + * application/json: + * schema: + * type: object + * properties: + * metadados: + * type: object + * properties: + * total: + * type: integer + * pagina: + * type: integer + * limite: + * type: integer + * usuarios: + * type: array + * items: + * type: object + * properties: + * id: + * type: integer + * nome: + * type: string + * telefone: + * type: string + * ra: + * type: string + * nullable: true + * email: + * type: string + * tipos_usuario: + * type: object + * properties: + * id: + * type: integer + * tipo: + * type: string + * created_at: + * type: string + * format: date-time + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '500': + * $ref: '#/components/responses/InternalServerError' + * post: + * summary: Cadastra um novo usuário + * tags: [Usuários] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * nome: + * type: string + * minLength: 1 + * email: + * type: string + * format: email + * minLength: 1 + * senha: + * type: string + * minLength: 1 + * tipo_usuario_id: + * type: integer + * herbario_id: + * type: integer + * required: + * - nome + * - email + * - senha + * - tipo_usuario_id + * - herbario_id + * example: + * nome: "Novo Usuário" + * email: "novo@email.com" + * senha: "senha123" + * tipo_usuario_id: 2 + * herbario_id: 1 + * responses: + * 201: + * description: Usuário cadastrado com sucesso + * content: + * application/json: + * schema: + * type: object + * example: + * id: 2 + * nome: "Novo Usuário" + * email: "novo@email.com" + * '400': + * $ref: '#/components/responses/BadRequest' + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '500': + * $ref: '#/components/responses/InternalServerError' + */ + app.route('/usuarios') + .get([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + ]), + validacoesMiddleware(listagemUsuarioEsquema), + listagensMiddleware, + controller.listagem, + ]) + .post([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + ]), + validacoesMiddleware(cadastrarUsuarioEsquema), + controller.cadastro, + ]); + + /** + * @swagger + * /usuarios/{usuario_id}: + * put: + * summary: Edita um usuário + * tags: [Usuários] + * parameters: + * - in: path + * name: usuario_id + * required: true + * schema: + * type: integer + * description: ID do usuário + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * nome: + * type: string + * email: + * type: string + * required: + * - nome + * - email + * example: + * nome: "Usuário Editado" + * email: "editado@email.com" + * responses: + * 200: + * description: Usuário editado com sucesso + * content: + * application/json: + * schema: + * type: object + * example: + * id: 1 + * nome: "Usuário Editado" + * email: "editado@email.com" + * '400': + * $ref: '#/components/responses/BadRequest' + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '404': + * $ref: '#/components/responses/NotFound' + * '500': + * $ref: '#/components/responses/InternalServerError' + * get: + * summary: Busca um usuário pelo ID + * tags: [Usuários] + * parameters: + * - in: path + * name: usuario_id + * required: true + * schema: + * type: integer + * description: ID do usuário + * responses: + * 200: + * description: Dados do usuário encontrados + * content: + * application/json: + * schema: + * type: object + * properties: + * id: + * type: integer + * nome: + * type: string + * telefone: + * type: string + * ra: + * type: string + * nullable: true + * email: + * type: string + * herbario_id: + * type: integer + * tipos_usuario: + * type: object + * properties: + * id: + * type: integer + * tipo: + * type: string + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '404': + * $ref: '#/components/responses/NotFound' + * '500': + * $ref: '#/components/responses/InternalServerError' + * delete: + * summary: Remove um usuário + * tags: [Usuários] + * parameters: + * - in: path + * name: usuario_id + * required: true + * schema: + * type: integer + * description: ID do usuário + * responses: + * 204: + * description: Usuário removido com sucesso + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '404': + * $ref: '#/components/responses/NotFound' + * '500': + * $ref: '#/components/responses/InternalServerError' + */ + app.route('/usuarios/:usuario_id') + .put([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + TIPOS_USUARIOS.OPERADOR, + TIPOS_USUARIOS.IDENTIFICADOR, + ]), + validacoesMiddleware(atualizarUsuarioEsquema), + controller.editar, + ]) + .get([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + TIPOS_USUARIOS.OPERADOR, + TIPOS_USUARIOS.IDENTIFICADOR, + ]), + controller.usuario, + ]) + .delete([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + ]), + validacoesMiddleware(desativarUsuarioEsquema), + controller.desativar, + ]); + + /** + * @swagger + * /usuarios/{usuarioId}/senha: + * put: + * summary: Atualiza a senha de um usuário + * tags: [Usuários] + * parameters: + * - in: path + * name: usuarioId + * required: true + * schema: + * type: integer + * description: ID do usuário + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * senha: + * type: string + * required: + * - senha + * example: + * senha: "novaSenha123" + * responses: + * 200: + * description: Senha atualizada com sucesso + * content: + * application/json: + * schema: + * type: object + * example: + * sucesso: true + * '400': + * $ref: '#/components/responses/BadRequest' + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '404': + * $ref: '#/components/responses/NotFound' + * '500': + * $ref: '#/components/responses/InternalServerError' + */ + app.route('/usuarios/:usuarioId/senha') + .put([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + TIPOS_USUARIOS.OPERADOR, + TIPOS_USUARIOS.IDENTIFICADOR, + ]), + validacoesMiddleware(atualizarSenhaEsquema), + controller.atualizarSenha, + ]); +}; diff --git a/src/validators/especie-atualiza.js b/src/validators/especie-atualiza.js index 1059850..675924a 100644 --- a/src/validators/especie-atualiza.js +++ b/src/validators/especie-atualiza.js @@ -1,25 +1,25 @@ -export default { - nome: { - in: 'body', - isString: true, - isEmpty: false, - isLength: { - options: [{ min: 3 }], - }, - }, - genero_id: { - in: 'body', - isInt: true, - isEmpty: false, - }, - autor_id: { - in: 'body', - isInt: true, - optional: true, - }, - especie_id: { - in: 'params', - isInt: true, - isEmpty: false, - }, -}; +export default { + nome: { + in: 'body', + isString: true, + isEmpty: false, + isLength: { + options: [{ min: 3 }], + }, + }, + genero_id: { + in: 'body', + isInt: true, + isEmpty: false, + }, + autor_id: { + in: 'body', + isInt: true, + optional: true, + }, + especie_id: { + in: 'params', + isInt: true, + isEmpty: false, + }, +}; diff --git a/src/validators/usuario-redefine-senha.js b/src/validators/usuario-redefine-senha.js new file mode 100644 index 0000000..f53b218 --- /dev/null +++ b/src/validators/usuario-redefine-senha.js @@ -0,0 +1,10 @@ +export default { + token: { + isEmpty: false, + errorMessage: 'O token é obrigatório.', + }, + novaSenha: { + isEmpty: false, + errorMessage: 'A nova senha é obrigatória.', + }, +}; diff --git a/src/validators/usuario-solicita-reset.js b/src/validators/usuario-solicita-reset.js new file mode 100644 index 0000000..c73c6cb --- /dev/null +++ b/src/validators/usuario-solicita-reset.js @@ -0,0 +1,6 @@ +export default { + email: { + isEmail: true, + isEmpty: false, + }, +}; diff --git a/src/views/ficha-tombo.ejs b/src/views/ficha-tombo.ejs index 7906a11..4ce5c8c 100644 --- a/src/views/ficha-tombo.ejs +++ b/src/views/ficha-tombo.ejs @@ -1,311 +1,311 @@ -<%# Nesse arquivo, há a criação da ficha tombo, que é exibida quando se %> -<%# deseja imprimir dados de um tombo específico, por exemplo. %> - - - - - - - - Ficha Tombo - - - <% if ( imprimir === '0') { %> - <% fotos.length = 1%> - <% } %> - - <% const copias = parseInt(numero_copias || 1); %> - <% let fichaIndex = 0; %> - - <% for (let j = 0; j < copias; j++) { %> -
- -
-
- Logo UTFPR -
-
- Herbário da Universidade Tecnológica Federal do Paraná -
Campus Campo Mourão
- -
- HCF <%- tombo.hcf %> - -
- Data: <%- romano_data_tombo %> -
-
-
-
- - -
- <% if (familia && familia.nome) { %> -
- Família: - <% if (familia && familia.nome.toLowerCase() !== 'indeterminada') { %> - <%- tombo.familia.nome %> - <% } %> - <% if (tombo && tombo.sub_familia) { %> - - <%- subfamilia.nome %> - <% } %> -
- <% } %> - -
- Espécie: - <% if (genero && genero.nome) { %> - <%- genero.nome %> - <% } %> - <% if (especie && especie.nome) { %> - <%- especie.nome %> - <% } %> - <% if (especie && especie.autor) { %> - <%- especie.autor.nome %> - <% } %> - <% if (variedade && variedade.nome) { %> - var. <%- variedade.nome %> - <% } %> - <% if (variedade && variedade.autor) { %> - <%- variedade.autor.nome %> - <% } %> - <% if (subespecie && subespecie.nome) { %> - subsp. <%- subespecie.nome %> - <% } %> - <% if (subespecie && subespecie.autor) { %> - <%- subespecie.autor.nome %> - <% } %> -
- -
- -
- Nome Vulgar: <%- tombo.nomes_populares %> -
-
-
- Identificador: <%- identificador %> -
-
- Data: <%- romano_data_identificacao %> -
-
-
- Local de Coleta: - <% if (localColeta && localColeta.complemento) { %> - <%- localColeta.complemento %> - <% } %> - <% if (localColeta && localColeta.descricao) { %> - - <%- localColeta.descricao %> - <% } %> - <% if (cidade && cidade.nome) { %> - - <%- cidade.nome %> - <% } %> - <% if (cidade && cidade.estado) { %> - - <%- cidade.estado.nome %> - <% } %> - <% if (cidade && cidade.estado && cidade.estado.pais) { %> - - <%- cidade.estado.pais.nome %> - <% } %> -
- -
- -
- Observações: - <% if (tombo && tombo.descricao) { %> - <%- tombo.descricao %> - <% } %> - <% if (tombo && tombo.latitude) { %> - - Latitude: <%- tombo.latitude %> - <% } %> - <% if (tombo && tombo.longitude) { %> - - Longitude: <%- tombo.longitude %> - <% } %> - <% if (tombo && tombo.altitude) { %> - - Altitude: <%- tombo.altitude %>m - <% } %> - <% if (localColeta && localColeta.solo) { %> - - Solo: <%- localColeta.solo.nome %> - <% } %> - <% if (localColeta && localColeta.relevo) { %> - - Relevo: <%- localColeta.relevo.nome %> - <% } %> - <% if (localColeta && localColeta.vegetaco) { %> - - Vegetação: <%- localColeta.vegetaco.nome %> - <% } %> - <% if (localColeta && localColeta.fase_sucessional) { %> - - Fase sucessional: <%- localColeta.fase_sucessional.nome %> - <% } %> -
- -
- -
-
- <%- tombo.coletores.length == 1 ? 'Coletor' : 'Coletores' %>: -
- <%- tombo.coletores %> -
-
- -
-
-
- nº: <%- tombo.numero_coleta %> -
- -
- Data: <%- romano_data_coleta %> -
-
- -
- - <% if (!!fotos[0]['id'] && imprimir !== '0') { %> -
- -
- <% } %> -
-
-
-
- <% if (!!fotos[0]['id'] && imprimir !== '0') { %> - - <% } %> - <% fichaIndex++; %> - <% } %> - - - - - +<%# Nesse arquivo, há a criação da ficha tombo, que é exibida quando se %> +<%# deseja imprimir dados de um tombo específico, por exemplo. %> + + + + + + + + Ficha Tombo + + + <% if ( imprimir === '0') { %> + <% fotos.length = 1%> + <% } %> + + <% const copias = parseInt(numero_copias || 1); %> + <% let fichaIndex = 0; %> + + <% for (let j = 0; j < copias; j++) { %> +
+ +
+
+ Logo UTFPR +
+
+ Herbário da Universidade Tecnológica Federal do Paraná -
Campus Campo Mourão
+ +
+ HCF <%- tombo.hcf %> + +
+ Data: <%- romano_data_tombo %> +
+
+
+
+ + +
+ <% if (familia && familia.nome) { %> +
+ Família: + <% if (familia && familia.nome.toLowerCase() !== 'indeterminada') { %> + <%- tombo.familia.nome %> + <% } %> + <% if (tombo && tombo.sub_familia) { %> + - <%- subfamilia.nome %> + <% } %> +
+ <% } %> + +
+ Espécie: + <% if (genero && genero.nome) { %> + <%- genero.nome %> + <% } %> + <% if (especie && especie.nome) { %> + <%- especie.nome %> + <% } %> + <% if (especie && especie.autor) { %> + <%- especie.autor.nome %> + <% } %> + <% if (variedade && variedade.nome) { %> + var. <%- variedade.nome %> + <% } %> + <% if (variedade && variedade.autor) { %> + <%- variedade.autor.nome %> + <% } %> + <% if (subespecie && subespecie.nome) { %> + subsp. <%- subespecie.nome %> + <% } %> + <% if (subespecie && subespecie.autor) { %> + <%- subespecie.autor.nome %> + <% } %> +
+ +
+ +
+ Nome Vulgar: <%- tombo.nomes_populares %> +
+
+
+ Identificador: <%- identificador %> +
+
+ Data: <%- romano_data_identificacao %> +
+
+
+ Local de Coleta: + <% if (localColeta && localColeta.complemento) { %> + <%- localColeta.complemento %> + <% } %> + <% if (localColeta && localColeta.descricao) { %> + - <%- localColeta.descricao %> + <% } %> + <% if (cidade && cidade.nome) { %> + - <%- cidade.nome %> + <% } %> + <% if (cidade && cidade.estado) { %> + - <%- cidade.estado.nome %> + <% } %> + <% if (cidade && cidade.estado && cidade.estado.pais) { %> + - <%- cidade.estado.pais.nome %> + <% } %> +
+ +
+ +
+ Observações: + <% if (tombo && tombo.descricao) { %> + <%- tombo.descricao %> + <% } %> + <% if (tombo && tombo.latitude) { %> + - Latitude: <%- tombo.latitude %> + <% } %> + <% if (tombo && tombo.longitude) { %> + - Longitude: <%- tombo.longitude %> + <% } %> + <% if (tombo && tombo.altitude) { %> + - Altitude: <%- tombo.altitude %>m + <% } %> + <% if (localColeta && localColeta.solo) { %> + - Solo: <%- localColeta.solo.nome %> + <% } %> + <% if (localColeta && localColeta.relevo) { %> + - Relevo: <%- localColeta.relevo.nome %> + <% } %> + <% if (localColeta && localColeta.vegetaco) { %> + - Vegetação: <%- localColeta.vegetaco.nome %> + <% } %> + <% if (localColeta && localColeta.fase_sucessional) { %> + - Fase sucessional: <%- localColeta.fase_sucessional.nome %> + <% } %> +
+ +
+ +
+
+ <%- tombo.coletores.length == 1 ? 'Coletor' : 'Coletores' %>: +
+ <%- tombo.coletores %> +
+
+ +
+
+
+ nº: <%- tombo.numero_coleta %> +
+ +
+ Data: <%- romano_data_coleta %> +
+
+ +
+ + <% if (!!fotos[0]['id'] && imprimir !== '0') { %> +
+ +
+ <% } %> +
+
+
+
+ <% if (!!fotos[0]['id'] && imprimir !== '0') { %> + + <% } %> + <% fichaIndex++; %> + <% } %> + + + + + diff --git a/yarn.lock b/yarn.lock index f7bc605..8fddf61 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5714,6 +5714,11 @@ node-wkhtmltopdf@^2.0.0: resolved "https://registry.npmjs.org/node-wkhtmltopdf/-/node-wkhtmltopdf-2.0.0.tgz" integrity sha512-X/pMpExoExOOjkFI2+Uw4+jnzB25VT+maVkgVw5Gaiu1sCpMwUZqI9vmhC06N7tyGz9HYWkARXQBrcW0pfQKaQ== +nodemailer@^7.0.9: + version "7.0.9" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-7.0.9.tgz#fe5abd4173e08e01aa243c7cddd612ad8c6ccc18" + integrity sha512-9/Qm0qXIByEP8lEV2qOqcAW7bRpL8CR9jcTwk3NBnHJNmP9fIJ86g2fgmIXqHY+nj55ZEMwWqYAT2QTDpRUYiQ== + nodemon@3.1.9: version "3.1.9" resolved "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz#df502cdc3b120e1c3c0c6e4152349019efa7387b" From 68b3988e682b251aa3d6231e7a589c5c1e983826 Mon Sep 17 00:00:00 2001 From: Lucas Vaz Date: Thu, 9 Oct 2025 22:11:02 -0300 Subject: [PATCH 2/6] Fix: Atualizando erros de nomeclatura lint --- src/controllers/usuarios-controller.js | 152 ++++++++++++------------- 1 file changed, 75 insertions(+), 77 deletions(-) diff --git a/src/controllers/usuarios-controller.js b/src/controllers/usuarios-controller.js index 9eeaa02..c5b17b2 100644 --- a/src/controllers/usuarios-controller.js +++ b/src/controllers/usuarios-controller.js @@ -307,94 +307,92 @@ export const atualizarSenha = (request, response, next) => { }; export const solicitarResetSenha = async (request, response, next) => { - const { email } = request.body; - try { - const usuario = await encontraUsuarioAtivoPorEmail(email); - if (usuario) { - const token = geraTokenResetSenha(usuario.id); - const dataExpiracao = new Date(); - dataExpiracao.setMinutes(dataExpiracao.getMinutes() + 45); - - await Usuario.update({ - reset_token: token, - reset_token_expiration: dataExpiracao, - }, { where: { id: usuario.id } }); - - const transporter = nodemailer.createTransport({ - host: process.env.SMTP_HOST, - port: process.env.SMTP_PORT, - secure: false, - auth: { - user: process.env.SMTP_USER, - pass: process.env.SMTP_PASS, - }, - }); - - const link = `${process.env.URL_PAINEL}reset-senha?token=${token}`; - await transporter.sendMail({ - from: '"Sistema HCF" ', - to: email, - subject: 'Redefinição de senha', - html: ` -

Olá ${usuario.nome},

+ const { email } = request.body; + try { + const user = await encontraUsuarioAtivoPorEmail(email); + if (user) { + const token = geraTokenResetSenha(user.id); + const dataExpiracao = new Date(); + dataExpiracao.setMinutes(dataExpiracao.getMinutes() + 45); + + await Usuario.update( + { reset_token: token, reset_token_expiration: dataExpiracao }, + { where: { id: user.id } } + ); + + const transporter = nodemailer.createTransport({ + host: process.env.SMTP_HOST, + port: process.env.SMTP_PORT, + secure: false, + auth: { + user: process.env.SMTP_USER, + pass: process.env.SMTP_PASS, + }, + }); + + const link = `${process.env.URL_PAINEL}reset-senha?token=${token}`; + await transporter.sendMail({ + from: process.env.SMTP_FROM || '"Sistema HCF" ', + to: email, + subject: 'Redefinição de senha', + html: ` +

Olá ${user.nome},

Você solicitou uma redefinição de senha.

Não compartilhe esse link.

Clique no link abaixo para criar uma nova senha (válido por 45 minutos):

${link} `, - }); - } - - return response.status(codigos.EDITAR_SEM_RETORNO).send(); - } catch (err) { - next(err); + }); } + + return response.status(codigos.EDITAR_SEM_RETORNO).send(); + } catch (err) { + return next(err); + } }; + export const redefinirSenhaComToken = async (request, response, next) => { - const { token, novaSenha } = request.body; + const { token, novaSenha } = request.body; - try { - if (!token || !novaSenha) { - throw new BadRequestExeption(400, 'Token e nova senha são obrigatórios.'); - } + try { + if (!token || !novaSenha) { + throw new BadRequestExeption(400, 'Token e nova senha são obrigatórios.'); + } - const usuario = await Usuario.findOne({ - where: { - reset_token: token, - reset_token_expiration: { [Op.gt]: new Date() }, - ativo: true, - }, - }); - - if (!usuario) { - return response.status(400).json({ - sucesso: false, - mensagem: 'Token inválido ou expirado.', - }); - } - - const novaSenhaHash = gerarSenha(novaSenha); - await Usuario.update( - { - senha: novaSenhaHash, - reset_token: null, - reset_token_expiration: null, - }, - { where: { id: usuario.id } } - ); - - return response.status(200).json({ - sucesso: true, - mensagem: 'Senha redefinida com sucesso.', - }); - } catch (err) { - console.error('Erro ao redefinir senha:', err.message); - return response.status(500).json({ - sucesso: false, - mensagem: 'Erro interno ao redefinir senha.', - detalhe: process.env.NODE_ENV === 'development' ? err.message : undefined, - }); + const user = await Usuario.findOne({ + where: { + reset_token: token, + reset_token_expiration: { [Op.gt]: new Date() }, + ativo: true, + }, + }); + + if (!user) { + return response.status(400).json({ + sucesso: false, + mensagem: 'Token inválido ou expirado.', + }); } + + const novaSenhaHash = gerarSenha(novaSenha); + await Usuario.update( + { + senha: novaSenhaHash, + reset_token: null, + reset_token_expiration: null, + }, + { where: { id: user.id } } + ); + + return response.status(200).json({ + sucesso: true, + mensagem: 'Senha redefinida com sucesso.', + }); + } catch (err) { + // ✅ Remove console.error para passar no lint + return next(err); + } }; + export default {}; From 51f73b5dcc2274dd931bb81ab149e15dfcf07ab6 Mon Sep 17 00:00:00 2001 From: Lucas Vaz Date: Thu, 16 Oct 2025 16:41:14 -0300 Subject: [PATCH 3/6] Fix: Atualizando conflitos development --- .env.example | 2 + .husky/pre-commit | 2 +- package.json | 8 +- src/app.js | 61 +- src/config/security.js | 2 +- src/config/swagger.js | 10 +- src/controllers/cidades-controller.js | 12 +- src/controllers/coletor-controller.js | 31 +- src/controllers/darwincore-controller.js | 6 - src/controllers/estados-controller.js | 8 + src/controllers/fichas-tombos-controller.js | 2 - src/controllers/herbarios-controller.js | 89 +- src/controllers/identificador-controller.js | 33 + src/controllers/locais-coleta-controller.js | 44 +- src/controllers/pendencias-controller.js | 2182 ++++++++++++++++- src/controllers/remessa-controller.js | 8 - src/controllers/splinker-controller.js | 5 - src/controllers/taxonomias-controller.js | 1459 +++++++++++ src/controllers/tombos-controller.js | 1640 ++++++++++++- src/controllers/uploads-controller.js | 15 +- src/controllers/usuarios-controller.js | 41 +- .../20251001194607_fix-nome-cientifico.ts | 46 + .../20251008212623_rem_campo_ativo.ts | 31 + .../migration/20251008221402_rem-cor-tombo.ts | 20 +- src/helpers/tokens.js | 5 +- src/helpers/tombo.js | 170 +- src/herbarium/reflora/main.js | 6 - src/herbarium/reflora/tombos.js | 12 - src/herbarium/specieslink/main.js | 6 - src/herbarium/specieslink/tombos.js | 269 ++ src/middlewares/tokens-middleware.js | 8 +- src/models/Autor.js | 4 - src/models/Coletor.js | 4 - src/models/Especie.js | 4 - src/models/Familia.js | 4 - src/models/Genero.js | 4 - src/models/Herbario.js | 4 - src/models/Subespecie.js | 4 - src/models/Subfamilia.js | 4 - src/models/Tombo.js | 558 ++--- src/models/Usuario.js | 3 + src/models/Variedade.js | 4 - src/routes/identificador.js | 43 + src/routes/uploads.js | 27 +- src/routes/usuarios.js | 502 ++++ src/validators/coletor-cadastro.js | 2 +- src/validators/especie-atualiza.js | 30 + src/validators/estado-listagem.js | 6 + src/validators/localColeta-listagem.js | 12 + src/validators/subespecie-atualiza.js | 18 +- src/validators/tombo-alteracao.js | 458 ++-- src/validators/tombo-cadastro.js | 350 +-- src/validators/tombo-listagem.js | 10 +- src/validators/variedade-atualiza.js | 18 +- tsconfig.json | 2 +- yarn.lock | 10 + 56 files changed, 7335 insertions(+), 983 deletions(-) create mode 100644 src/database/migration/20251008212623_rem_campo_ativo.ts diff --git a/.env.example b/.env.example index 840276f..ba35275 100644 --- a/.env.example +++ b/.env.example @@ -15,6 +15,8 @@ MYSQL_MIGRATION_PASSWORD=masterkey RECAPTCHA_SECRET_KEY=6LcYYYYYYYYYYYYYY +JWT_SECRET=your-jwt-secret-here + SMTP_HOST=smtp.gmail.com SMTP_PORT=587 SMTP_USER="seu-email@gmail.com" diff --git a/.husky/pre-commit b/.husky/pre-commit index 3867a0f..c57434c 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1 @@ -npm run lint +npm run lint diff --git a/package.json b/package.json index ed50fd7..1326a7f 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,9 @@ "start": "nodemon --ext 'js,ts,tsx' --exec babel-node --extensions '.js,.ts,.tsx' ./src/index.js", "build": "run-s clean build:app", "test": "jest", - "prepare": "husky" + "prepare": "husky", + "audit": "npm audit --audit-level=moderate", + "audit:fix": "npm audit fix" }, "devDependencies": { "@babel/cli": "7.27.0", @@ -65,7 +67,9 @@ "express-validator": "7.2.1", "fast-csv": "^5.0.5", "handlebars": "^4.7.8", + "helmet": "^8.0.0", "jsonwebtoken": "9.0.2", + "express-rate-limit": "^7.4.1", "knex": "2.5.1", "moment": "^2.24.0", "moment-timezone": "^0.5.21", @@ -88,4 +92,4 @@ "wkhtmltopdf": "^0.4.0" }, "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" -} +} \ No newline at end of file diff --git a/src/app.js b/src/app.js index 450733a..2bb0c92 100644 --- a/src/app.js +++ b/src/app.js @@ -1,6 +1,8 @@ import parser from 'body-parser'; import cors from 'cors'; import express from 'express'; +import rateLimit from 'express-rate-limit'; +import helmet from 'helmet'; import morgan from 'morgan'; import swaggerUi from 'swagger-ui-express'; @@ -11,7 +13,64 @@ import { generatePreview, reportPreview } from './reports/controller'; import routes from './routes'; const app = express(); -app.use(cors()); + +// Security headers +app.use(helmet({ + contentSecurityPolicy: { + directives: { + defaultSrc: ["'self'"], + styleSrc: ["'self'", "'unsafe-inline'"], + scriptSrc: ["'self'"], + imgSrc: ["'self'", 'data:', 'https:'], + }, + }, + crossOriginEmbedderPolicy: false, // Disable for file uploads +})); + +// CORS configuration +const corsOptions = { + origin(origin, callback) { + // Allow requests with no origin (mobile apps, curl, etc.) + if (!origin) return callback(null, true); + + const allowedOrigins = [ + 'http://localhost:3000', + 'http://localhost:3001', + 'http://localhost:5173', + 'https://hcf.cm.utfpr.edu.br', + 'https://dev.hcf.cm.utfpr.edu.br', + 'https://api.dev.hcf.cm.utfpr.edu.br', + ]; + + if (allowedOrigins.includes(origin)) { + return callback(null, true); + } + return callback(new Error('Not allowed by CORS')); + + }, + credentials: true, + methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'], +}; + +app.use(cors(corsOptions)); + +// Rate limiting +const limiter = rateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 500, // Limit each IP to 100 requests per windowMs + message: { + error: { + code: 429, + message: 'Muitas requisições. Tente novamente em 15 minutos.', + }, + }, + standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers + legacyHeaders: false, // Disable the `X-RateLimit-*` headers +}); + +// Apply rate limiting to all requests +app.use(limiter); app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec)); app.use(parser.json()); diff --git a/src/config/security.js b/src/config/security.js index 7d9d72f..31fc9f9 100644 --- a/src/config/security.js +++ b/src/config/security.js @@ -1,3 +1,3 @@ export const recaptchaSecret = process.env.RECAPTCHA_SECRET_KEY; -export const secret = '^Og7c:ga4BP@%Z#T]Z4NsU&*C)}#ON#dihB7m)6Qw{7!UCLu0w'; +export const secret = process.env.JWT_SECRET; export const expires = '2d'; diff --git a/src/config/swagger.js b/src/config/swagger.js index 0c295cd..e088026 100644 --- a/src/config/swagger.js +++ b/src/config/swagger.js @@ -90,16 +90,16 @@ const options = { }, }, securitySchemes: { - ApiKeyAuth: { - type: 'apiKey', - in: 'header', - name: 'token', + BearerAuth: { + type: 'http', + scheme: 'bearer', + bearerFormat: 'JWT', }, }, }, security: [ { - ApiKeyAuth: [], + BearerAuth: [], }, ], }, diff --git a/src/controllers/cidades-controller.js b/src/controllers/cidades-controller.js index 0481100..b733028 100644 --- a/src/controllers/cidades-controller.js +++ b/src/controllers/cidades-controller.js @@ -413,7 +413,7 @@ export const buscarPontosTaxonomiaComFiltros = async (req, res, next) => { if (nomeFamilia) { whereClause.include.push({ model: Familia, - where: { nome: { [Op.eq]: nomeFamilia }, ativo: 1 }, + where: { nome: { [Op.eq]: nomeFamilia } }, attributes: ['id', 'nome'], required: true, }); @@ -422,7 +422,7 @@ export const buscarPontosTaxonomiaComFiltros = async (req, res, next) => { if (nomeSubFamilia) { whereClause.include.push({ model: Subfamilia, - where: { nome: { [Op.eq]: nomeSubFamilia }, ativo: 1 }, + where: { nome: { [Op.eq]: nomeSubFamilia } }, attributes: ['id', 'nome'], required: true, }); @@ -431,7 +431,7 @@ export const buscarPontosTaxonomiaComFiltros = async (req, res, next) => { if (nomeGenero) { whereClause.include.push({ model: Genero, - where: { nome: { [Op.eq]: nomeGenero }, ativo: 1 }, + where: { nome: { [Op.eq]: nomeGenero } }, attributes: ['id', 'nome'], required: true, }); @@ -440,7 +440,7 @@ export const buscarPontosTaxonomiaComFiltros = async (req, res, next) => { if (nomeEspecie) { whereClause.include.push({ model: Especie, - where: { nome: { [Op.eq]: nomeEspecie }, ativo: 1 }, + where: { nome: { [Op.eq]: nomeEspecie } }, attributes: ['id', 'nome'], required: true, }); @@ -449,7 +449,7 @@ export const buscarPontosTaxonomiaComFiltros = async (req, res, next) => { if (nomeSubEspecie) { whereClause.include.push({ model: Subespecie, - where: { nome: { [Op.eq]: nomeSubEspecie }, ativo: 1 }, + where: { nome: { [Op.eq]: nomeSubEspecie } }, attributes: ['id', 'nome'], required: true, }); @@ -458,7 +458,7 @@ export const buscarPontosTaxonomiaComFiltros = async (req, res, next) => { if (nomeVariedade) { whereClause.include.push({ model: Variedade, - where: { nome: { [Op.eq]: nomeVariedade }, ativo: 1 }, + where: { nome: { [Op.eq]: nomeVariedade } }, attributes: ['id', 'nome'], required: true, }); diff --git a/src/controllers/coletor-controller.js b/src/controllers/coletor-controller.js index 30327bf..b2e9e17 100644 --- a/src/controllers/coletor-controller.js +++ b/src/controllers/coletor-controller.js @@ -20,7 +20,7 @@ export const encontraColetor = async (req, res, next) => { try { const { id } = req.params; const coletor = await Coletor.findOne({ - where: { id, ativo: true }, + where: { id }, }); if (!coletor) { @@ -41,7 +41,7 @@ export const listaColetores = async (req, res, next) => { const { limite, pagina } = req.paginacao; const offset = (pagina - 1) * limite; - const where = { ativo: true }; + const where = {}; if (id) { where.id = id; } else if (nome) { @@ -74,7 +74,7 @@ export const atualizaColetor = async (req, res, next) => { try { const { id } = req.params; const [updated] = await Coletor.update(req.body, { - where: { id, ativo: true }, + where: { id }, }); if (updated) { const updatedColetor = await Coletor.findByPk(id); @@ -90,15 +90,30 @@ export const atualizaColetor = async (req, res, next) => { export const desativaColetor = async (req, res, next) => { try { const { id } = req.params; - const [updated] = await Coletor.update({ ativo: false }, { - where: { id, ativo: true }, + const { Tombo } = models; + + const coletor = await Coletor.findOne({ + where: { id }, }); - if (updated) { - res.status(codigos.DESATIVAR).send(); - } else { + if (!coletor) { throw new BadRequestException(404, 'Coletor não encontrado'); } + + const tombosAssociados = await Tombo.count({ + where: { + coletor_id: id }, + }); + + if (tombosAssociados > 0) { + throw new BadRequestException('Coletor não pode ser excluído porque possui dependentes.'); + } + + await Coletor.destroy({ + where: { id }, + }); + + res.status(204).send(); } catch (error) { next(error); } diff --git a/src/controllers/darwincore-controller.js b/src/controllers/darwincore-controller.js index 1094af9..09c32a3 100644 --- a/src/controllers/darwincore-controller.js +++ b/src/controllers/darwincore-controller.js @@ -52,7 +52,6 @@ const obterModeloDarwinCoreLotes = async (limit, offset, request, response) => { limit, offset, where: { - ativo: true, rascunho: 0, }, attributes: [ @@ -335,11 +334,6 @@ export const obterModeloDarwinCore = async (request, response, next) => { const limit = request.query.limit > 1000 ? 1000 : request.query.limit || 1000; const quantidadeTombos = await Tombo.count( - { - where: { - ativo: true, - }, - }, { distinct: true } ); diff --git a/src/controllers/estados-controller.js b/src/controllers/estados-controller.js index 664360e..ebd1c4c 100644 --- a/src/controllers/estados-controller.js +++ b/src/controllers/estados-controller.js @@ -67,9 +67,17 @@ export const cadastrarEstado = (req, res, next) => { export const listagem = async (req, res, next) => { try { + const paisId = req.query.pais_id ? parseInt(req.query.pais_id, 10) : undefined; + + const where = {}; + if (!Number.isNaN(paisId) && paisId !== undefined) { + where.pais_id = paisId; + } + const estados = await Estado.findAll({ attributes: { exclude: ['created_at', 'updated_at'] }, include: [{ model: Pais, as: 'pais', attributes: ['id', 'nome', 'sigla'] }], + where, order: [['id', 'DESC']], }); diff --git a/src/controllers/fichas-tombos-controller.js b/src/controllers/fichas-tombos-controller.js index 70e324c..1975221 100644 --- a/src/controllers/fichas-tombos-controller.js +++ b/src/controllers/fichas-tombos-controller.js @@ -148,7 +148,6 @@ export default function fichaTomboController(request, response, next) { ]; const where = { - ativo: true, hcf: parseInt(tomboId), }; @@ -204,7 +203,6 @@ export default function fichaTomboController(request, response, next) { ]; const where = { - ativo: true, tombo_hcf: tombo.hcf, }; diff --git a/src/controllers/herbarios-controller.js b/src/controllers/herbarios-controller.js index 7cd4c61..7ada8de 100644 --- a/src/controllers/herbarios-controller.js +++ b/src/controllers/herbarios-controller.js @@ -51,7 +51,6 @@ export const listaTodosHerbariosAtivos = (limit, offset, where) => Herbario.find export const buscarHerbario = (request, response, next) => { const where = { id: request.params.herbario_id, - ativo: true, }; const retorno = { herbario: {}, @@ -63,7 +62,6 @@ export const buscarHerbario = (request, response, next) => { .then(() => listaTodosHerbariosAtivos(1, 0, where)) .then(herbario => { // eslint-disable-next-line - console.log(herbario.rows[0].cidade) // eslint-disable-next-line prefer-destructuring retorno.herbario = herbario.rows[0]; if (retorno.count === 0) { @@ -118,7 +116,6 @@ export const cadastro = (request, response, next) => { .then(() => { const { herbario } = request.body; const where = { - ativo: true, email: herbario.email, }; @@ -133,8 +130,6 @@ export const cadastro = (request, response, next) => { return Endereco.create(endereco, { transaction }); }) .then(endereco => { - // eslint-disable-next-line - console.log(request.body.herbario) const herbario = { ...request.body.herbario, endereco_id: endereco.id, @@ -144,7 +139,6 @@ export const cadastro = (request, response, next) => { }) .then(herbario => { const where = { - ativo: true, id: herbario.id, }; @@ -169,7 +163,6 @@ export const editar = (request, response, next) => { .then(() => { const attributes = { exclude: undefined }; const where = { - ativo: true, id: request.params.herbario_id, }; @@ -206,7 +199,6 @@ export const editar = (request, response, next) => { }) .then(herbario => { const where = { - ativo: true, id: herbario.id, }; @@ -229,30 +221,85 @@ export const editar = (request, response, next) => { export const desativar = (request, response, next) => { const { params } = request; - Promise.resolve() + const callback = transaction => Promise.resolve() .then(() => { const where = { - ativo: true, id: params.herbario_id, }; - return Herbario.findOne({ where }); + return Herbario.findOne({ where, transaction }); }) .then(herbario => { if (!herbario) { throw new NotFoundExeption(200); } - - const where = { - ativo: true, + }) + .then(() => { + const { Tombo } = models; + return Tombo.count({ + where: { + entidade_id: params.herbario_id, + }, + transaction, + }); + }) + .then(tombosCount => { + if (tombosCount > 0) { + throw new BadRequestExeption('Herbário não pode ser excluído porque possui dependentes.'); + } + }) + .then(() => { + const { Usuario } = models; + return Usuario.count({ + where: { + herbario_id: params.herbario_id, + }, + transaction, + }); + }) + .then(usuariosCount => { + if (usuariosCount > 0) { + throw new BadRequestExeption('Herbário não pode ser excluído porque possui dependentes.'); + } + }) + .then(() => { + const { Remessa } = models; + return Remessa.count({ + where: { + herbario_id: params.herbario_id, + }, + transaction, + }); + }) + .then(remessasOrigemCount => { + if (remessasOrigemCount > 0) { + throw new BadRequestExeption('Herbário não pode ser excluído porque possui dependentes.'); + } + }) + .then(() => { + const { Remessa } = models; + return Remessa.count({ + where: { + entidade_destino_id: params.herbario_id, + }, + transaction, + }); + }) + .then(remessasDestinoCount => { + if (remessasDestinoCount > 0) { + throw new BadRequestExeption('Herbário não pode ser excluído porque possui dependentes.'); + } + }) + .then(() => Herbario.destroy({ + where: { id: params.herbario_id, - }; + }, + transaction, + })); - return herbario.update({ ativo: false }, { where }); - }) + sequelize.transaction(callback) .then(() => { - response.status(204) - .send(); + response.status(204).send(); }) .catch(next); }; @@ -261,9 +308,7 @@ export const listagem = (request, response, next) => { const { pagina, limite, offset } = request.paginacao; const { nome, email, sigla } = request.query; - let where = { - ativo: true, - }; + let where = {}; if (nome) { where = { diff --git a/src/controllers/identificador-controller.js b/src/controllers/identificador-controller.js index 596162c..36dd24f 100644 --- a/src/controllers/identificador-controller.js +++ b/src/controllers/identificador-controller.js @@ -83,3 +83,36 @@ export const atualizaIdentificador = async (req, res, next) => { next(error); } }; + +export const excluirIdentificador = async (req, res, next) => { + try { + const { id } = req.params; + + const identificador = await Identificador.findOne({ + where: { id }, + }); + + if (!identificador) { + throw new BadRequestException('Identificador não encontrado'); + } + + const { TomboIdentificador } = models; + const tombosAssociados = await TomboIdentificador.count({ + where: { + identificador_id: id, + }, + }); + + if (tombosAssociados > 0) { + throw new BadRequestException('Identificador não pode ser excluído porque possui dependentes.'); + } + + await Identificador.destroy({ + where: { id }, + }); + + res.status(204).send(); + } catch (error) { + next(error); + } +}; diff --git a/src/controllers/locais-coleta-controller.js b/src/controllers/locais-coleta-controller.js index 6c3494a..a31306c 100644 --- a/src/controllers/locais-coleta-controller.js +++ b/src/controllers/locais-coleta-controller.js @@ -134,27 +134,38 @@ export const cadastrarLocalColeta = async (request, response, next) => { export const buscarLocaisColeta = async (request, response, next) => { try { - const cidadeId = request.query.cidade_id; + const { cidade_id: cidadeId, estado_id: estadoId, pais_id: paisId } = request.query; const { limite, pagina, offset } = request.paginacao; const { getAll } = request.query; const where = {}; + const include = [ + { + model: Cidade, + include: [ + { + model: Estado, + include: [Pais], + }, + ], + }, + { model: FaseSucessional }, + ]; + if (cidadeId) { where.cidade_id = cidadeId; + } else if (estadoId) { + include[0].where = { estado_id: estadoId }; + include[0].required = true; + } else if (paisId) { + include[0].include[0].where = { pais_id: paisId }; + include[0].include[0].required = true; + include[0].required = true; } const queryOptions = { where, - include: [ - { model: Cidade, - include: [ - { model: Estado, - include: [Pais], - }, - ], - }, - { model: FaseSucessional }, - ], + include, order: [['id', 'DESC']], }; @@ -256,25 +267,18 @@ export const deletarLocalColeta = async (request, response, next) => { }); if (!localColeta) { - response.status(404).json({ - mensagem: 'Local de coleta não encontrado.', - }); - return; + throw new BadRequestExeption('Local de Coleta não encontrado.'); } const { Tombo } = models; const tombosAssociados = await Tombo.count({ where: { local_coleta_id: id, - ativo: true, }, }); if (tombosAssociados > 0) { - response.status(400).json({ - mensagem: `Não é possível excluir o local de coleta. Existem ${tombosAssociados} tombo(s) associado(s) a este local.`, - }); - return; + throw new BadRequestExeption('Local de Coleta não pode ser excluído porque possui dependentes.'); } await LocalColeta.destroy({ diff --git a/src/controllers/pendencias-controller.js b/src/controllers/pendencias-controller.js index ad570ad..b349413 100644 --- a/src/controllers/pendencias-controller.js +++ b/src/controllers/pendencias-controller.js @@ -1,3 +1,4 @@ +<<<<<<< HEAD import BadRequestExeption from '../errors/bad-request-exception'; import { converteParaDecimal } from '../helpers/coordenadas'; import models from '../models'; @@ -2176,4 +2177,2183 @@ export function verificaAlteracao(request, response, next) { }) .catch(next); -} \ No newline at end of file +} +======= +import BadRequestExeption from '../errors/bad-request-exception'; +import { converteParaDecimal } from '../helpers/coordenadas'; +import models from '../models'; +import codigos from '../resources/codigos-http'; + +const { + Alteracao, + Usuario, + Herbario, + Solo, + Relevo, + Vegetacao, + Cidade, + FaseSucessional, + LocalColeta, + sequelize, + Sequelize: { Op }, + Tombo, + Especie, + Variedade, + Coletor, + Tipo, + Familia, + Subfamilia, + Genero, + Subespecie, + ColecaoAnexa, + TomboIdentificador, + Identificador, + ColetorComplementar, +} = models; + +export const listagem = (request, response, next) => { + const { limite, pagina, offset } = request.paginacao; + const { status, nome_usuario: nomeUsuario } = request.query; + const retorno = { + metadados: { + total: 0, + pagina, + limite, + }, + resultado: {}, + }; + let where = { + ativo: 1, + }; + let whereUsuario = {}; + if (status) { + where = { + ...where, + status, + }; + } else { + where = { + ...where, + status: { [Op.ne]: 'APROVADO' }, + }; + } + if (nomeUsuario) { + whereUsuario = { + nome: { [Op.like]: `%${nomeUsuario}%` }, + }; + } + const callback = transaction => Promise.resolve() + .then(() => Alteracao.findAndCountAll({ + include: [ + { + model: Usuario, + whereUsuario, + }, + ], + limit: limite, + offset, + where, + order: [['id', 'DESC']], + transaction, + })) + .then(alteracoes => { + retorno.metadados.total = alteracoes.count; + // const alteracoesValidas = alteracoes.rows.filter(item => { + // if (item.usuario.tipo_usuario_id === 1) { + // return false; + // } + // if (item.identificacao) { + // if (item.usuario.tipo_usuario_id === 3) { + // return true; + // } + // return false; + // } + // return true; + // }); + retorno.resultado = alteracoes.rows.map(item => ({ + id: item.id, + nome_usuario: item.usuario.nome, + numero_tombo: item.tombo_hcf, + json: JSON.parse(item.tombo_json), + data_criacao: item.created_at, + status: item.status, + observacao: item.observacao || '', + })); + return retorno; + }); + sequelize.transaction(callback) + .then(() => { + response.status(codigos.LISTAGEM).json(retorno); + }) + .catch(next); +}; + +export const desativar = (request, response, next) => { + const id = request.params.pendencia_id; + + const callback = transaction => Promise.resolve() + .then(() => Alteracao.findOne({ + where: { + ativo: true, + id, + }, + transaction, + })) + .then(alteracao => { + if (!alteracao) { + throw new BadRequestExeption(800); + } + return Alteracao.update({ + ativo: false, + }, { + where: { + id, + }, + transaction, + }); + }); + sequelize.transaction(callback) + .then(() => { + response.status(codigos.DESATIVAR).send(); + }) + .catch(next); +}; + +const comparaDoisTombos = (tombo, tomboAlterado) => { + const parametros = []; + if (tombo.data_coleta_dia !== tomboAlterado.data_coleta_dia) { + parametros.push({ + key: '1', + campo: 'Dia da coleta', + antigo: tombo.data_coleta_dia, + novo: tomboAlterado.data_coleta_dia, + }); + } + if (tombo.data_coleta_mes !== tomboAlterado.data_coleta_mes) { + parametros.push({ + key: '2', + campo: 'Mes da coleta', + antigo: tombo.data_coleta_mes, + novo: tomboAlterado.data_coleta_mes, + }); + } + if (tombo.data_coleta_ano !== tomboAlterado.data_coleta_ano) { + parametros.push({ + key: '3', + campo: 'Ano da coleta', + antigo: tombo.data_coleta_ano, + novo: tomboAlterado.data_coleta_ano, + }); + } + if (tombo.observacao !== tomboAlterado.observacao) { + parametros.push({ + key: '4', + campo: 'Observação', + antigo: tombo.observacao, + novo: tomboAlterado.observacao, + }); + } + if (tombo.nomes_populares !== tomboAlterado.nomes_populares) { + parametros.push({ + key: '5', + campo: 'Nomes populares', + antigo: tombo.nomes_populares, + novo: tomboAlterado.nomes_populares, + }); + } + if (tombo.numero_coleta !== tomboAlterado.numero_coleta) { + parametros.push({ + key: '6', + campo: 'Numero de coleta', + antigo: tombo.numero_coleta, + novo: tomboAlterado.numero_coleta, + }); + } + if (tombo.latitude !== tomboAlterado.latitude) { + parametros.push({ + key: '7', + campo: 'Latitude', + antigo: tombo.latitude, + novo: tomboAlterado.latitude, + }); + } + if (tombo.longitude !== tomboAlterado.longitude) { + parametros.push({ + key: '8', + campo: 'Longitude', + antigo: tombo.longitude, + novo: tomboAlterado.longitude, + }); + } + if (tombo.altitude !== tomboAlterado.altitude) { + parametros.push({ + key: '9', + campo: 'Altitude', + antigo: tombo.altitude, + novo: tomboAlterado.altitude, + }); + } + if (tombo.herbario && tomboAlterado.herbario + && (tombo.herbario.nome !== tomboAlterado.herbario.nome)) { + parametros.push({ + key: '10', + campo: 'Herbário', + antigo: tombo.herbario.nome, + novo: tomboAlterado.herbario.nome, + }); + } + if (tombo.locais_coletum && tomboAlterado.locais_coletum + && tombo.locais_coletum.descricao !== tomboAlterado.locais_coletum.descricao) { + parametros.push({ + key: '11', + campo: 'Descrição do local de coleta', + antigo: tombo.locais_coletum.descricao, + novo: tomboAlterado.locais_coletum.descricao, + }); + } + if (tombo.locais_coletum && tombo.locais_coletum.solo + && tomboAlterado.locais_coletum && tomboAlterado.locais_coletum.solo + && tombo.locais_coletum.solo.nome !== tomboAlterado.locais_coletum.solo.nome) { + parametros.push({ + key: '12', + campo: 'Solo', + antigo: tombo.locais_coletum.solo.nome, + novo: tomboAlterado.locais_coletum.solo.nome, + }); + } + if (tombo.locais_coletum && tombo.locais_coletum.relevo + && tombo.locais_coletum && tombo.locais_coletum.relevo + && tombo.locais_coletum.relevo.nome !== tomboAlterado.locais_coletum.relevo.nome) { + parametros.push({ + key: '13', + campo: 'Relevo', + antigo: tombo.locais_coletum.relevo.nome, + novo: tomboAlterado.locais_coletum.relevo.nome, + }); + } + if (tombo.locais_coletum && tombo.locais_coletum.vegetaco + && tomboAlterado.locais_coletum && tomboAlterado.locais_coletum.vegetaco + && tombo.locais_coletum.vegetaco.nome !== tomboAlterado.locais_coletum.vegetaco.nome) { + parametros.push({ + key: '14', + campo: 'Vegetação', + antigo: tombo.locais_coletum.vegetaco.nome, + novo: tomboAlterado.locais_coletum.vegetaco.nome, + }); + } + if (tombo.locais_coletum && tombo.locais_coletum.cidade + && tomboAlterado.locais_coletum && tomboAlterado.locais_coletum.cidade + && tombo.locais_coletum.cidade.nome !== tomboAlterado.locais_coletum.cidade.nome) { + parametros.push({ + key: '15', + campo: 'Cidade', + antigo: tombo.locais_coletum.cidade.nome, + novo: tomboAlterado.locais_coletum.cidade.nome, + }); + } + if (tombo.locais_coletum && tomboAlterado.locais_coletum + && tombo.locais_coletum.fase_sucessional !== tomboAlterado.locais_coletum.fase_sucessional) { + parametros.push({ + key: '16', + campo: 'Fase Sucessional', + antigo: tombo.locais_coletum.fase_sucessional, + novo: tomboAlterado.locais_coletum.fase_sucessional, + }); + } + if (tombo.situacao !== tomboAlterado.situacao) { + parametros.push({ + key: '17', + campo: 'Situação', + antigo: tombo.situacao, + novo: tomboAlterado.situacao, + }); + } + if (tombo.nome_cientifico !== tomboAlterado.nome_cientifico) { + parametros.push({ + key: '18', + campo: 'Nome Científico', + antigo: tombo.nome_cientifico, + novo: tomboAlterado.nome_cientifico, + }); + } + if (tombo.variedade && tomboAlterado.variedade + && tombo.variedade.nome !== tomboAlterado.variedade.nome) { + parametros.push({ + key: '20', + campo: 'Variedade', + antigo: tombo.variedade.nome, + novo: tomboAlterado.variedade.nome, + }); + } + if (tombo.tipo && tomboAlterado.tipo + && tombo.tipo.nome !== tomboAlterado.tipo.nome) { + parametros.push({ + key: '21', + campo: 'Tipo', + antigo: tombo.tipo.nome, + novo: tomboAlterado.tipo.nome, + }); + } + if (tombo.especy && tomboAlterado.especy + && tombo.especy.nome !== tomboAlterado.especy.nome) { + parametros.push({ + key: '22', + campo: 'Espécie', + antigo: tombo.especy.nome, + novo: tomboAlterado.especy.nome, + }); + } + if (tombo.genero && tomboAlterado.genero + && tombo.genero.nome !== tomboAlterado.genero.nome) { + parametros.push({ + key: '23', + campo: 'Género', + antigo: tombo.genero.nome, + novo: tomboAlterado.genero.nome, + }); + } + if (tombo.familia && tomboAlterado.familia + && tombo.familia.nome !== tomboAlterado.familia.nome) { + parametros.push({ + key: '24', + campo: 'Família', + antigo: tombo.familia.nome, + novo: tomboAlterado.familia.nome, + }); + } + if (tombo.sub_familia && tomboAlterado.sub_familia + && tombo.sub_familia.nome !== tomboAlterado.sub_familia.nome) { + parametros.push({ + key: '25', + campo: 'Subfamília', + antigo: tombo.sub_familia.nome, + novo: tomboAlterado.sub_familia.nome, + }); + } + if (tombo.sub_especy && tomboAlterado.sub_especy + && tombo.sub_especy.nome !== tomboAlterado.sub_especy.nome) { + parametros.push({ + key: '26', + campo: 'Subespécie', + antigo: tombo.sub_especy.nome, + novo: tomboAlterado.sub_especy.nome, + }); + } + if (tombo.colecoes_anexa && tomboAlterado.colecoes_anexa + && tombo.colecoes_anexa.observacoes !== tomboAlterado.colecoes_anexa.observacoes) { + parametros.push({ + key: '27', + campo: 'Observações - Coleção Anexa', + antigo: tombo.colecoes_anexa.observacoes, + novo: tomboAlterado.colecoes_anexa.observacoes, + }); + } + if (tombo.colecoes_anexa && tomboAlterado.colecoes_anexa + && tombo.colecoes_anexa.tipo !== tomboAlterado.colecoes_anexa.tipo) { + parametros.push({ + key: '28', + campo: 'Tipo - Coleção Anexa', + antigo: tombo.colecoes_anexa.tipo, + novo: tomboAlterado.colecoes_anexa.tipo, + }); + } + + return parametros; +}; + +export const formatarTomboNovo = tombo => { + const parametros = []; + parametros.push({ + key: '1', + campo: 'Dia da coleta', + antigo: '', + novo: tombo.data_coleta_dia, + }); + parametros.push({ + key: '2', + campo: 'Mes da coleta', + antigo: '', + novo: tombo.data_coleta_mes, + }); + parametros.push({ + key: '3', + campo: 'Ano da coleta', + antigo: '', + novo: tombo.data_coleta_ano, + }); + parametros.push({ + key: '4', + campo: 'Observação', + antigo: '', + novo: tombo.observacao, + }); + parametros.push({ + key: '5', + campo: 'Nomes populares', + antigo: '', + novo: tombo.nomes_populares, + }); + parametros.push({ + key: '6', + campo: 'Numero de coleta', + antigo: '', + novo: tombo.numero_coleta, + }); + parametros.push({ + key: '7', + campo: 'Latitude', + antigo: '', + novo: tombo.latitude, + }); + parametros.push({ + key: '8', + campo: 'Longitude', + antigo: '', + novo: tombo.longitude, + }); + parametros.push({ + key: '9', + campo: 'Altitude', + antigo: '', + novo: tombo.altitude, + }); + if (tombo.herbario) { + parametros.push({ + key: '10', + campo: 'Herbário', + antigo: '', + novo: tombo.herbario.nome, + }); + } + if (tombo.locais_coletum) { + parametros.push({ + key: '11', + campo: 'Descrição do local de coleta', + antigo: '', + novo: tombo.locais_coletum.descricao, + }); + if (tombo.locais_coletum.solo) { + parametros.push({ + key: '12', + campo: 'Solo', + antigo: '', + novo: tombo.locais_coletum.solo.nome, + }); + } + if (tombo.locais_coletum.relevo) { + parametros.push({ + key: '13', + campo: 'Relevo', + antigo: '', + novo: tombo.locais_coletum.relevo.nome, + }); + } + if (tombo.locais_coletum.vegetaco) { + parametros.push({ + key: '14', + campo: 'Vegetação', + antigo: '', + novo: tombo.locais_coletum.vegetaco.nome, + }); + } + if (tombo.locais_coletum.cidade) { + parametros.push({ + key: '15', + campo: 'Cidade', + antigo: '', + novo: tombo.locais_coletum.cidade.nome, + }); + } + if (tombo.locais_coletum.fase_sucessional) { + parametros.push({ + key: '16', + campo: 'Fase Sucessional', + antigo: '', + novo: tombo.locais_coletum.fase_sucessional.nome, + }); + } + } + parametros.push({ + key: '17', + campo: 'Situação', + antigo: '', + novo: tombo.situacao, + }); + parametros.push({ + key: '18', + campo: 'Nome Científico', + antigo: '', + novo: tombo.nome_cientifico, + }); + if (tombo.variedade) { + parametros.push({ + key: '19', + campo: 'Variedade', + antigo: '', + novo: tombo.variedade.nome, + }); + } + if (tombo.tipo) { + parametros.push({ + key: '20', + campo: 'Tipo', + antigo: '', + novo: tombo.tipo.nome, + }); + } + if (tombo.especy) { + parametros.push({ + key: '21', + campo: 'Espécie', + antigo: '', + novo: tombo.especy.nome, + }); + } + if (tombo.genero) { + parametros.push({ + key: '22', + campo: 'Genero', + antigo: '', + novo: tombo.genero.nome, + }); + } + if (tombo.familia) { + parametros.push({ + key: '23', + campo: 'Família', + antigo: '', + novo: tombo.familia.nome, + }); + } + if (tombo.sub_familia) { + parametros.push({ + key: '24', + campo: 'Subfamília', + antigo: '', + novo: tombo.sub_familia.nome, + }); + } + if (tombo.sub_especy) { + parametros.push({ + key: '25', + campo: 'Subespécie', + antigo: '', + novo: tombo.sub_especy.nome, + }); + } + if (tombo.colecoes_anexa) { + parametros.push({ + key: '26', + campo: 'Observações - Coleção Anexa', + antigo: '', + novo: tombo.colecoes_anexa.observacoes, + }); + } + if (tombo.colecoes_anexa) { + parametros.push({ + key: '27', + campo: 'Tipo - Coleção Anexa', + antigo: '', + novo: tombo.colecoes_anexa.tipo, + }); + } + return parametros; +}; + +export const visualizarComCadastro = (alteracao, transaction) => { + let parametros = {}; + + return new Promise((resolve, reject) => { + + parametros = { + ...parametros, + numero_tombo: alteracao.tombo_hcf, + numero_tombo_alteracao: JSON.parse(alteracao.tombo_json).hcf, + }; + Tombo.findAll({ + where: { + hcf: { + [Op.in]: [alteracao.tombo_hcf, parametros.numero_tombo_alteracao], + }, + }, + include: [ + { + model: Herbario, + }, + { + model: Variedade, + }, + { + model: Tipo, + }, + { + model: Especie, + }, + { + model: Familia, + }, + { + model: Subfamilia, + }, + { + model: Genero, + }, + { + model: Subespecie, + }, + { + model: ColecaoAnexa, + }, + { + model: LocalColeta, + include: [ + { + model: Solo, + }, + { + model: Relevo, + }, + { + model: Vegetacao, + }, + { + model: Cidade, + }, + { + model: FaseSucessional, + }, + ], + }, + ], + transaction, + }) + .then(tombos => { + parametros = { + ...parametros, + retorno: [], + }; + if (tombos.length === 2) { + if (tombos[0].hcf === parametros.numero_tombo) { + parametros = { + ...parametros, + tombo: tombos[0], + tombo_alterado: tombos[1], + }; + } else { + parametros = { + ...parametros, + tombo: tombos[1], + tombo_alterado: tombos[0], + }; + } + parametros = comparaDoisTombos(parametros.tombo, parametros.tombo_alterado); + } else { + parametros = formatarTomboNovo(tombos[0]); + } + resolve(parametros); + }) + .catch(reject); + }); +}; + +const insereNoParametro = (key, campo, antigo, novo) => ({ + key, campo, antigo, novo, +}); + +const comparaDoisTombosOperador = (tombo, tomboAlterado) => { + const parametros = []; + // / colecoes anexas + if (tomboAlterado.colecoes_anexas) { + if (tombo.colecoes_anexa) { + if (tombo.colecoes_anexa.tipo !== tomboAlterado.colecoes_anexas.tipo) { + parametros.push(insereNoParametro('1', 'Coleções anexas tipo', tombo.colecoes_anexa.tipo, tomboAlterado.colecoes_anexas.tipo)); + } + if (tombo.colecoes_anexa.observacoes !== tomboAlterado.colecoes_anexas.observacoes) { + // eslint-disable-next-line + parametros.push( + insereNoParametro( + '2', + 'Coleções anexas observacoes', + tombo.colecoes_anexa.observacoes, + tomboAlterado.colecoes_anexas.observacoes + ) + ); + } + } else { + if (tomboAlterado.colecoes_anexas.tipo) { + parametros.push(insereNoParametro('1', 'Coleções anexas tipo', '', tomboAlterado.colecoes_anexas.tipo)); + } + if (tomboAlterado.colecoes_anexas.observacoes) { + parametros.push(insereNoParametro('2', 'Coleções anexas observacoes', '', tomboAlterado.colecoes_anexas.observacoes)); + } + } + } + // / coletores + let coletorPrincipalOrig = {}; + let coletoresOrig = ''; + let coletoresAlt = ''; + let novo = ''; + let antigo = ''; + + if (tomboAlterado.coletores) { + const colAlt = tomboAlterado.coletores; + for (let i = 0; i < colAlt.length; i++) { // eslint-disable-line + coletoresAlt += ` ${colAlt[i].nome} `; + } + novo = coletoresAlt; + } + if (tombo.coletores) { + const colOrig = tombo.coletores; + for (let i = 0; i < colOrig.length; i++) { // eslint-disable-line + if (colOrig[i].tombos_coletores.principal) { + coletorPrincipalOrig = { + id: colOrig[i].id, + nome: colOrig[i].nome, + }; + } else { + coletoresOrig += ` ${colOrig[i].nome} `; + } + } + antigo = coletoresOrig; + } + parametros.push(insereNoParametro('3', 'Coletores', antigo, novo)); + if (coletorPrincipalOrig.id) { + if (tomboAlterado.coletor_principal.id) { + if (coletorPrincipalOrig.id !== tomboAlterado.coletor_principal.id) { + parametros.push(insereNoParametro('4', 'Coletor principal', coletorPrincipalOrig.nome, tomboAlterado.coletor_principal.nome)); + } + } + } else if (tomboAlterado.coletor_principal.id) { + parametros.push(insereNoParametro('4', 'Coletor principal', '', tomboAlterado.coletor_principal.nome)); + } + // /////local de coleta + if (tomboAlterado.localidade) { + if (tomboAlterado.localidade.altitude) { + if (tombo.altitude) { + if (tombo.altitude !== tomboAlterado.localidade.altitude) { + parametros.push(insereNoParametro('5', 'Altitude', tombo.altitude, tomboAlterado.localidade.altitude)); + } + } else { + parametros.push(insereNoParametro('5', 'Altitude', '', tomboAlterado.localidade.altitude)); + } + } + if (tomboAlterado.localidade.cidade) { + if (tomboAlterado.localidade.cidade.id) { + if (tombo.locais_coletum && tombo.locais_coletum.cidade) { + if (tombo.locais_coletum.cidade.id !== tomboAlterado.localidade.cidade.id) { + parametros.push(insereNoParametro('6', 'Cidade', tombo.locais_coletum.cidade.nome, tomboAlterado.localidade.cidade.nome)); + } + } else { + parametros.push(insereNoParametro('6', 'Cidade', '', tomboAlterado.localidade.cidade.nome)); + } + } + } + if (tomboAlterado.localidade.latitude) { + if (tombo.latitude) { + if (converteParaDecimal(tomboAlterado.localidade.latitude) !== tombo.latitude) { + parametros.push(insereNoParametro('7', 'Latitude', tombo.latitude, tomboAlterado.localidade.latitude)); + } + } else { + parametros.push(insereNoParametro('7', 'Latitude', '', tomboAlterado.localidade.latitude)); + } + } + if (tomboAlterado.localidade.longitude) { + if (tombo.longitude) { + if (converteParaDecimal(tomboAlterado.localidade.longitude) !== tombo.longitude) { + parametros.push(insereNoParametro('8', 'Longitude', tombo.longitude, tomboAlterado.localidade.longitude)); + } + } else { + parametros.push(insereNoParametro('8', 'Longitude', '', tomboAlterado.localidade.longitude)); + } + } + } + + if (tomboAlterado.observacoes) { + if (tombo.observacoes) { + parametros.push(insereNoParametro('9', 'Observações', tombo.observacoes, tomboAlterado.observacoes)); + } else { + parametros.push(insereNoParametro('9', 'Observações', '', tomboAlterado.observacoes)); + } + } + + if (tomboAlterado.paisagem) { + const { + descricao, fase_sucessional: faseSucessional, relevo, solo, vegetacao, + } = tomboAlterado.paisagem; + if (descricao) { + if (tombo.locais_coletum && tombo.locais_coletum.descricao) { + if (descricao !== tombo.locais_coletum.descricao) { + parametros.push(insereNoParametro('10', 'Descrição do local de coleta', tombo.locais_coletum.descricao, descricao)); + } + } else { + parametros.push(insereNoParametro('10', 'Descrição do local de coleta', '', descricao)); + } + } + if (faseSucessional) { + if (tombo.locais_coletum && tombo.locais_coletum.fase_sucessional) { + if (tombo.locais_coletum.fase_sucessional.nome !== faseSucessional.nome) { + parametros.push(insereNoParametro('11', 'Fase sucessional', tombo.locais_coletum.nome, faseSucessional.nome)); + } + } else { + parametros.push(insereNoParametro('11', 'Fase sucessional', '', faseSucessional.nome)); + } + } + if (relevo) { + if (tombo.locais_coletum && tombo.locais_coletum.relevo) { + if (tombo.locais_coletum.relevo.nome !== relevo.nome) { + parametros.push(insereNoParametro('12', 'Relevo', tombo.locais_coletum.relevo.nome, relevo.nome)); + } + } else { + parametros.push(insereNoParametro('12', 'Relevo', '', relevo.nome)); + } + } + if (solo) { + if (tombo.locais_coletum && tombo.locais_coletum.solo) { + if (tombo.locais_coletum.solo.nome !== solo.nome) { + parametros.push(insereNoParametro('13', 'Solo', tombo.locais_coletum.solo.nome, solo.nome)); + } + } else { + parametros.push(insereNoParametro('13', 'Solo', '', solo.nome)); + } + } + if (vegetacao) { + if (tombo.locais_coletum && tombo.locais_coletum.vegetaco) { + if (tombo.locais_coletum.vegetaco.nome !== solo.nome) { + parametros.push(insereNoParametro('14', 'Vegetação', tombo.locais_coletum.vegetaco.nome, vegetacao.nome)); + } + } else { + parametros.push(insereNoParametro('14', 'Vegetação', '', vegetacao.nome)); + } + } + } + + if (tomboAlterado.principal) { + const { + data_coleta: dataColeta, entidade, + nome_popular: nomePopular, numero_coleta: numColeta, tipo, + } = tomboAlterado.principal; + + if (dataColeta) { + if (dataColeta.dia) { + if (tombo.data_coleta_dia) { + if (dataColeta.dia !== tombo.data_coleta_dia) { + parametros.push(insereNoParametro('16', 'Data coleta dia', tombo.data_coleta_dia, dataColeta.dia)); + } + } else { + parametros.push(insereNoParametro('16', 'Data coleta dia', '', dataColeta.dia)); + } + } + if (dataColeta.mes) { + if (tombo.data_coleta_mes) { + if (dataColeta.mes !== tombo.data_coleta_mes) { + parametros.push(insereNoParametro('17', 'Data coleta mes', tombo.data_coleta_mes, dataColeta.mes)); + } + } else { + parametros.push(insereNoParametro('17', 'Data coleta mes', '', dataColeta.mes)); + } + } + if (dataColeta.ano) { + if (tombo.data_coleta_ano) { + if (dataColeta.ano !== tombo.data_coleta_ano) { + parametros.push(insereNoParametro('18', 'Data coleta ano', tombo.data_coleta_ano, dataColeta.ano)); + } + } else { + parametros.push(insereNoParametro('18', 'Data coleta ano', '', dataColeta.ano)); + } + } + } + + if (entidade) { + if (tombo.herbario) { + if (entidade.id !== tombo.herbario.id) { + parametros.push(insereNoParametro('19', 'Herbário', tombo.herbario.nome, entidade.nome)); + } + } else { + parametros.push(insereNoParametro('19', 'Herbário', '', entidade.nome)); + } + } + + if (nomePopular) { + if (tombo.nome_populares) { + if (nomePopular !== tombo.nome_populares) { + parametros.push(insereNoParametro('20', 'Nomes populares', tombo.nome_populares, nomePopular)); + } + } else { + parametros.push(insereNoParametro('20', 'Nomes populares', '', nomePopular)); + } + } + + if (numColeta) { + if (tombo.numero_coleta) { + if (numColeta !== tombo.numero_coleta) { + parametros.push(insereNoParametro('21', 'Numero de coleta', numColeta, tombo.numero_coleta)); + } + } else { + parametros.push(insereNoParametro('21', 'Numero de coleta', '', tombo.numero_coleta)); + } + } + + if (tipo) { + if (tombo.tipo) { + if (tipo.id !== tombo.tipo.id) { + parametros.push(insereNoParametro('22', 'Tipo', tombo.tipo.nome, tipo.nome)); + } + } else { + parametros.push(insereNoParametro('22', 'Tipo', '', tipo.nome)); + } + } + } + + if (tomboAlterado.taxonomia) { + const { + especie, familia, genero, sub_especie: subEspecie, sub_familia: subFamilia, variedade, + } = tomboAlterado.taxonomia; + + if (especie) { + if (tombo.especy) { + if (especie.nome !== tombo.especy.nome) { + parametros.push(insereNoParametro('23', 'Especie', especie, tombo.especy.nome)); + } + } else { + parametros.push(insereNoParametro('23', 'Especie', '', especie.nome)); + } + } + + if (familia) { + if (tombo.familia) { + if (familia.nome !== tombo.familia.nome) { + parametros.push(insereNoParametro('24', 'Familia', familia, tombo.familia.nome)); + } + } else { + parametros.push(insereNoParametro('24', 'Familia', '', familia.nome)); + } + } + + if (genero) { + if (tombo.genero) { + if (genero.nome !== tombo.genero.nome) { + parametros.push(insereNoParametro('25', 'Genero', genero, tombo.genero.nome)); + } + } else { + parametros.push(insereNoParametro('25', 'Genero', '', genero.nome)); + } + } + + if (subEspecie) { + if (tombo.sub_especy) { + if (subEspecie.nome !== tombo.sub_especy) { + parametros.push(insereNoParametro('26', 'Subespecie', subEspecie, tombo.sub_especy.nome)); + } + } else { + parametros.push(insereNoParametro('26', 'Subespecie', '', subEspecie.nome)); + } + } + + if (subFamilia) { + if (tombo.sub_familia) { + if (subFamilia.nome !== tombo.sub_familia) { + parametros.push(insereNoParametro('27', 'Subfamilia', subFamilia, tombo.sub_familia.nome)); + } + } else { + parametros.push(insereNoParametro('27', 'Subfamilia', '', subFamilia.nome)); + } + } + + if (variedade) { + if (tombo.variedade) { + if (variedade.nome !== tombo.variedade) { + parametros.push(insereNoParametro('28', 'Variedade', variedade, tombo.variedade.nome)); + } + } else { + parametros.push(insereNoParametro('28', 'Variedade', '', variedade.nome)); + } + } + } + return parametros; + +}; + +export const visualizarAlteracaoOperador = (json, alteracao, transaction) => { + let parametros = {}; + + return new Promise((resolve, reject) => { + + parametros = { + ...parametros, + numero_tombo: alteracao.tombo_hcf, + }; + Tombo.findAll({ + where: { + hcf: alteracao.tombo_hcf, + }, + include: [ + { + model: Coletor, + }, + { + model: Herbario, + }, + { + model: Variedade, + }, + { + model: Tipo, + }, + { + model: Especie, + }, + { + model: Familia, + }, + { + model: Subfamilia, + }, + { + model: Genero, + }, + { + model: Subespecie, + }, + { + model: ColecaoAnexa, + }, + { + model: LocalColeta, + include: [ + { + model: Solo, + }, + { + model: Relevo, + }, + { + model: Vegetacao, + }, + { + model: Cidade, + }, + { + model: FaseSucessional, + }, + ], + }, + ], + transaction, + }) + .then(tombo => { + parametros = { + ...parametros, + tombo_original: tombo, + }; + const visualizacaoFormatada = comparaDoisTombosOperador(tombo, json); + parametros = { + ...parametros, + retorno: visualizacaoFormatada, + }; + resolve(visualizacaoFormatada); + }) + .catch(reject); + }); +}; + +export const aprovarPendencia = async (alteracao, hcf, transaction) => { + if (!alteracao || !hcf) { + throw new BadRequestExeption(404); + } + + const tomboAtual = await Tombo.findOne({ + where: { hcf }, + transaction, + raw: true, + nest: true, + }); + + if (!tomboAtual) { + throw new BadRequestExeption(404); + } + + const updateTombo = {}; + const nomesCientificosPartes = []; + + if (alteracao.nomes_populares !== undefined) { + updateTombo.nomes_populares = alteracao.nomes_populares; + } + + if (alteracao.unicata !== undefined) { + updateTombo.unicata = alteracao.unicata; + } + + if (alteracao.numero_coleta !== undefined) { + updateTombo.numero_coleta = alteracao.numero_coleta; + } + + if (alteracao.observacao !== undefined) { + updateTombo.observacao = alteracao.observacao; + } + + if (alteracao.data_tombo !== undefined) { + updateTombo.data_tombo = alteracao.data_tombo; + } + + if (alteracao.data_coleta_dia !== undefined) { + updateTombo.data_coleta_dia = alteracao.data_coleta_dia; + } + + if (alteracao.data_coleta_mes !== undefined) { + updateTombo.data_coleta_mes = alteracao.data_coleta_mes; + } + + if (alteracao.data_coleta_ano !== undefined) { + updateTombo.data_coleta_ano = alteracao.data_coleta_ano; + } + + if (alteracao.data_identificacao_dia !== undefined) { + updateTombo.data_identificacao_dia = alteracao.data_identificacao_dia; + } + + if (alteracao.data_identificacao_mes !== undefined) { + updateTombo.data_identificacao_mes = alteracao.data_identificacao_mes; + } + + if (alteracao.data_identificacao_ano !== undefined) { + updateTombo.data_identificacao_ano = alteracao.data_identificacao_ano; + } + + if (alteracao.latitude !== undefined) { + let latitudeValue = null; + if (alteracao.latitude !== null) { + if (typeof alteracao.latitude === 'string') { + latitudeValue = converteParaDecimal(alteracao.latitude); + } else { + latitudeValue = alteracao.latitude; + } + } + updateTombo.latitude = latitudeValue; + } + + if (alteracao.longitude !== undefined) { + let longitudeValue = null; + if (alteracao.longitude !== null) { + if (typeof alteracao.longitude === 'string') { + longitudeValue = converteParaDecimal(alteracao.longitude); + } else { + longitudeValue = alteracao.longitude; + } + } + updateTombo.longitude = longitudeValue; + } + + if (alteracao.altitude !== undefined) { + updateTombo.altitude = alteracao.altitude; + } + + if (alteracao.entidade_id !== undefined) { + if (alteracao.entidade_id !== null) { + const herbario = await Herbario.findOne({ + where: { id: alteracao.entidade_id }, + transaction, + raw: true, + nest: true, + }); + + if (!herbario) { + throw new BadRequestExeption(404); + } + } + updateTombo.entidade_id = alteracao.entidade_id; + } + + if (alteracao.tipo_id !== undefined) { + if (alteracao.tipo_id !== null) { + const tipo = await Tipo.findOne({ + where: { id: alteracao.tipo_id }, + transaction, + raw: true, + nest: true, + }); + + if (!tipo) { + throw new BadRequestExeption(404); + } + } + updateTombo.tipo_id = alteracao.tipo_id; + } + + if (alteracao.familia_id !== undefined) { + if (alteracao.familia_id !== null) { + const familia = await Familia.findOne({ + where: { id: alteracao.familia_id }, + transaction, + raw: true, + nest: true, + }); + + if (!familia) { + throw new BadRequestExeption(404); + } + } + + updateTombo.familia_id = alteracao.familia_id; + + if (alteracao.familia_id === null) { + updateTombo.sub_familia_id = null; + updateTombo.genero_id = null; + updateTombo.especie_id = null; + updateTombo.sub_especie_id = null; + updateTombo.variedade_id = null; + } + } + + if (alteracao.sub_familia_id !== undefined) { + if (alteracao.sub_familia_id !== null) { + const subfamilia = await Subfamilia.findOne({ + where: { + id: alteracao.sub_familia_id, + familia_id: updateTombo.familia_id || tomboAtual.familia_id, + }, + transaction, + raw: true, + nest: true, + }); + + if (!subfamilia) { + throw new BadRequestExeption(404); + } + } + + updateTombo.sub_familia_id = alteracao.sub_familia_id; + + if (alteracao.sub_familia_id === null) { + updateTombo.genero_id = null; + updateTombo.especie_id = null; + updateTombo.sub_especie_id = null; + updateTombo.variedade_id = null; + } + } + + if (alteracao.genero_id !== undefined) { + if (alteracao.genero_id !== null) { + const genero = await Genero.findOne({ + where: { + id: alteracao.genero_id, + familia_id: updateTombo.familia_id || tomboAtual.familia_id, + }, + transaction, + raw: true, + nest: true, + }); + + if (!genero) { + throw new BadRequestExeption(404); + } + nomesCientificosPartes.push(genero.nome); + } + + updateTombo.genero_id = alteracao.genero_id; + + if (alteracao.genero_id === null) { + updateTombo.especie_id = null; + updateTombo.sub_especie_id = null; + updateTombo.variedade_id = null; + } + } + + if (alteracao.especie_id !== undefined) { + if (alteracao.especie_id !== null) { + const especie = await Especie.findOne({ + where: { + id: alteracao.especie_id, + genero_id: updateTombo.genero_id || tomboAtual.genero_id, + }, + transaction, + raw: true, + nest: true, + }); + + if (!especie) { + throw new BadRequestExeption(404); + } + nomesCientificosPartes.push(especie.nome); + } + + updateTombo.especie_id = alteracao.especie_id; + + if (alteracao.especie_id === null) { + updateTombo.sub_especie_id = null; + updateTombo.variedade_id = null; + } + } + + if (alteracao.sub_especie_id !== undefined) { + if (alteracao.sub_especie_id !== null) { + const subespecie = await Subespecie.findOne({ + where: { + id: alteracao.sub_especie_id, + especie_id: updateTombo.especie_id || tomboAtual.especie_id, + }, + transaction, + raw: true, + nest: true, + }); + + if (!subespecie) { + throw new BadRequestExeption(404); + } + } + + updateTombo.sub_especie_id = alteracao.sub_especie_id; + + if (alteracao.sub_especie_id === null) { + updateTombo.variedade_id = null; + } + } + + if (alteracao.variedade_id !== undefined) { + if (alteracao.variedade_id !== null) { + const variedade = await Variedade.findOne({ + where: { + id: alteracao.variedade_id, + especie_id: updateTombo.especie_id || tomboAtual.especie_id, + }, + transaction, + raw: true, + nest: true, + }); + + if (!variedade) { + throw new BadRequestExeption(404); + } + } + + updateTombo.variedade_id = alteracao.variedade_id; + } + + if (nomesCientificosPartes.length > 0) { + updateTombo.nome_cientifico = nomesCientificosPartes.join(' '); + } else if (Object.keys(updateTombo).some(key => key.includes('genero_id') || key.includes('especie_id'))) { + updateTombo.nome_cientifico = null; + } + + if (alteracao.local_coleta_id !== undefined) { + if (alteracao.local_coleta_id !== null) { + const localColeta = await LocalColeta.findOne({ + where: { id: alteracao.local_coleta_id }, + transaction, + raw: true, + nest: true, + }); + + if (!localColeta) { + throw new BadRequestExeption(404); + } + } + updateTombo.local_coleta_id = alteracao.local_coleta_id; + } + + if (alteracao.descricao !== undefined) { + updateTombo.descricao = alteracao.descricao; + } + + if (alteracao.solo_id !== undefined) { + if (alteracao.solo_id !== null) { + const solo = await Solo.findOne({ + where: { id: alteracao.solo_id }, + transaction, + raw: true, + nest: true, + }); + + if (!solo) { + throw new BadRequestExeption(404); + } + } + updateTombo.solo_id = alteracao.solo_id; + } + + if (alteracao.relevo_id !== undefined) { + if (alteracao.relevo_id !== null) { + const relevo = await Relevo.findOne({ + where: { id: alteracao.relevo_id }, + transaction, + raw: true, + nest: true, + }); + + if (!relevo) { + throw new BadRequestExeption(404); + } + } + updateTombo.relevo_id = alteracao.relevo_id; + } + + if (alteracao.vegetacao_id !== undefined) { + if (alteracao.vegetacao_id !== null) { + const vegetacao = await Vegetacao.findOne({ + where: { id: alteracao.vegetacao_id }, + transaction, + raw: true, + nest: true, + }); + + if (!vegetacao) { + throw new BadRequestExeption(404); + } + } + updateTombo.vegetacao_id = alteracao.vegetacao_id; + } + + if (alteracao.coletor_id !== undefined) { + if (alteracao.coletor_id !== null) { + const coletor = await Coletor.findOne({ + where: { id: alteracao.coletor_id }, + transaction, + raw: true, + nest: true, + }); + + if (!coletor) { + throw new BadRequestExeption(404); + } + + } + updateTombo.coletor_id = alteracao.coletor_id; + } + + updateTombo.rascunho = false; + + if (Object.keys(updateTombo).length > 0) { + await Tombo.update(updateTombo, { + where: { hcf }, + transaction, + }); + } + + if (alteracao.identificadores !== undefined) { + await TomboIdentificador.destroy({ + where: { tombo_hcf: hcf }, + transaction, + }); + + if (Array.isArray(alteracao.identificadores) && alteracao.identificadores.length > 0) { + const identificadoresPromises = alteracao.identificadores.map(async (identificadorId, index) => { + const identificador = await Identificador.findOne({ + where: { id: identificadorId }, + transaction, + raw: true, + nest: true, + }); + + if (!identificador) { + throw new BadRequestExeption(404); + } + + return TomboIdentificador.create({ + tombo_hcf: hcf, + identificador_id: identificadorId, + ordem: index + 1, + }, { transaction }); + }); + + await Promise.all(identificadoresPromises); + } + } + + if (alteracao.complementares !== undefined) { + await ColetorComplementar.destroy({ + where: { hcf }, + transaction, + }); + + if (alteracao.complementares) { + await ColetorComplementar.create({ + hcf, + complementares: alteracao.complementares, + }, { transaction }); + } + } + + if (alteracao.colecoes_anexas_tipo !== undefined || alteracao.colecoes_anexas_observacoes !== undefined) { + const tomboAtualizado = await Tombo.findOne({ + where: { hcf }, + transaction, + raw: true, + nest: true, + }); + + if (tomboAtualizado.colecao_anexa_id) { + const updateColecao = {}; + + if (alteracao.colecoes_anexas_tipo !== undefined) { + updateColecao.tipo = alteracao.colecoes_anexas_tipo; + } + + if (alteracao.colecoes_anexas_observacoes !== undefined) { + updateColecao.observacoes = alteracao.colecoes_anexas_observacoes; + } + + if (Object.keys(updateColecao).length > 0) { + await ColecaoAnexa.update(updateColecao, { + where: { id: tomboAtualizado.colecao_anexa_id }, + transaction, + }); + } + } else if (alteracao.colecoes_anexas_tipo || alteracao.colecoes_anexas_observacoes) { + const novaColecao = await ColecaoAnexa.create({ + tipo: alteracao.colecoes_anexas_tipo, + observacoes: alteracao.colecoes_anexas_observacoes, + }, { transaction }); + + await Tombo.update({ + colecao_anexa_id: novaColecao.id, + }, { + where: { hcf }, + transaction, + }); + } + } + + const tomboFinal = await Tombo.findOne({ + where: { hcf, ativo: true }, + transaction, + raw: true, + nest: true, + }); + + return { + success: true, + message: 'Pendência aprovada com sucesso', + tombo: tomboFinal, + }; +}; + +export const visualizarComJsonNome = (alteracao, hcf, transaction) => new Promise((resolve, reject) => { + Tombo.findOne({ + where: { + hcf, + }, + include: [ + { + model: Variedade, + }, + { + model: Especie, + }, + { + model: Familia, + }, + { + model: Subfamilia, + }, + { + model: Genero, + }, + { + model: Subespecie, + }, + ], + transaction, + }) + .then(tombos => { + // eslint-disable-next-line + var jsonRetorno = []; + if (tombos.especy) { + if (alteracao.especie_nome) { + if (tombos.especy.nome !== alteracao.especie_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '1', + campo: 'Especie', + antigo: tombos.especy.nome, + novo: alteracao.especie_nome, + }); + } + } + } else if (alteracao.especie_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '1', + campo: 'Especie', + antigo: '', + novo: alteracao.especie_nome, + }); + } + if (tombos.familia) { + if (alteracao.familia_nome) { + if (tombos.familia.nome !== alteracao.familia_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '2', + campo: 'Familia', + antigo: tombos.familia.nome, + novo: alteracao.familia_nome, + }); + } + } + } else if (alteracao.familia_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '2', + campo: 'Familia', + antigo: '', + novo: alteracao.familia_nome, + }); + } + if (tombos.genero) { + if (alteracao.genero_nome) { + if (tombos.genero.nome !== alteracao.genero_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '3', + campo: 'Gênero', + antigo: tombos.genero.nome, + novo: alteracao.genero_nome, + }); + } + } + } else if (alteracao.genero_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '3', + campo: 'Gênero', + antigo: '', + novo: alteracao.genero_nome, + }); + } + if (tombos.variedade) { + if (alteracao.variedade_nome) { + if (tombos.variedade.nome !== alteracao.variedade_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '4', + campo: 'Variedade', + antigo: tombos.variedade.nome, + novo: alteracao.variedade_nome, + }); + } + } + } else if (alteracao.variedade_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '4', + campo: 'Variedade', + antigo: '', + novo: alteracao.variedade_nome, + }); + } + if (tombos.sub_especy) { + if (alteracao.subespecie_nome) { + if (tombos.sub_especy.nome !== alteracao.subespecie_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '5', + campo: 'Subespecie', + antigo: tombos.sub_especy.nome, + novo: alteracao.subespecie_nome, + }); + } + } + } else if (alteracao.subespecie_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '5', + campo: 'Subespecie', + antigo: '', + novo: alteracao.subespecie_nome, + }); + } + if (tombos.sub_familia || tombos.rascunho) { + if (alteracao.subfamilia_nome) { + if (tombos.sub_familia.nome !== alteracao.subfamilia_nome) { + jsonRetorno.push({ + key: '6', + campo: 'Subfamilia', + antigo: tombos.sub_familia.nome, + novo: alteracao.subfamilia_nome, + }); + } + } + } else if (alteracao.subfamilia_nome || tombos.rascunho) { + jsonRetorno.push({ + key: '6', + campo: 'Subfamilia', + antigo: '', + novo: alteracao.subfamilia_nome, + }); + } + resolve(jsonRetorno); + }) + .catch(reject); +}); + +export async function visualizar(request, response, next) { + try { + const id = request.params.pendencia_id; + const alteracao = await Alteracao.findOne({ + where: { ativo: true, id }, + }); + + if (!alteracao) { + throw new BadRequestExeption(800); + } + + const objetoAlterado = JSON.parse(alteracao.tombo_json); + const parametros = {}; + const alteracaoAprovada = alteracao.status === 'APROVADO'; + + if (objetoAlterado.nomes_populares !== undefined) { + parametros.nome_popular = objetoAlterado.nomes_populares; + } + + if (objetoAlterado.numero_coleta !== undefined) { + parametros.numero_coleta = objetoAlterado.numero_coleta; + } + + if (objetoAlterado.data_coleta_dia !== undefined) { + parametros.data_coleta_dia = objetoAlterado.data_coleta_dia; + } + + if (objetoAlterado.data_coleta_mes !== undefined) { + parametros.data_coleta_mes = objetoAlterado.data_coleta_mes; + } + + if (objetoAlterado.data_coleta_ano !== undefined) { + parametros.data_coleta_ano = objetoAlterado.data_coleta_ano; + } + + if (objetoAlterado.altitude !== undefined) { + parametros.altitude = objetoAlterado.altitude; + } + + if (objetoAlterado.local_coleta_id !== undefined) { + parametros.localColeta = await LocalColeta.findOne({ where: { id: objetoAlterado.local_coleta_id }, raw: true, nest: true }); + } + + if (objetoAlterado.descricao !== undefined) { + parametros.descricao = objetoAlterado.descricao; + } + + if (objetoAlterado.data_identificacao_dia !== undefined) { + parametros.data_identificacao_dia = objetoAlterado.data_identificacao_dia; + } + + if (objetoAlterado.data_identificacao_mes !== undefined) { + parametros.data_identificacao_mes = objetoAlterado.data_identificacao_mes; + } + + if (objetoAlterado.data_identificacao_ano !== undefined) { + parametros.data_identificacao_ano = objetoAlterado.data_identificacao_ano; + } + + if (objetoAlterado.colecoes_anexas_observacoes !== undefined) { + parametros.colecoes_anexas_observacoes = objetoAlterado.colecoes_anexas_observacoes; + } + + if (objetoAlterado.observacao !== undefined) { + parametros.observacoes = objetoAlterado.observacao; + } + + if (objetoAlterado.unicata !== undefined) { + parametros.unicata = objetoAlterado.unicata; + } + + if (objetoAlterado.latitude !== undefined) { + parametros.latitude = objetoAlterado.latitude; + } + + if (objetoAlterado.longitude !== undefined) { + parametros.longitude = objetoAlterado.longitude; + } + + if (objetoAlterado.coletor_id !== undefined) { + parametros.coletor = await Coletor.findOne({ where: { id: objetoAlterado.coletor_id }, raw: true, nest: true }); + } + + if (objetoAlterado.complementares !== undefined) { + parametros.complementares = objetoAlterado.complementares; + } + + if (objetoAlterado.familia_id !== undefined) { + parametros.familia = await Familia.findOne({ where: { id: objetoAlterado.familia_id }, raw: true, nest: true }); + } + + if (objetoAlterado.subfamilia_id !== undefined) { + parametros.subfamilia = await Subfamilia.findOne({ where: { id: objetoAlterado.subfamilia_id }, raw: true, nest: true }); + } + + if (objetoAlterado.genero_id !== undefined) { + parametros.genero = await Genero.findOne({ where: { id: objetoAlterado.genero_id }, raw: true, nest: true }); + } + + if (objetoAlterado.especie_id !== undefined) { + parametros.especie = await Especie.findOne({ where: { id: objetoAlterado.especie_id }, raw: true, nest: true }); + } + + if (objetoAlterado.identificadores !== undefined) { + const idsIdent = Array.isArray(objetoAlterado.identificadores) + ? objetoAlterado.identificadores + : [objetoAlterado.identificadores]; + parametros.identificadores = await Identificador.findAll({ + where: { id: { [Op.in]: idsIdent } }, + raw: true, + nest: true, + }); + } + + if (objetoAlterado.fase_sucessional_id !== undefined) { + parametros.faseSucessional = await FaseSucessional.findOne({ where: { numero: objetoAlterado.fase_sucessional_id }, raw: true, nest: true }); + } + + if (objetoAlterado.vegetacao_id !== undefined) { + parametros.vegetacao = await Vegetacao.findOne({ where: { id: objetoAlterado.vegetacao_id }, raw: true, nest: true }); + } + + if (objetoAlterado.relevo_id !== undefined) { + parametros.relevo = await Relevo.findOne({ where: { id: objetoAlterado.relevo_id }, raw: true, nest: true }); + } + + if (objetoAlterado.solo_id !== undefined) { + parametros.solo = await Solo.findOne({ where: { id: objetoAlterado.solo_id }, raw: true, nest: true }); + } + + if (objetoAlterado.cidade_id !== undefined) { + parametros.cidade = await Cidade.findOne({ where: { id: objetoAlterado.cidade_id }, raw: true, nest: true }); + } + + if (objetoAlterado.tipo_id !== undefined) { + parametros.tipo = await Tipo.findOne({ where: { id: objetoAlterado.tipo_id }, raw: true, nest: true }); + } + + if (objetoAlterado.entidade_id !== undefined) { + parametros.entidade = await Herbario.findOne({ where: { id: objetoAlterado.entidade_id }, raw: true, nest: true }); + } + + if (objetoAlterado.variedade_id !== undefined) { + parametros.variedade = await Variedade.findOne({ where: { id: objetoAlterado.variedade_id }, raw: true, nest: true }); + } + + if (objetoAlterado.sub_especie_id !== undefined) { + parametros.subespecie = await Subespecie.findOne({ where: { id: objetoAlterado.sub_especie_id }, raw: true, nest: true }); + } + + const tombo = await Tombo.findOne({ + where: { hcf: alteracao.dataValues.tombo_hcf }, + include: [ + { model: Variedade }, { model: Especie }, { model: Familia }, + { model: Subfamilia }, { model: Genero }, { model: Subespecie }, + { model: Herbario }, { model: Tipo }, { model: Coletor }, { model: ColetorComplementar, as: 'coletor_complementar' }, + { model: Solo }, { model: Relevo }, { model: Vegetacao }, { model: ColecaoAnexa }, + { + model: LocalColeta, + as: 'locais_coletum', + include: [{ model: Cidade }, { model: FaseSucessional }], + }, + { model: Usuario }, + ], + raw: true, + nest: true, + }); + + if (!tombo) { + throw new BadRequestExeption(801, 'Tombo não encontrado'); + } + + const jsonRetorno = []; + const ehRascunho = tombo?.rascunho === 1; + + const converteDecimalParaDMS = (decimal, isLatitude = true) => { + if (decimal === null || decimal === undefined || decimal === '') { + return ''; + } + + const abs = Math.abs(decimal); + const graus = Math.floor(abs); + const minutosDecimal = (abs - graus) * 60; + const minutos = Math.floor(minutosDecimal); + const segundos = ((minutosDecimal - minutos) * 60).toFixed(2); + + let hemisferio; + if (isLatitude) { + hemisferio = decimal >= 0 ? 'N' : 'S'; + } else { + hemisferio = decimal >= 0 ? 'E' : 'W'; + } + + return `${graus}° ${minutos}' ${segundos}" ${hemisferio}`; + }; + + const addRetorno = (key, campo, antigo, novo) => { + const antigoStr = String(antigo || '').trim(); + const novoStr = String(novo || '').trim(); + + if (antigoStr === '' && novoStr === '') { + return; + } + if (antigoStr !== novoStr) { + jsonRetorno.push({ key, campo, antigo: antigoStr, novo: novoStr }); + } + }; + + if (parametros.familia !== undefined) { + const nomeFamilia = typeof parametros.familia === 'string' ? parametros.familia : parametros.familia?.nome || ''; + const antigoFamilia = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.familia?.nome || ''); + addRetorno('1', 'Família', antigoFamilia, nomeFamilia); + } + + if (parametros.subfamilia !== undefined) { + const nomeSubfamilia = typeof parametros.subfamilia === 'string' ? parametros.subfamilia : parametros.subfamilia?.nome || ''; + const antigoSubfamilia = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.sub_familia?.nome || ''); + addRetorno('2', 'Subfamília', antigoSubfamilia, nomeSubfamilia); + } + + if (parametros.genero !== undefined) { + const nomeGenero = typeof parametros.genero === 'string' ? parametros.genero : parametros.genero?.nome || ''; + const antigoGenero = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.genero?.nome || ''); + addRetorno('3', 'Gênero', antigoGenero, nomeGenero); + } + + if (parametros.especie !== undefined) { + const nomeEspecie = typeof parametros.especie === 'string' ? parametros.especie : parametros.especie?.nome || ''; + const antigoEspecie = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.especy?.nome || ''); + addRetorno('4', 'Espécie', antigoEspecie, nomeEspecie); + } + + if (parametros.subespecie !== undefined) { + const antigoSubespecie = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.sub_especy?.nome || ''); + addRetorno('5', 'Subespécie', antigoSubespecie, parametros.subespecie?.nome || ''); + } + + if (parametros.variedade !== undefined) { + const antigoVariedade = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.variedade?.nome || ''); + addRetorno('6', 'Variedade', antigoVariedade, parametros.variedade?.nome || ''); + } + + if (parametros.coletor !== undefined) { + const antigoColetor = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.coletore?.nome || ''); + addRetorno('7', 'Coletor', antigoColetor, parametros.coletor?.nome || ''); + } + + if (parametros.complementares !== undefined) { + const complementaresAtuais = tombo?.coletor_complementar?.complementares || ''; + const complementaresNovos = parametros.complementares === null ? '' : parametros.complementares; + const antigoComplementares = (alteracaoAprovada || ehRascunho) ? '' : complementaresAtuais; + addRetorno('8', 'Coletores complementares', antigoComplementares, complementaresNovos); + } + + if (parametros.numero_coleta !== undefined) { + const antigoNumeroColeta = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.numero_coleta || ''); + addRetorno('9', 'Número da coleta', antigoNumeroColeta, parametros.numero_coleta); + } + + if (parametros.data_coleta_dia !== undefined) { + const antigoDataDia = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_coleta_dia || ''); + addRetorno('10', 'Data de coleta dia', antigoDataDia, parametros.data_coleta_dia); + } + + if (parametros.data_coleta_mes !== undefined) { + const antigoDataMes = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_coleta_mes || ''); + addRetorno('11', 'Data de coleta mês', antigoDataMes, parametros.data_coleta_mes); + } + + if (parametros.data_coleta_ano !== undefined) { + const antigoDataAno = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_coleta_ano || ''); + addRetorno('12', 'Data de coleta ano', antigoDataAno, parametros.data_coleta_ano); + } + + if (parametros.nome_popular !== undefined) { + const antigoNomePopular = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.nomes_populares || ''); + addRetorno('13', 'Nome popular', antigoNomePopular, parametros.nome_popular); + } + + if (parametros.entidade !== undefined) { + const antigoHerbario = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.herbario?.nome || ''); + addRetorno('14', 'Herbário', antigoHerbario, parametros.entidade?.nome || ''); + } + + if (parametros.tipo !== undefined) { + const antigoTipo = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.tipo?.nome || ''); + addRetorno('15', 'Tipo', antigoTipo, parametros.tipo?.nome || ''); + } + + if (parametros.latitude !== undefined) { + const antigoLatitude = (alteracaoAprovada || ehRascunho) ? '' : converteDecimalParaDMS(tombo?.latitude, true); + const novoLatitude = converteDecimalParaDMS(parametros.latitude, true); + addRetorno('16', 'Latitude', antigoLatitude, novoLatitude); + } + + if (parametros.longitude !== undefined) { + const antigoLongitude = (alteracaoAprovada || ehRascunho) ? '' : converteDecimalParaDMS(tombo?.longitude, false); + const novoLongitude = converteDecimalParaDMS(parametros.longitude, false); + addRetorno('17', 'Longitude', antigoLongitude, novoLongitude); + } + + if (parametros.altitude !== undefined) { + const antigoAltitude = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.altitude || ''); + addRetorno('18', 'Altitude', antigoAltitude, parametros.altitude); + } + + if (parametros.localColeta !== undefined) { + const antigoLocalColeta = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.locais_coletum?.descricao || ''); + addRetorno('19', 'Local de Coleta', antigoLocalColeta, parametros.localColeta?.descricao || ''); + } + + if (parametros.descricao !== undefined) { + const antigoDescricao = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.descricao || ''); + addRetorno('20', 'Descrição do relevo', antigoDescricao, parametros.descricao); + } + + if (parametros.solo !== undefined) { + const antigoSolo = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.solo?.nome || ''); + addRetorno('21', 'Solo', antigoSolo, parametros.solo?.nome || ''); + } + + if (parametros.relevo !== undefined) { + const antigoRelevo = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.relevo?.nome || ''); + addRetorno('22', 'Relevo', antigoRelevo, parametros.relevo?.nome || ''); + } + + if (parametros.vegetacao !== undefined) { + const antigoVegetacao = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.vegetaco?.nome || ''); + addRetorno('23', 'Vegetação', antigoVegetacao, parametros.vegetacao?.nome || ''); + } + + if (parametros.identificadores !== undefined) { + const identificadoresAtuais = await TomboIdentificador.findAll({ + attributes: ['tombo_hcf', 'identificador_id', 'ordem'], + where: { tombo_hcf: tombo?.hcf }, + include: [{ model: Identificador }], + order: [['ordem', 'ASC']], + raw: true, + nest: true, + }); + + const nomesNovos = parametros.identificadores.map(ident => ident.nome).join(', '); + const nomesAntigos = identificadoresAtuais.map(ident => ident.identificadore?.nome || '').join(', '); + const antigoIdentificadores = (alteracaoAprovada || ehRascunho) ? '' : nomesAntigos; + + addRetorno('24', 'Identificadores', antigoIdentificadores, nomesNovos); + } + + if (parametros.data_identificacao_dia !== undefined) { + const antigoDataIdentDia = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_identificacao_dia || ''); + addRetorno('25', 'Data de identificação dia', antigoDataIdentDia, parametros.data_identificacao_dia); + } + + if (parametros.data_identificacao_mes !== undefined) { + const antigoDataIdentMes = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_identificacao_mes || ''); + addRetorno('26', 'Data de identificação mês', antigoDataIdentMes, parametros.data_identificacao_mes); + } + + if (parametros.data_identificacao_ano !== undefined) { + const antigoDataIdentAno = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.data_identificacao_ano || ''); + addRetorno('27', 'Data de identificação ano', antigoDataIdentAno, parametros.data_identificacao_ano); + } + + if (objetoAlterado.colecoes_anexas_tipo !== undefined) { + const antigoTipoColecao = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.colecoes_anexa?.tipo || ''); + addRetorno('28', 'Tipo - Coleção Anexa', antigoTipoColecao, objetoAlterado.colecoes_anexas_tipo); + } + + if (parametros.colecoes_anexas_observacoes !== undefined) { + const antigoObsColecao = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.colecoes_anexa?.observacoes || ''); + addRetorno('29', 'Observações - Coleção Anexa', antigoObsColecao, parametros.colecoes_anexas_observacoes); + } + + if (parametros.observacoes !== undefined) { + const antigoObservacoes = (alteracaoAprovada || ehRascunho) ? '' : (tombo?.observacao || ''); + addRetorno('30', 'Observações', antigoObservacoes, parametros.observacoes); + } + + if (parametros.unicata !== undefined) { + let unicataAntigo; + if (alteracaoAprovada || ehRascunho) { + unicataAntigo = ''; + } else { + unicataAntigo = tombo?.unicata ? 'Unicata' : 'Duplicata'; + } + + const unicataNovo = parametros.unicata ? 'Unicata' : 'Duplicata'; + addRetorno('31', 'Tipo de Exsicata', unicataAntigo, unicataNovo); + } + + const jsonRender = { + fotos: { novas: [], antigas: [] }, + status: null, + tabela: jsonRetorno, + }; + + response.status(codigos.LISTAGEM).json(jsonRender); + } catch (error) { + next(error); + } +} + +export function aceitarPendencia(request, response, next) { + const id = request.params.pendencia_id; + const { observacao, status } = request.body; + let retorno = {}; + const callback = transaction => Promise.resolve() + .then(() => Alteracao.update({ + observacao, + status, + }, { + where: { + ativo: true, + id, + }, + transaction, + })) + .then(() => Alteracao.findOne({ + where: { + ativo: true, + id, + }, + transaction, + })) + .then(alt => { + if (status === 'APROVADO') { + const objetoAlterado = JSON.parse(alt.tombo_json); + retorno = aprovarPendencia(objetoAlterado, alt.tombo_hcf, transaction); + } + return retorno; + }); + sequelize.transaction(callback) + .then(() => { + // eslint-disable-next-line no-underscore-dangle + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); + +} + +export function avaliaPendencia(request, response, next) { + const { pendencia_id: pendenciaId } = request.params; + const { observacao, status } = request.body; + + return Promise.resolve() + .then(() => { + Alteracao.update({ + status, + observacao, + }, { + where: { + id: pendenciaId, + }, + }).then(pendencias => { + response.status(codigos.BUSCAR_UM_ITEM) + .json(pendencias); + }); + }) + .catch(next); +} + +export function verificaAlteracao(request, response, next) { + const { tombo_id: tomboId } = request.params; + const callback = transaction => Promise.resolve() + .then(() => Alteracao.findOne({ + where: { + status: 'ESPERANDO', + tombo_hcf: tomboId, + }, + transaction, + })) + .then(retorno => retorno); + sequelize.transaction(callback) + .then(retorno => { + response.status(codigos.BUSCAR_VARIOS_ITENS) + .json(retorno); + + }) + .catch(next); + +} +>>>>>>> origin/development diff --git a/src/controllers/remessa-controller.js b/src/controllers/remessa-controller.js index e378864..f4ea138 100644 --- a/src/controllers/remessa-controller.js +++ b/src/controllers/remessa-controller.js @@ -26,7 +26,6 @@ export const cadastro = (request, response, next) => { .then(() => { const { herbario_id: herbarioId } = request.body.remessa; const where = { - ativo: true, id: herbarioId, }; @@ -40,7 +39,6 @@ export const cadastro = (request, response, next) => { .then(() => { const { entidade_destino_id: entidadeDestino } = request.body.remessa; const where = { - ativo: true, id: entidadeDestino, }; @@ -59,7 +57,6 @@ export const cadastro = (request, response, next) => { return Tombo.findAndCountAll({ where: { [Op.or]: hcf, - ativo: 1, rascunho: 0, situacao: 'REGULAR', }, @@ -160,7 +157,6 @@ export const listagem = (request, response, next) => { whereTombo = { hcf: numTombo, rascunho: 0, - ativo: 1, }; } Promise.resolve() @@ -246,7 +242,6 @@ export const alteracao = (request, response, next) => { .then(() => { const { herbario_id: herbarioId } = request.body.remessa; const where = { - ativo: true, id: herbarioId, }; @@ -260,7 +255,6 @@ export const alteracao = (request, response, next) => { .then(() => { const { entidade_destino_id: entidadeDestino } = request.body.remessa; const where = { - ativo: true, id: entidadeDestino, }; @@ -298,7 +292,6 @@ export const alteracao = (request, response, next) => { return Tombo.findAndCountAll({ where: { [Op.or]: hcf, - ativo: 1, rascunho: 0, situacao: 'REGULAR', }, @@ -495,7 +488,6 @@ export const devolverTombo = (request, response, next) => { .then(() => Tombo.findOne({ where: { hcf, - ativo: 1, rascunho: 0, situacao: 'EMPRESTIMO', }, diff --git a/src/controllers/splinker-controller.js b/src/controllers/splinker-controller.js index a4879c6..e625e24 100644 --- a/src/controllers/splinker-controller.js +++ b/src/controllers/splinker-controller.js @@ -220,11 +220,6 @@ export const obterModeloSPLinker = async (request, response, next) => { const limit = request.query.limit > 1000 ? 1000 : request.query.limit || 1000; const quantidadeTombos = await Tombo.count( - { - where: { - ativo: true, - }, - }, { distinct: true } ); diff --git a/src/controllers/taxonomias-controller.js b/src/controllers/taxonomias-controller.js index b97815f..5dfa792 100644 --- a/src/controllers/taxonomias-controller.js +++ b/src/controllers/taxonomias-controller.js @@ -1,3 +1,4 @@ +<<<<<<< HEAD import BadRequestExeption from '../errors/bad-request-exception'; import models from '../models'; import codigos from '../resources/codigos-http'; @@ -1491,3 +1492,1461 @@ export const listagem = (request, response, next) => { }; export default {}; +======= +import BadRequestExeption from '../errors/bad-request-exception'; +import models from '../models'; +import codigos from '../resources/codigos-http'; +import listaTaxonomiasSQL from '../resources/sqls/lista-taxonomias'; +import verifyRecaptcha from '../utils/verify-recaptcha'; + +const { + sequelize, Sequelize: { Op }, Sequelize, Reino, Familia, Genero, Subfamilia, Especie, Variedade, Subespecie, Autor, Tombo, +} = models; +// ////////////////////FAMILIA/////////////////////////// +export const cadastrarFamilia = (request, response, next) => { + const { nome, reinoId } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => Familia.findOne({ + where: { + nome, + }, + transaction, + })) + .then(familiaEncontrada => { + if (familiaEncontrada) { + throw new BadRequestExeption(501); + } + }) + .then(() => Familia.create({ nome, reino_id: reinoId }, transaction)); + sequelize.transaction(callback) + .then(familiaCriada => { + if (!familiaCriada) { + throw new BadRequestExeption(502); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const cadastrarReino = (request, response, next) => { + const { nome } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => Reino.findOne({ + where: { + nome, + }, + transaction, + })) + .then(reinoEncontrado => { + if (reinoEncontrado) { + throw new BadRequestExeption(501); + } + }) + .then(() => Reino.create({ nome }, transaction)); + sequelize.transaction(callback) + .then(reinoCriado => { + if (!reinoCriado) { + throw new BadRequestExeption(502); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const editarReino = (request, response, next) => { + const id = request.params.reino_id; + const { nome } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => Reino.findOne({ + where: { + id, + }, + transaction, + })) + .then(reinoEncontrado => { + if (!reinoEncontrado) { + throw new BadRequestExeption(516); + } + }) + .then(() => Reino.update({ nome }, { + where: { + id, + }, + transaction, + })); + sequelize.transaction(callback) + .then(reinoEditado => { + if (!reinoEditado) { + throw new BadRequestExeption(502); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarReinos = async (request, response, next) => { + try { + if (request.query.recaptchaToken) { + await verifyRecaptcha(request); + } + + const { limite, pagina, offset } = request.paginacao; + const { orderClause } = request.ordenacao; + const { reino, reinoId } = request.query; + + let where; + if (reino) { + where = { nome: { [Op.like]: `%${reino}%` } }; + } + if (reinoId) { + where = { ...where, reino_id: reinoId }; + } + + const resultado = await Reino.findAndCountAll({ + attributes: ['id', 'nome'], + order: orderClause, + limit: limite, + offset, + where, + }); + + response.status(codigos.LISTAGEM).json({ + metadados: { + total: resultado.count, + pagina, + limite, + }, + resultado: resultado.rows, + }); + } catch (err) { + next(err); + } + return true; +}; + +export const buscarFamilias = async (request, response, next) => { + try { + if (request.query.recaptchaToken) { + await verifyRecaptcha(request); + } + + const { limite, pagina, offset } = request.paginacao; + const { orderClause } = request.ordenacao; + const { familia, reino_id: reinoId } = request.query; + + const where = {}; + if (familia) where.nome = { [Op.like]: `%${familia}%` }; + if (reinoId) where.reino_id = reinoId; + + const result = await Familia.findAndCountAll({ + attributes: ['id', 'nome'], + order: orderClause, + limit: limite, + offset, + where, + include: [{ model: Reino, attributes: ['id', 'nome'] }], + }); + + return response.status(codigos.LISTAGEM).json({ + metadados: { total: result.count, pagina, limite }, + resultado: result.rows, + }); + } catch (err) { + next(err); + } + return true; +}; + +export const editarFamilia = (request, response, next) => { + const id = request.params.familia_id; + const { nome } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => Familia.findOne({ + where: { + id, + }, + transaction, + })) + .then(familiaEncontrada => { + if (!familiaEncontrada) { + throw new BadRequestExeption(516); + } + }) + .then(() => Familia.update({ nome }, { + where: { + id, + }, + transaction, + })); + sequelize.transaction(callback) + .then(familiaCriada => { + if (!familiaCriada) { + throw new BadRequestExeption(502); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const excluirFamilia = (request, response, next) => { + const id = request.params.familia_id; + + const callback = transaction => + Promise.resolve() + .then(() => + Familia.findOne({ + where: { + id, + }, + transaction, + }) + ) + .then(familiaEncontrada => { + if (!familiaEncontrada) { + throw new BadRequestExeption(516); + } + }) + .then(() => + Promise.all([ + Genero.count({ where: { familia_id: id }, transaction }), + Tombo.count({ where: { familia_id: id }, transaction }), + ]) + ) + .then(([generosCount, tombosCount]) => { + if (generosCount > 0 || tombosCount > 0) { + throw new BadRequestExeption('A família não pode ser excluída porque possui dependentes.'); + } + }) + .then(() => + Familia.destroy({ + where: { + id, + }, + transaction, + }) + ); + + sequelize + .transaction(callback) + .then(() => { + response.status(codigos.DESATIVAR).send(); + }) + .catch(next); +}; +// /////////////////////SUBFAMILIA///////////////////////// +export const cadastrarSubfamilia = (request, response, next) => { + const { nome, familia_id: familiaId } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => Subfamilia.findOne({ + where: { + nome, + familia_id: familiaId, + }, + transaction, + })) + .then(subfamiliaEncontrada => { + if (subfamiliaEncontrada) { + throw new BadRequestExeption(503); + } + }) + .then(() => Familia.findOne({ + where: { + id: familiaId, + }, + transaction, + })) + .then(familiaEncontrada => { + if (!familiaEncontrada) { + throw new BadRequestExeption(516); + } + + return familiaEncontrada; + }) + .then(() => Subfamilia.create({ nome, + familia_id: familiaId, + }, transaction)); + sequelize.transaction(callback) + .then(subfamiliaCriado => { + if (!subfamiliaCriado) { + throw new BadRequestExeption(504); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarSubfamilia = async (req, res, next) => { + try { + if (req.query.recaptchaToken) { + await verifyRecaptcha(req); + } + + const { limite, pagina, offset } = req.paginacao; + const { orderClause } = req.ordenacao; + + const { + subfamilia: nomeFiltro, + familia_id: familiaIdRaw, + familia_nome: familiaNomeFiltro, + } = req.query; + + const where = {}; + if (nomeFiltro) { + where.nome = { [Op.like]: `%${nomeFiltro}%` }; + } + if (familiaIdRaw) { + const familiaId = parseInt(familiaIdRaw, 10); + if (!Number.isNaN(familiaId)) { + where.familia_id = familiaId; + } + } + + const familiaWhere = {}; + if (familiaNomeFiltro) { + familiaWhere.nome = { [Op.like]: `%${familiaNomeFiltro}%` }; + } + + const { count, rows } = await Subfamilia.findAndCountAll({ + attributes: ['id', 'nome'], + where, + order: orderClause, + limit: parseInt(limite, 10), + offset: parseInt(offset, 10), + include: [ + { model: Familia, attributes: ['id', 'nome'], where: familiaWhere }, + { model: Autor, attributes: ['id', 'nome'], as: 'autor' }, + ], + }); + + return res.status(codigos.LISTAGEM).json({ + metadados: { + total: count, + pagina: parseInt(pagina, 10), + limite: parseInt(limite, 10), + }, + resultado: rows, + }); + } catch (err) { + return next(err); + } +}; + +export const excluirSubfamilia = (request, response, next) => { + const id = request.params.subfamilia_id; + + const callback = transaction => + Promise.resolve() + .then(() => + Subfamilia.findOne({ + where: { + id, + }, + transaction, + }) + ) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(520); + } + }) + .then(() => + Promise.all([Tombo.count({ where: { sub_familia_id: id }, transaction })]) + ) + .then(([tombosCount]) => { + if (tombosCount > 0) { + throw new BadRequestExeption('A subfamília não pode ser excluída porque possui dependentes.'); + } + }) + .then(() => + Subfamilia.destroy({ + where: { + id, + }, + transaction, + }) + ); + + sequelize + .transaction(callback) + .then(() => { + response.status(codigos.DESATIVAR).send(); + }) + .catch(next); +}; + +export const editarSubfamilia = (request, response, next) => { + const { nome, familia_id: familiaId } = request.body; + const subfamiliaId = parseInt(request.params.subfamilia_id); + + const callback = transaction => Promise.resolve() + .then(() => Familia.findOne({ + where: { + id: familiaId, + }, + transaction, + })) + .then(familiaEncontrada => { + if (!familiaEncontrada) { + throw new BadRequestExeption(516); + } + }) + .then(() => Subfamilia.findOne({ + where: { + id: subfamiliaId, + }, + transaction, + })) + .then(subfEncontrado => { + if (!subfEncontrado) { + throw new BadRequestExeption(520); + } + }) + .then(() => Subfamilia.update({ nome, familia_id: familiaId }, { + where: { + id: subfamiliaId, + }, + transaction, + })); + sequelize.transaction(callback) + .then(subfCriado => { + if (!subfCriado) { + throw new BadRequestExeption(504); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +// //////////////////////GENERO///////////////////// +export const cadastrarGenero = (request, response, next) => { + const { nome, familia_id: familiaId } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => Genero.findOne({ + where: { + nome, + familia_id: familiaId, + }, + transaction, + })) + .then(generoEncontrado => { + if (generoEncontrado) { + throw new BadRequestExeption(505); + } + }) + .then(() => Familia.findOne({ + where: { + id: familiaId, + }, + transaction, + })) + .then(familiaEncontrada => { + if (!familiaEncontrada) { + throw new BadRequestExeption(516); + } + + return familiaEncontrada; + }) + .then(() => Genero.create({ nome, + familia_id: familiaId, + }, transaction)); + sequelize.transaction(callback) + .then(generoCriado => { + if (!generoCriado) { + throw new BadRequestExeption(506); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarGeneros = async (request, response, next) => { + try { + if (request.query.recaptchaToken) { + await verifyRecaptcha(request); + } + + const { limite, pagina, offset } = request.paginacao; + const { orderClause } = request.ordenacao; + const { genero, familia_id: familiaId, familia_nome: familiaNome } = request.query; + + const where = {}; + if (genero) where.nome = { [Op.like]: `%${genero}%` }; + if (familiaId) where.familia_id = familiaId; + + const familiaWhere = {}; + if (familiaNome) familiaWhere.nome = { [Op.like]: `%${familiaNome}%` }; + + const result = await Genero.findAndCountAll({ + attributes: ['id', 'nome'], + order: orderClause, + limit: limite, + offset, + where, + include: [ + { model: Familia, attributes: ['id', 'nome'], where: familiaWhere }, + ], + }); + + return response.status(codigos.LISTAGEM).json({ + metadados: { total: result.count, pagina, limite }, + resultado: result.rows, + }); + } catch (err) { + next(err); + } + return true; +}; + +export const excluirGeneros = (request, response, next) => { + const id = request.params.genero_id; + + const callback = transaction => + Promise.resolve() + .then(() => + Genero.findOne({ + where: { + id, + }, + transaction, + }) + ) + .then(generoEncontrado => { + if (!generoEncontrado) { + throw new BadRequestExeption(519); + } + }) + .then(() => + Promise.all([ + Especie.count({ where: { genero_id: id }, transaction }), + Tombo.count({ where: { genero_id: id }, transaction }), + ]) + ) + .then(([especiesCount, tombosCount]) => { + if (especiesCount > 0 || tombosCount > 0) { + throw new BadRequestExeption('O gênero não pode ser excluído porque possui dependentes.'); + } + }) + .then(() => + Genero.destroy({ + where: { + id, + }, + transaction, + }) + ); + + sequelize + .transaction(callback) + .then(() => { + response.status(codigos.DESATIVAR).send(); + }) + .catch(next); +}; + +export const editarGenero = (request, response, next) => { + const { nome, familia_id: familiaId } = request.body; + const generoId = parseInt(request.params.genero_id); + + const callback = transaction => Promise.resolve() + .then(() => Familia.findOne({ + where: { + id: familiaId, + }, + transaction, + })) + .then(familiaEncontrada => { + if (!familiaEncontrada) { + throw new BadRequestExeption(516); + } + }) + .then(() => Genero.findOne({ + where: { + id: generoId, + }, + transaction, + })) + .then(generoEncontrado => { + if (!generoEncontrado) { + throw new BadRequestExeption(519); + } + }) + .then(() => Genero.update({ nome, familia_id: familiaId }, { + where: { + id: generoId, + }, + transaction, + })); + sequelize.transaction(callback) + .then(generoCriado => { + if (!generoCriado) { + throw new BadRequestExeption(506); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; +// ///////////////////////ESPECIE//////////////////////////// +export const cadastrarEspecie = (request, response, next) => { + const { nome, genero_id: generoId, autor_id: autorId } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => { + if (!autorId) { + return undefined; + } + const where = { + id: autorId, + }; + return Autor.findOne({ + where, + transaction, + }); + }) + .then(autor => { + if (autorId) { + if (!autor) { + throw new BadRequestExeption(532); + } + } + }) + .then(() => Especie.findOne({ + where: { + nome, + genero_id: generoId, + }, + transaction, + })) + .then(especieEncontrada => { + if (especieEncontrada) { + throw new BadRequestExeption(507); + } + }) + .then(() => Genero.findOne({ + where: { + id: generoId, + }, + transaction, + })) + .then(generoEncontrado => { + if (!generoEncontrado) { + throw new BadRequestExeption(519); + } + return generoEncontrado; + }) + .then(genero => Especie.create( + { + nome, + genero_id: generoId, + familia_id: genero.familia_id, + autor_id: autorId, + }, + transaction + )); + sequelize.transaction(callback) + .then(especieCriada => { + if (!especieCriada) { + throw new BadRequestExeption(508); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarEspecies = async (request, response, next) => { + try { + if (request.query.recaptchaToken) { + await verifyRecaptcha(request); + } + + const { limite, pagina, offset } = request.paginacao; + const { orderClause } = request.ordenacao; + const { + especie, genero_id: generoId, + familia_nome: familiaNome, + genero_nome: generoNome, + } = request.query; + + const where = {}; + if (especie) where.nome = { [Op.like]: `%${especie}%` }; + if (generoId) where.genero_id = generoId; + + const familiaWhere = {}; + if (familiaNome) familiaWhere.nome = { [Op.like]: `%${familiaNome}%` }; + + const generoWhere = {}; + if (generoNome) generoWhere.nome = { [Op.like]: `%${generoNome}%` }; + + const result = await Especie.findAndCountAll({ + attributes: ['id', 'nome'], + order: orderClause, + limit: limite, + offset, + where, + include: [ + { model: Familia, attributes: ['id', 'nome'], where: familiaWhere }, + { model: Genero, attributes: ['id', 'nome'], where: generoWhere }, + { model: Autor, attributes: ['id', 'nome'], as: 'autor' }, + ], + }); + + return response.status(codigos.LISTAGEM).json({ + metadados: { total: result.count, pagina, limite }, + resultado: result.rows, + }); + } catch (err) { + next(err); + } + return true; +}; + +export const excluirEspecies = (request, response, next) => { + const id = request.params.especie_id; + + const callback = transaction => + Promise.resolve() + .then(() => + Especie.findOne({ + where: { + id, + }, + transaction, + }) + ) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(521); + } + }) + .then(() => + Promise.all([ + Subespecie.count({ where: { especie_id: id }, transaction }), + Variedade.count({ where: { especie_id: id }, transaction }), + Tombo.count({ where: { especie_id: id }, transaction }), + ]) + ) + .then(([subEspeciesCount, variedadesCount, tombosCount]) => { + if (subEspeciesCount > 0 || variedadesCount > 0 || tombosCount > 0) { + throw new BadRequestExeption('A espécie não pode ser excluída porque possui dependentes.'); + } + }) + .then(() => + Especie.destroy({ + where: { + id, + }, + transaction, + }) + ); + + sequelize + .transaction(callback) + .then(() => { + response.status(codigos.DESATIVAR).send(); + }) + .catch(next); +}; + +export const editarEspecie = (request, response, next) => { + const { nome, genero_id: generoId, autor_id: autorId } = request.body; + const especieId = parseInt(request.params.especie_id); + + const callback = transaction => Promise.resolve() + .then(() => Genero.findOne({ + where: { + id: generoId, + }, + transaction, + })) + .then(generoEncontrado => { + if (!generoEncontrado) { + throw new BadRequestExeption(519); + } + }) + .then(() => Especie.findOne({ + where: { + id: especieId, + }, + transaction, + })) + .then(especieEncontrado => { + if (!especieEncontrado) { + throw new BadRequestExeption(521); + } + }) + .then(() => { + if (autorId === null) { + return null; + } + const where = { + id: autorId, + }; + return Autor.findOne({ + where, + transaction, + }); + }) + .then(autor => { + if (autorId !== null) { + if (!autor) { + throw new BadRequestExeption(532); + } + } + }) + .then(() => Especie.update({ nome, genero_id: generoId, autor_id: autorId }, { + where: { + id: especieId, + }, + transaction, + })); + sequelize.transaction(callback) + .then(especieCriado => { + if (!especieCriado) { + throw new BadRequestExeption(522); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; +// ////////////////////SUBESPECIE/////////////////////////// +export const cadastrarSubespecie = (request, response, next) => { + const { nome, especie_id: especieId, autor_id: autorId } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => { + if (!autorId) { + return undefined; + } + const where = { + id: autorId, + }; + return Autor.findOne({ + where, + transaction, + }); + }) + .then(autor => { + if (autorId) { + if (!autor) { + throw new BadRequestExeption(532); + } + } + }) + .then(() => Subespecie.findOne({ + where: { + nome, + especie_id: especieId, + }, + transaction, + })) + .then(encontrado => { + if (encontrado) { + throw new BadRequestExeption(509); + } + }) + .then(() => Especie.findOne({ + where: { + id: especieId, + }, + transaction, + })) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(521); + } + return encontrado; + }) + .then(especie => Subespecie.create({ + nome, + genero_id: especie.genero_id, + especie_id: especieId, + familia_id: especie.familia_id, + autor_id: autorId, + }, transaction)); + sequelize.transaction(callback) + .then(subespecieCriada => { + if (!subespecieCriada) { + throw new BadRequestExeption(524); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarSubespecies = async (request, response, next) => { + try { + if (request.query.recaptchaToken) { + await verifyRecaptcha(request); + } + + const { limite, pagina, offset } = request.paginacao; + const { orderClause } = request.ordenacao; + const { + subespecie, + especie_id: especieId, + familia_nome: familiaNome, + genero_nome: generoNome, + especie_nome: especieNome, + } = request.query; + + const where = {}; + if (subespecie) where.nome = { [Op.like]: `%${subespecie}%` }; + if (especieId) where.especie_id = especieId; + + const familiaWhere = {}; + if (familiaNome) familiaWhere.nome = { [Op.like]: `%${familiaNome}%` }; + + const generoWhere = {}; + if (generoNome) generoWhere.nome = { [Op.like]: `%${generoNome}%` }; + + const especieWhere = {}; + if (especieNome) especieWhere.nome = { [Op.like]: `%${especieNome}%` }; + + const result = await Subespecie.findAndCountAll({ + attributes: ['id', 'nome'], + order: orderClause, + limit: limite, + offset, + where, + include: [ + { model: Familia, attributes: ['id', 'nome'], where: familiaWhere }, + { model: Genero, attributes: ['id', 'nome'], where: generoWhere }, + { model: Especie, attributes: ['id', 'nome'], where: especieWhere, as: 'especie' }, + { model: Autor, attributes: ['id', 'nome'], as: 'autor' }, + ], + }); + + return response.status(codigos.LISTAGEM).json({ + metadados: { total: result.count, pagina, limite }, + resultado: result.rows, + }); + } catch (err) { + next(err); + } + return true; +}; + +export const excluirSubespecies = (request, response, next) => { + const id = request.params.subespecie_id; + + const callback = transaction => + Promise.resolve() + .then(() => + Subespecie.findOne({ + where: { + id, + }, + transaction, + }) + ) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(525); + } + }) + .then(() => + Promise.all([Tombo.count({ where: { sub_especie_id: id }, transaction })]) + ) + .then(([tombosCount]) => { + if (tombosCount > 0) { + throw new BadRequestExeption('A subespécie não pode ser excluída porque possui dependentes.'); + } + }) + .then(() => + Subespecie.destroy({ + where: { + id, + }, + transaction, + }) + ); + + sequelize + .transaction(callback) + .then(() => { + response.status(codigos.DESATIVAR).send(); + }) + .catch(next); +}; + +export const editarSubespecie = (request, response, next) => { + const { nome, especie_id: especieId, autor_id: autorId } = request.body; + const subespecieId = parseInt(request.params.subespecie_id); + + const callback = transaction => Promise.resolve() + .then(() => Subespecie.findOne({ + where: { + id: subespecieId, + }, + transaction, + })) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(525); + } + }) + .then(() => { + if (autorId === null) { + return null; + } + const where = { + id: autorId, + }; + return Autor.findOne({ + where, + transaction, + }); + }) + .then(autor => { + if (autorId !== null) { + if (!autor) { + throw new BadRequestExeption(532); + } + } + }) + .then(() => Especie.findOne({ + where: { + id: especieId, + }, + transaction, + })) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(521); + } + return encontrado; + }) + .then(especie => Subespecie.update({ + nome, + especie_id: especieId, + genero_id: especie.genero_id, + familia_id: especie.familia_id, + autor_id: autorId, + }, { + where: { + id: subespecieId, + }, + transaction, + })); + sequelize.transaction(callback) + .then(especieCriado => { + if (!especieCriado) { + throw new BadRequestExeption(522); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +// //////////////////////VARIEDADE///////////////////////////// +export const cadastrarVariedade = (request, response, next) => { + const { nome, especie_id: especieId, autor_id: autorId } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => { + if (!autorId) { + return undefined; + } + const where = { + id: autorId, + }; + return Autor.findOne({ + where, + transaction, + }); + }) + .then(autor => { + if (autorId) { + if (!autor) { + throw new BadRequestExeption(532); + } + } + }) + .then(() => Variedade.findOne({ + where: { + nome, + especie_id: especieId, + }, + transaction, + })) + .then(encontrado => { + if (encontrado) { + throw new BadRequestExeption(511); + } + }) + .then(() => Especie.findOne({ + where: { + id: especieId, + }, + transaction, + })) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(521); + } + return encontrado; + }) + .then(especie => Variedade.create( + { + nome, + genero_id: especie.genero_id, + especie_id: especieId, + familia_id: especie.familia_id, + autor_id: autorId, + }, + transaction + )); + sequelize.transaction(callback) + .then(variedadeCriada => { + if (!variedadeCriada) { + throw new BadRequestExeption(512); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarVariedades = async (request, response, next) => { + try { + if (request.query.recaptchaToken) { + await verifyRecaptcha(request); + } + + const { limite, pagina, offset } = request.paginacao; + const { orderClause } = request.ordenacao; + const { + variedade, + especie_id: especieId, + familia_nome: familiaNome, + genero_nome: generoNome, + especie_nome: especieNome, + } = request.query; + + const where = {}; + if (variedade) where.nome = { [Op.like]: `%${variedade}%` }; + if (especieId) where.especie_id = especieId; + + const familiaWhere = {}; + if (familiaNome) familiaWhere.nome = { [Op.like]: `%${familiaNome}%` }; + + const generoWhere = {}; + if (generoNome) generoWhere.nome = { [Op.like]: `%${generoNome}%` }; + + const especieWhere = {}; + if (especieNome) especieWhere.nome = { [Op.like]: `%${especieNome}%` }; + + const result = await Variedade.findAndCountAll({ + attributes: ['id', 'nome'], + order: orderClause, + limit: limite, + offset, + where, + include: [ + { model: Familia, attributes: ['id', 'nome'], where: familiaWhere }, + { model: Genero, attributes: ['id', 'nome'], where: generoWhere }, + { model: Especie, attributes: ['id', 'nome'], where: especieWhere, as: 'especie' }, + { model: Autor, attributes: ['id', 'nome'], as: 'autor' }, + ], + }); + + return response.status(codigos.LISTAGEM).json({ + metadados: { total: result.count, pagina, limite }, + resultado: result.rows, + }); + } catch (err) { + next(err); + } + return true; +}; + +export const excluirVariedades = (request, response, next) => { + const id = request.params.variedade_id; + + const callback = transaction => Promise.resolve() + .then(() => Variedade.findOne({ + where: { + id, + }, + transaction, + })) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(526); + } + }) + .then(() => + Promise.all([Tombo.count({ where: { variedade_id: id }, transaction })]) + ) + .then(([tombosCount]) => { + if (tombosCount > 0) { + throw new BadRequestExeption('A variedade não pode ser excluída porque possui dependentes.'); + } + }) + .then(() => Variedade.destroy({ + where: { + id, + }, + transaction, + })); + sequelize.transaction(callback) + .then(() => { + response.status(codigos.DESATIVAR).send(); + }) + .catch(next); +}; + +export const editarVariedade = (request, response, next) => { + const { nome, especie_id: especieId, autor_id: autorId } = request.body; + const variedadeId = parseInt(request.params.variedade_id); + + const callback = transaction => Promise.resolve() + .then(() => { + if (autorId === null) { + return null; + } + const where = { + id: autorId, + }; + return Autor.findOne({ + where, + transaction, + }); + }) + .then(autor => { + if (autorId !== null) { + if (!autor) { + throw new BadRequestExeption(532); + } + } + }) + .then(() => Variedade.findOne({ + where: { + id: variedadeId, + }, + transaction, + })) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(526); + } + }) + .then(() => Especie.findOne({ + where: { + id: especieId, + }, + transaction, + })) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(521); + } + return encontrado; + }) + .then(especie => Variedade.update({ + nome, + especie_id: especieId, + genero_id: especie.genero_id, + familia_id: especie.familia_id, + autor_id: autorId, + }, { + where: { + id: variedadeId, + }, + transaction, + })); + sequelize.transaction(callback) + .then(variedade => { + if (!variedade) { + throw new BadRequestExeption(527); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +// //////////////////AUTORES////////////////// +export const cadastrarAutores = (request, response, next) => { + const { nome, iniciais } = request.body; + + const callback = transaction => Promise.resolve() + .then(() => Autor.findOne({ + where: { + nome, + }, + transaction, + })) + .then(autorEncontrado => { + if (autorEncontrado) { + throw new BadRequestExeption(513); + } + }) + .then(() => Autor.create({ nome, iniciais }, transaction)); + sequelize.transaction(callback) + .then(autorCriado => { + if (!autorCriado) { + throw new BadRequestExeption(514); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarAutores = async (request, response, next) => { + try { + if (request.query.recaptchaToken) { + await verifyRecaptcha(request); + } + + const { limite, pagina, offset } = request.paginacao; + const { autor } = request.query; + const { orderClause } = request.ordenacao; + + const where = {}; + if (autor) where.nome = { [Op.like]: `%${autor}%` }; + + const result = await Autor.findAndCountAll({ + attributes: ['id', 'nome', 'iniciais'], + order: orderClause, + limit: limite, + offset, + where, + }); + + return response.status(codigos.LISTAGEM).json({ + metadados: { total: result.count, pagina, limite }, + resultado: result.rows, + }); + } catch (err) { + next(err); + } + return true; +}; + +export const excluirAutores = (request, response, next) => { + const id = request.params.autor_id; + + const callback = transaction => + Promise.resolve() + .then(() => + Autor.findOne({ + where: { + id, + }, + transaction, + }) + ) + .then(encontrado => { + if (!encontrado) { + throw new BadRequestExeption(517); + } + }) + .then(() => + Promise.all([ + Subespecie.count({ where: { autor_id: id }, transaction }), + Especie.count({ where: { autor_id: id }, transaction }), + Variedade.count({ where: { autor_id: id }, transaction }), + ]) + ) + .then(([subEspeciesCount, especiesCount, variedadesCount]) => { + if (subEspeciesCount > 0 || especiesCount > 0 || variedadesCount > 0) { + throw new BadRequestExeption('O autor não pode ser excluído porque possui dependentes.'); + } + }) + .then(() => + Autor.destroy({ + where: { + id, + }, + transaction, + }) + ); + + sequelize + .transaction(callback) + .then(() => { + response.status(codigos.DESATIVAR).send(); + }) + .catch(next); +}; + +export const editarAutores = (request, response, next) => { + const { nome, iniciais } = request.body; + const autorId = parseInt(request.params.autor_id); + + const callback = transaction => Promise.resolve() + .then(() => Autor.findOne({ + where: { + id: autorId, + }, + transaction, + })) + .then(autorEncontrado => { + if (!autorEncontrado) { + throw new BadRequestExeption(517); + } + }) + .then(() => Autor.update({ nome, iniciais }, { + where: { + id: autorId, + }, + transaction, + })); + sequelize.transaction(callback) + .then(autorAtualizado => { + if (!autorAtualizado) { + throw new BadRequestExeption(523); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; +// ////////////////////////////////////////////// +export const listagem = (request, response, next) => { + + const sequelizeQueryTaxonomias = (limite, offset) => new Promise((resolve, reject) => { + + const type = Sequelize.QueryTypes.SELECT; + sequelize.query(listaTaxonomiasSQL(true, limite, offset), { type }) + .then(resultadoCount => { + let count = 0; + if (Array.isArray(resultadoCount) && resultadoCount.length > 0) { + count = resultadoCount[0].count; // eslint-disable-line + } + + const retorno = { count }; + + return sequelize.query(listaTaxonomiasSQL(false, limite, offset), { type }) + .then(resultado => ({ + ...retorno, + rows: resultado, + })); + }) + .then(resolve) + .catch(reject); + }); + + const { limite, pagina, offset } = request.paginacao; + + Promise.resolve() + .then(() => sequelizeQueryTaxonomias(limite, offset)) + .then(resultado => { + response.status(200) + .json({ + metadados: { + total: resultado.count, + pagina, + limite, + }, + resultado: resultado.rows, + }); + }) + .catch(next); +}; + +export default {}; +>>>>>>> origin/development diff --git a/src/controllers/tombos-controller.js b/src/controllers/tombos-controller.js index 795dc92..c7727c0 100644 --- a/src/controllers/tombos-controller.js +++ b/src/controllers/tombos-controller.js @@ -1,3 +1,4 @@ +<<<<<<< HEAD /* eslint-disable quotes */ // @ts-nocheck import { ForeignKeyConstraintError } from 'sequelize'; @@ -1647,4 +1648,1641 @@ export const editarCodigoBarra = (request, response, next) => { .catch(next); }; -export default {}; \ No newline at end of file +export default {}; +======= +/* eslint-disable quotes */ +// @ts-nocheck +import { ForeignKeyConstraintError } from 'sequelize'; + +import { padronizarNomeDarwincore } from '~/helpers/padroniza-nome-darwincore'; + +import BadRequestExeption from '../errors/bad-request-exception'; +import NotFoundException from '../errors/not-found-exception'; +import { + converteParaDecimal, converteDecimalParaGraus, converteDecimalParaGMSGrau, converteDecimalParaGMSMinutos, converteDecimalParaGMSSegundos, +} from '../helpers/coordenadas'; +import pick from '../helpers/pick'; +import { converteInteiroParaRomano } from '../helpers/tombo'; +import models from '../models'; +import codigos from '../resources/codigos-http'; +import verifyRecaptcha from '../utils/verify-recaptcha'; +import { aprovarPendencia } from './pendencias-controller'; + +const { + Solo, Relevo, Cidade, Estado, Vegetacao, FaseSucessional, Pais, Tipo, LocalColeta, Familia, sequelize, + Genero, Subfamilia, Autor, Coletor, Variedade, Subespecie, TomboFoto, Identificador, + ColecaoAnexa, Especie, Herbario, Tombo, Alteracao, TomboIdentificador, ColetorComplementar, Sequelize: { Op }, +} = models; + +function parseDataTombo(valor) { + const partes = valor.split(/[-]/).map(p => p.trim()); + if (partes.length >= 3) { + const [anoStr, mesStr, diaStr] = partes; + const dia = parseInt(diaStr, 10); + const mes = parseInt(mesStr, 10) - 1; + const ano = parseInt(anoStr, 10); + if (!Number.isNaN(dia) && !Number.isNaN(mes) && !Number.isNaN(ano)) { + return new Date(ano, mes, dia, 12, 0, 0, 0); + } + return null; + } + return null; +} + +export const cadastro = (request, response, next) => { + const { + principal, + taxonomia, + localidade, + paisagem, + identificacao, + coletor, + // eslint-disable-next-line @typescript-eslint/naming-convention + coletor_complementar, + colecoes_anexas: colecoesAnexas, + observacoes, + unicata, + } = request.body.json; + let tomboCriado = null; + + const callback = transaction => + Promise.resolve() + .then(() => { + if (!paisagem || !paisagem.solo_id) { + return undefined; + } + + const where = { + id: paisagem.solo_id, + }; + + return Solo.findOne({ where, transaction }); + }) + .then(solo => { + if (paisagem && paisagem.solo_id) { + if (!solo) { + throw new BadRequestExeption(528); + } + } + if (paisagem && paisagem.relevo_id) { + return Relevo.findOne({ + where: { + id: paisagem.relevo_id, + }, + transaction, + }); + } + return undefined; + }) + .then(relevo => { + if (paisagem && paisagem.relevo_id) { + if (!relevo) { + throw new BadRequestExeption(529); + } + } + if (paisagem && paisagem.vegetacao_id) { + return Vegetacao.findOne({ + where: { + id: paisagem.vegetacao_id, + }, + transaction, + }); + } + return undefined; + }) + .then(vegetacao => { + if (paisagem && paisagem.vegetacao_id) { + if (!vegetacao) { + throw new BadRequestExeption(530); + } + } + if (paisagem && paisagem.fase_sucessional_id) { + return FaseSucessional.findOne({ + where: { + numero: paisagem.fase_sucessional_id, + }, + transaction, + }); + } + return undefined; + }) + .then(fase => { + if (paisagem && paisagem.fase_sucessional_id) { + if (!fase) { + throw new BadRequestExeption(531); + } + } + return undefined; + }) + .then(() => { + if (!localidade?.local_coleta_id) { + throw new BadRequestExeption(400); + } + return LocalColeta.findOne({ + where: { + id: localidade.local_coleta_id, + }, + transaction, + }); + }) + .then(localColeta => { + if (!localColeta) { + throw new BadRequestExeption(533); + } + return undefined; + }) + // //////////////CRIA COLECOES ANEXAS/////////// + .then(() => { + if (colecoesAnexas) { + const object = pick(colecoesAnexas, ['tipo', 'observacoes']); + return ColecaoAnexa.create(object, { transaction }); + } + return undefined; + }) + .then(colecao => { + if (colecoesAnexas) { + if (!colecao) { + throw new BadRequestExeption(401); + } + colecoesAnexas.id = colecao.id; + } + return undefined; + }) + // ///////// VALIDA A TAXONOMIA E A INSERE NO NOME CIENTIFICO ////////// + .then(() => { + if (taxonomia && taxonomia.familia_id) { + return Familia.findOne({ + where: { + id: taxonomia.familia_id, + }, + transaction, + }); + } + return undefined; + }) + .then(familia => { + if (taxonomia && taxonomia.familia_id) { + if (!familia) { + throw new BadRequestExeption(402); + } + } + return undefined; + }) + .then(() => { + if (taxonomia && taxonomia.sub_familia_id) { + return Subfamilia.findOne({ + where: { + id: taxonomia.sub_familia_id, + familia_id: taxonomia.familia_id, + }, + transaction, + }); + } + return undefined; + }) + .then(subfamilia => { + if (taxonomia && taxonomia.sub_familia_id) { + if (!subfamilia) { + throw new BadRequestExeption(403); + } + } + return undefined; + }) + .then(() => { + if (taxonomia && taxonomia.genero_id) { + return Genero.findOne({ + where: { + id: taxonomia.genero_id, + familia_id: taxonomia.familia_id, + }, + transaction, + }); + } + return undefined; + }) + .then(genero => { + if (taxonomia && taxonomia.genero_id) { + if (!genero) { + throw new BadRequestExeption(404); + } + taxonomia.nome_cientifico = genero.nome; + } + return undefined; + }) + .then(() => { + if (taxonomia && taxonomia.especie_id) { + return Especie.findOne({ + where: { + id: taxonomia.especie_id, + genero_id: taxonomia.genero_id, + }, + transaction, + }); + } + return undefined; + }) + .then(especie => { + if (taxonomia && taxonomia.especie_id) { + if (!especie) { + throw new BadRequestExeption(405); + } + taxonomia.nome_cientifico += ` ${especie.nome}`; + } + return undefined; + }) + .then(() => { + if (taxonomia && taxonomia.sub_especie_id) { + return Subespecie.findOne({ + where: { + id: taxonomia.sub_especie_id, + especie_id: taxonomia.especie_id, + }, + transaction, + }); + } + return undefined; + }) + .then(subespecie => { + if (taxonomia && taxonomia.sub_especie_id) { + if (!subespecie) { + throw new BadRequestExeption(406); + } + } + return undefined; + }) + .then(() => { + if (taxonomia && taxonomia.variedade_id) { + return Variedade.findOne({ + where: { + id: taxonomia.variedade_id, + especie_id: taxonomia.especie_id, + }, + transaction, + }); + } + return undefined; + }) + .then(variedade => { + if (taxonomia && taxonomia.variedade_id) { + if (!variedade) { + throw new BadRequestExeption(407); + } + } + return undefined; + }) + // /////////// CADASTRA TOMBO ///////////// + .then(() => { + let jsonTombo = { + data_coleta_dia: principal.data_coleta.dia, + data_coleta_mes: principal.data_coleta.mes, + data_coleta_ano: principal.data_coleta.ano, + numero_coleta: principal.numero_coleta, + local_coleta_id: localidade.local_coleta_id, + coletor_id: coletor, + data_tombo: parseDataTombo(principal.data_tombo), + }; + + if (paisagem?.descricao) { + jsonTombo.descricao = paisagem.descricao; + } + + if (observacoes) { + jsonTombo.observacao = observacoes; + } + if (unicata !== undefined) { + jsonTombo.unicata = unicata; + } + if (principal.nome_popular) { + jsonTombo.nomes_populares = principal.nome_popular; + } + if (localidade.latitude) { + jsonTombo.latitude = converteParaDecimal(localidade.latitude); + } + if (localidade.longitude) { + jsonTombo.longitude = converteParaDecimal(localidade.longitude); + } + if (localidade.altitude) { + jsonTombo.altitude = localidade.altitude; + } + if (identificacao) { + jsonTombo.data_identificacao_dia = identificacao.data_identificacao?.dia; + jsonTombo.data_identificacao_mes = identificacao.data_identificacao?.mes; + jsonTombo.data_identificacao_ano = identificacao.data_identificacao?.ano; + } + if (paisagem) { + jsonTombo.solo_id = paisagem.solo_id; + jsonTombo.relevo_id = paisagem.relevo_id; + jsonTombo.vegetacao_id = paisagem.vegetacao_id; + } + jsonTombo = { + ...jsonTombo, + ...pick(principal, ['entidade_id', 'tipo_id', 'taxon_id']), + }; + if (taxonomia) { + jsonTombo = { + ...jsonTombo, + // eslint-disable-next-line max-len + ...pick(taxonomia, ['nome_cientifico', 'variedade_id', 'especie_id', 'genero_id', 'familia_id', 'sub_familia_id', 'sub_especie_id']), + }; + } + if (colecoesAnexas && colecoesAnexas.id) { + jsonTombo.colecao_anexa_id = colecoesAnexas.id; + } + if (request.usuario.tipo_usuario_id === 2 || request.usuario.tipo_usuario_id === 3) { + jsonTombo.rascunho = true; + } + return Tombo.create(jsonTombo, { transaction }); + }) + // //////////// CADASTRA A ALTERACAO /////////// + .then(tombo => { + if (!tombo) { + throw new BadRequestExeption(408); + } + let status = 'ESPERANDO'; + principal.hcf = tombo.hcf; + if (request.usuario.tipo_usuario_id === 1) { + status = 'APROVADO'; + } + + const dadosComplementares = coletor_complementar?.complementares || ''; + + const tomboData = { ...tombo.toJSON(), complementares: dadosComplementares, colecoes_anexas_tipo: colecoesAnexas?.tipo || null, colecoes_anexas_observacoes: colecoesAnexas?.observacoes || null }; + + if (identificacao?.identificadores && identificacao.identificadores.length > 0) { + tomboData.identificadores = identificacao.identificadores; + } + + const dados = { + tombo_hcf: tombo.hcf, + usuario_id: request.usuario.id, + status, + tombo_json: JSON.stringify(tomboData), + ativo: true, + identificacao: 0, + }; + tomboCriado = tombo; + + return Alteracao.create(dados, { transaction }).then(alteracaoTomboCriado => { + if (!alteracaoTomboCriado) { + throw new BadRequestExeption(409); + } + + if (coletor_complementar && coletor_complementar.complementares) { + const jsonColetorComplementar = { + hcf: principal.hcf, + complementares: coletor_complementar.complementares, + }; + + return ColetorComplementar.create(jsonColetorComplementar, { transaction }); + } + + return alteracaoTomboCriado; + }); + }) + // /////////////// CADASTRA O INDETIFICADOR /////////////// + .then(alteracaoTomboCriado => { + if (!alteracaoTomboCriado) { + throw new BadRequestExeption(409); + } + if (tomboCriado !== null) { + if (identificacao && identificacao.identificadores && identificacao.identificadores.length > 0) { + const promises = identificacao.identificadores.map((identificador_id, index) => { + const isPrincipal = index === 0; + const dadosIdentificadores = { + identificador_id, + tombo_hcf: tomboCriado.hcf, + ordem: index + 1, + principal: isPrincipal, + }; + return TomboIdentificador.create(dadosIdentificadores, { + transaction, + }); + }); + return Promise.all(promises); + } + } + return undefined; + }); + + sequelize.transaction(callback) + .then(() => { + response.status(codigos.CADASTRO_RETORNO).json({ + hcf: principal.hcf, + }); + }) + .catch(next); +}; + +function alteracaoIdentificador(request, transaction) { + const { + familia_id: familiaId, subfamilia_id: subfamiliaId, genero_id: generoId, + especie_id: especieId, subespecie_id: subespecieId, variedade_id: variedadeId, + } = request.body; + const { tombo_id: tomboId } = request.params; + const update = {}; + + if (familiaId !== undefined) { + update.familia_id = familiaId; + } + if (subfamiliaId !== undefined) { + update.subfamilia_id = subfamiliaId; + } + if (generoId !== undefined) { + update.genero_id = generoId; + } + if (especieId !== undefined) { + update.especie_id = especieId; + } + if (subespecieId !== undefined) { + update.subespecie_id = subespecieId; + } + if (variedadeId !== undefined) { + update.variedade_id = variedadeId; + } + + return Promise.resolve() + .then(() => Alteracao.create({ + tombo_hcf: tomboId, + usuario_id: request.usuario.id, + status: 'ESPERANDO', + tombo_json: JSON.stringify(update), + ativo: true, + identificacao: 1, + }, { transaction })) + .then(alteracaoIdent => { + if (request.usuario.tipo_usuario_id === 3) { + if (!alteracaoIdent) { + throw new BadRequestExeption(421); + } + } + }); +} + +function alteracaoCuradorouOperador(request, response, transaction) { + const { body } = request; + const update = {}; + + const nomePopular = body?.principal?.nome_popular; + if (nomePopular !== undefined) update.nomes_populares = nomePopular; + + const entidadeId = body?.principal?.entidade_id; + if (entidadeId !== undefined) update.entidade_id = entidadeId; + + const numeroColeta = body?.principal?.numero_coleta; + if (numeroColeta !== undefined) update.numero_coleta = numeroColeta; + + const dataColeta = body?.principal?.data_coleta; + if (dataColeta?.dia !== undefined) update.data_coleta_dia = dataColeta.dia; + if (dataColeta?.mes !== undefined) update.data_coleta_mes = dataColeta.mes; + if (dataColeta?.ano !== undefined) update.data_coleta_ano = dataColeta.ano; + + const tipoId = body?.principal?.tipo_id; + if (tipoId !== undefined) update.tipo_id = tipoId; + + const dataTombo = body?.principal?.data_tombo; + if (dataTombo !== undefined) update.data_tombo = parseDataTombo(dataTombo); + + const familiaId = body?.taxonomia?.familia_id; + if (familiaId !== undefined) update.familia_id = familiaId; + + const subfamiliaId = body?.taxonomia?.sub_familia_id; + if (subfamiliaId !== undefined) update.sub_familia_id = subfamiliaId; + + const generoId = body?.taxonomia?.genero_id; + if (generoId !== undefined) update.genero_id = generoId; + + const especieId = body?.taxonomia?.especie_id; + if (especieId !== undefined) update.especie_id = especieId; + + const subespecieId = body?.taxonomia?.sub_especie_id; + if (subespecieId !== undefined) update.sub_especie_id = subespecieId; + + const variedadeId = body?.taxonomia?.variedade_id; + if (variedadeId !== undefined) update.variedade_id = variedadeId; + + const latitude = body?.localidade?.latitude; + if (latitude !== undefined) { + update.latitude = latitude ? converteParaDecimal(latitude) : null; + } + + const longitude = body?.localidade?.longitude; + if (longitude !== undefined) { + update.longitude = longitude ? converteParaDecimal(longitude) : null; + } + + const altitude = body?.localidade?.altitude; + if (altitude !== undefined) update.altitude = altitude; + + const localColeta = body?.localidade?.local_coleta_id; + if (localColeta !== undefined) update.local_coleta_id = localColeta; + + const soloId = body?.paisagem?.solo_id; + if (soloId !== undefined) update.solo_id = soloId; + + const relevoId = body?.paisagem?.relevo_id; + if (relevoId !== undefined) update.relevo_id = relevoId; + + const vegetacaoId = body?.paisagem?.vegetacao_id; + if (vegetacaoId !== undefined) update.vegetacao_id = vegetacaoId; + + const descricao = body?.paisagem?.descricao; + if (descricao !== undefined) update.descricao = descricao; + + const unicata = body?.unicata; + if (unicata !== undefined) update.unicata = unicata; + + const faseSucessionalId = body?.paisagem?.fase_sucessional_id; + if (faseSucessionalId !== undefined) update.fase_sucessional_id = faseSucessionalId; + + const identificadores = body?.identificacao?.identificadores; + if (identificadores !== undefined) update.identificadores = identificadores; + + const dataIdentificacao = body?.identificacao?.data_identificacao; + if (dataIdentificacao?.dia !== undefined) update.data_identificacao_dia = dataIdentificacao.dia; + if (dataIdentificacao?.mes !== undefined) update.data_identificacao_mes = dataIdentificacao.mes; + if (dataIdentificacao?.ano !== undefined) update.data_identificacao_ano = dataIdentificacao.ano; + if (dataIdentificacao === null) { + update.data_identificacao_dia = null; + update.data_identificacao_mes = null; + update.data_identificacao_ano = null; + } + + const coletor = body?.coletor; + if (coletor !== undefined) update.coletor_id = coletor; + + const complementares = body?.coletor_complementar?.complementares; + if (complementares !== undefined) update.complementares = complementares; + + const colecoesAnexasTipo = body?.colecoes_anexas?.tipo; + if (colecoesAnexasTipo !== undefined) update.colecoes_anexas_tipo = colecoesAnexasTipo; + + const colecoesAnexasObservacoes = body?.colecoes_anexas?.observacoes; + if (colecoesAnexasObservacoes !== undefined) update.colecoes_anexas_observacoes = colecoesAnexasObservacoes; + + const { observacoes } = body || {}; + if (observacoes !== undefined) update.observacao = observacoes; + + const { tombo_id: tomboId } = request.params; + + return Alteracao.create({ + tombo_hcf: tomboId, + usuario_id: request.usuario.id, + status: 'ESPERANDO', + tombo_json: JSON.stringify(update), + ativo: true, + identificacao: 1, + }, { transaction }) + .then(alteracaoCriada => { + if (request.usuario.tipo_usuario_id === 1) { + return aprovarPendencia(update, tomboId, transaction) + .then(() => Alteracao.update({ status: 'APROVADO' }, { + where: { id: alteracaoCriada.id }, + transaction, + })) + .then(() => alteracaoCriada.toJSON()); + } if (request.usuario.tipo_usuario_id !== 2) { + throw new BadRequestExeption(421); + } + return alteracaoCriada.toJSON(); + }); +} + +export function alteracao(request, response, next) { + return sequelize.transaction(transaction => { + if (request.usuario.tipo_usuario_id === 3) { + return alteracaoIdentificador(request, transaction); + } if (request.usuario.tipo_usuario_id === 1 || request.usuario.tipo_usuario_id === 2) { + return alteracaoCuradorouOperador(request, response, transaction); + } + throw new BadRequestExeption(421); + + }) + .then(() => { + response.status(codigos.EDITAR_SEM_RETORNO).send(); + }) + .catch(next); +} + +export const desativar = (request, response, next) => { + const { params } = request; + + Promise.resolve() + .then(() => { + const where = { + hcf: params.tombo_id, + }; + + return Tombo.findOne({ where }); + }) + .then(tombo => { + if (!tombo) { + throw new NotFoundException(416); + } + + const where = { + ativo: true, + hcf: params.tombo_id, + }; + + return Tombo.update({ ativo: false }, { where }); + }) + .then(() => { + response.status(204) + .send(); + }) + .catch(next); +}; + +export const listagem = (request, response, next) => { + const { pagina, limite, offset } = request.paginacao; + const { + nome_cientifico: nomeCientifico, hcf, tipo, nome_popular: nomePopular, situacao, + } = request.query; + let where = { + rascunho: 0, + }; + + if (nomeCientifico) { + where = { + ...where, + nome_cientifico: { [Op.like]: `%${nomeCientifico}%` }, + }; + } + + if (hcf) { + where = { + ...where, + hcf, + }; + } + + if (tipo) { + where = { + ...where, + tipo_id: tipo, + }; + } + + if (nomePopular) { + where = { + ...where, + nomes_populares: { [Op.like]: `%${nomePopular}%` }, + }; + } + + if (situacao) { + where = { + ...where, + situacao, + }; + } + + let retorno = { // eslint-disable-line + metadados: { + total: 0, + pagina, + limite, + }, + tombos: [], + }; + Promise.resolve() + .then(() => Tombo.count({ where })) + .then(total => { + retorno.metadados.total = total; + }) + .then(() => Tombo.findAndCountAll({ + attributes: [ + 'hcf', + 'nomes_populares', + 'nome_cientifico', + 'data_coleta_dia', + 'data_coleta_mes', + 'data_coleta_ano', + 'created_at', + ], + include: { + model: Coletor, + attributes: ['id', 'nome'], + required: false, + }, + where, + order: [['hcf', 'DESC']], + limit: limite, + offset, + })) + .then(listaTombos => { + retorno.tombos = listaTombos.rows; + response.status(codigos.LISTAGEM) + .json(retorno); + }) + .catch(next); +}; + +export const getDadosCadTombo = (request, response, next) => { + const retorno = {}; + const callback = transaction => Promise.resolve() + .then(() => Tombo.findAndCountAll({ + attributes: ['hcf', 'numero_coleta'], + order: [['numero_coleta', 'DESC']], + transaction, + })) + .then(tombos => { + if (!tombos) { + throw new BadRequestExeption(202); + } + retorno.numero_coleta = (tombos.rows[0].numero_coleta) + 1; + }) + .then(() => Herbario.findAndCountAll({ + attributes: ['id', 'nome', 'sigla'], + order: [['nome', 'ASC']], + transaction, + })) + .then(herbario => { + if (!herbario) { + throw new BadRequestExeption(203); + } + retorno.herbarios = herbario.rows; + }) + .then(() => Tipo.findAndCountAll({ + attributes: ['id', 'nome'], + order: [['nome', 'ASC']], + transaction, + })) + .then(tipos => { + if (!tipos) { + throw new BadRequestExeption(204); + } + retorno.tipos = tipos.rows; + }) + .then(() => Pais.findAndCountAll({ + order: [['nome', 'ASC']], + transaction, + })) + .then(paises => { + if (!paises) { + throw new BadRequestExeption(205); + } + retorno.paises = paises.rows; + }) + .then(() => Familia.findAndCountAll({ + attributes: ['id', 'nome'], + order: [['nome', 'ASC']], + transaction, + })) + .then(familias => { + if (!familias) { + throw new BadRequestExeption(206); + } + retorno.familias = familias.rows; + }) + .then(() => Solo.findAndCountAll({ + attributes: ['id', 'nome'], + order: [['nome', 'ASC']], + transaction, + })) + .then(solos => { + if (!solos) { + throw new BadRequestExeption(207); + } + retorno.solos = solos.rows; + }) + .then(() => Relevo.findAndCountAll({ + attributes: ['id', 'nome'], + order: [['nome', 'ASC']], + transaction, + })) + .then(relevos => { + if (!relevos) { + throw new BadRequestExeption(208); + } + retorno.relevos = relevos.rows; + }) + .then(() => Vegetacao.findAndCountAll({ + attributes: ['id', 'nome'], + order: [['nome', 'ASC']], + transaction, + })) + .then(vegetacoes => { + if (!vegetacoes) { + throw new BadRequestExeption(209); + } + retorno.vegetacoes = vegetacoes.rows; + }) + .then(() => FaseSucessional.findAndCountAll({ + attributes: ['numero', 'nome'], + order: [['nome', 'ASC']], + transaction, + })) + .then(fases => { + if (!fases) { + throw new BadRequestExeption(210); + } + retorno.fases = fases.rows; + }) + .then(() => Autor.findAndCountAll({ + attributes: ['id', 'nome'], + order: [['nome', 'ASC']], + transaction, + })) + .then(autores => { + if (!autores) { + throw new BadRequestExeption(213); + } + retorno.autores = autores.rows; + return retorno; + }); + sequelize.transaction(callback) + .then(() => { + response.status(codigos.BUSCAR_VARIOS_ITENS) + .json(retorno); + + }) + .catch(next); +}; + +export const cadastrarTipo = (request, response, next) => { + const callback = transaction => Promise.resolve() + .then(() => Tipo.findOne({ + where: { + nome: request.body.nome, + }, + transaction, + })) + .then(tipoEncontrado => { + if (tipoEncontrado) { + throw new BadRequestExeption(412); + } + }) + .then(() => Tipo.create( + { + nome: request.body.nome, + }, + transaction + )); + sequelize.transaction(callback) + .then(() => { + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarTipos = (request, response, next) => { + Promise.resolve() + .then(() => Tipo.findAndCountAll({ + attributes: ['id', 'nome'], + })) + .then(tipos => { + response.status(codigos.LISTAGEM).json(tipos.rows); + }) + .catch(next); +}; + +export const cadastrarColetores = (request, response, next) => { + const callback = transaction => Promise.resolve() + .then(() => Coletor.findOne({ + where: { + nome: request.body.nome, + email: request.body.email, + }, + transaction, + })) + .then(coletorEncontrado => { + if (coletorEncontrado) { + throw new BadRequestExeption(413); + } + }) + .then(() => Coletor.create({ + nome: request.body.nome, + email: request.body.email, + }, transaction)); + sequelize.transaction(callback) + .then(coletor => { + if (!coletor) { + throw new BadRequestExeption(414); + } + response.status(codigos.CADASTRO_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export const buscarColetores = (request, response, next) => { + let where = {}; + let limit = 10; + const { limite, nome } = request.query; + + if (limite) { + limit = parseInt(limite); + } + + if (nome) { + where = { + ...where, + nome: { [Op.like]: `%${nome}%` }, + }; + } + + Promise.resolve() + .then(() => Coletor.findAndCountAll({ + attributes: ['id', 'nome', 'email', 'numero'], + where, + limit, + })) + .then(coletores => { + if (!coletores) { + throw new BadRequestExeption(415); + } + response.status(codigos.LISTAGEM).json(coletores.rows); + }) + .catch(next); +}; + +export const obterTombo = async (request, response, next) => { + try { + if (request.query.recaptchaToken) { + await verifyRecaptcha(request); + } + const id = request.params.tombo_id; + + let resposta = {}; + let dadosTombo = {}; + Promise.resolve() + .then(() => + Tombo.findOne({ + where: { + hcf: id, + rascunho: 0, + }, + attributes: [ + 'data_coleta_mes', + 'data_coleta_ano', + 'situacao', + 'nome_cientifico', + 'hcf', + 'data_tombo', + 'data_coleta_dia', + 'observacao', + 'nomes_populares', + 'numero_coleta', + 'latitude', + 'longitude', + 'altitude', + 'ativo', + 'rascunho', + 'data_identificacao_dia', + 'data_identificacao_mes', + 'data_identificacao_ano', + 'descricao', + 'unicata', + ], + include: [ + { + model: Herbario, + }, + { + as: 'identificadores', + model: Identificador, + }, + { + model: Solo, + attributes: { + exclude: ['updated_at', 'created_at'], + }, + }, + { + model: Relevo, + attributes: { + exclude: ['updated_at', 'created_at'], + }, + }, + { + model: Vegetacao, + attributes: { + exclude: ['updated_at', 'created_at'], + }, + }, + { + model: LocalColeta, + include: [ + { + model: Cidade, + include: [ + { + model: Estado, + include: [ + { + model: Pais, + }, + ], + }, + ], + }, + { + model: FaseSucessional, + attributes: { + exclude: ['updated_at', 'created_at'], + }, + }, + ], + }, + { + model: Variedade, + include: { + model: Autor, + attributes: { + exclude: ['updated_at', 'created_at', 'ativo'], + }, + as: 'autor', + }, + }, + { + model: Tipo, + attributes: ['id', 'nome'], + }, + { + model: Especie, + include: { + model: Autor, + attributes: { + exclude: ['updated_at', 'created_at', 'ativo'], + }, + as: 'autor', + }, + }, + { + model: ColecaoAnexa, + }, + { + model: Coletor, + attributes: ['id', 'nome'], + }, + { + model: ColetorComplementar, + as: 'coletor_complementar', + attributes: ['complementares'], + }, + { + model: Genero, + }, + { + model: Familia, + }, + { + model: Subfamilia, + }, + { + model: Subespecie, + include: { + model: Autor, + attributes: { + exclude: ['updated_at', 'created_at', 'ativo'], + }, + as: 'autor', + }, + }, + ], + }) + ) + .then(tombo => { + if (!tombo) { + throw new BadRequestExeption(416); + } + + dadosTombo = tombo; + + resposta = { + herbarioInicial: tombo.herbario !== null ? tombo.herbario?.id : '', + tipoInicial: tombo.tipo !== null ? tombo.tipo?.id : '', + paisInicial: tombo.locais_coletum.cidade?.estado?.paise !== null ? tombo.locais_coletum.cidade?.estado?.paise?.id : '', + estadoInicial: tombo.locais_coletum.cidade?.estado !== null ? tombo.locais_coletum.cidade?.estado?.id : '', + cidadeInicial: tombo.locais_coletum.cidade !== null ? tombo.locais_coletum?.cidade?.id : '', + reinoInicial: tombo.reino !== null ? tombo.reino?.id : '', + familiaInicial: tombo.familia !== null ? tombo.familia?.id : '', + subfamiliaInicial: tombo.sub_familia !== null ? tombo.sub_familia?.id : '', + generoInicial: tombo.genero !== null ? tombo.genero?.id : '', + especieInicial: tombo.especy !== null ? tombo.especy?.id : '', + subespecieInicial: tombo.sub_especy !== null ? tombo.sub_especy?.id : '', + variedadeInicial: tombo.variedade !== null ? tombo.variedade?.id : '', + idSoloInicial: tombo.solo !== null ? tombo.solo?.id : '', + soloInicial: tombo.solo !== null ? tombo.solo?.nome : '', + idRelevoInicial: tombo.relevo !== null ? tombo.relevo?.id : '', + relevoInicial: tombo.relevo !== null ? tombo.relevo?.nome : '', + idVegetacaoInicial: tombo.vegetaco !== null ? tombo.vegetaco?.id : '', + vegetacaoInicial: tombo.vegetaco !== null ? tombo.vegetaco?.nome : '', + faseInicial: + tombo.locais_coletum !== null && tombo.locais_coletum?.fase_sucessional !== null ? tombo.locais_coletum?.fase_sucessional?.numero : '', + coletor: tombo.coletore + ? { + id: tombo.coletore?.id, + nome: tombo.coletore?.nome, + } + : null, + colecaoInicial: tombo.colecoes_anexa !== null ? tombo.colecoes_anexa?.tipo : '', + complementoInicial: tombo.localizacao !== null && tombo.localizacao !== undefined ? tombo.localizacao?.complemento : '', + hcf: tombo.hcf, + situacao: tombo.situacao, + data_tombo: tombo.data_tombo, + observacao: tombo.observacao !== null ? tombo.observacao : '', + tipo: tombo.tipo !== null ? tombo.tipo?.nome : '', + numero_coleta: tombo.numero_coleta, + descricao: tombo.descricao !== null ? tombo.descricao : '', + herbario: tombo.herbario !== null ? `${tombo.herbario?.sigla} - ${tombo.herbario?.nome}` : '', + localizacao: { + latitude: tombo.latitude !== null ? tombo.latitude : '', + longitude: tombo.longitude !== null ? tombo.longitude : '', + latitude_graus: tombo.latitude !== null ? converteDecimalParaGraus(tombo.latitude, true).replace('.', ',') : '', + lat_grau: tombo.latitude !== null ? converteDecimalParaGMSGrau(tombo.latitude, true) : '', + latitude_min: tombo.latitude !== null ? converteDecimalParaGMSMinutos(tombo.latitude, true) : '', + latitude_sec: tombo.latitude !== null ? converteDecimalParaGMSSegundos(tombo.latitude, true) : '', + longitude_graus: tombo.longitude !== null ? converteDecimalParaGraus(tombo.longitude, false).replace('.', ',') : '', + long_graus: tombo.longitude !== null ? converteDecimalParaGMSGrau(tombo.longitude, false) : '', + long_min: tombo.longitude !== null ? converteDecimalParaGMSMinutos(tombo.longitude, false) : '', + long_sec: tombo.longitude !== null ? converteDecimalParaGMSSegundos(tombo.longitude, false) : '', + altitude: tombo.altitude !== null ? tombo.altitude : '', + cidade: tombo.locais_coletum !== null && tombo.locais_coletum.cidade !== null ? tombo.locais_coletum?.cidade?.nome : '', + estado: tombo.locais_coletum !== null && tombo.locais_coletum.cidade !== null ? tombo.locais_coletum.cidade?.estado?.nome : '', + pais: tombo.locais_coletum !== null && tombo.locais_coletum.cidade !== null ? tombo.locais_coletum.cidade.estado?.paise?.nome : '', + complemento: tombo.locais_coletum?.complemento !== null ? tombo.locais_coletum?.complemento : '', + }, + local_coleta: { + id: tombo.locais_coletum !== null ? tombo.locais_coletum?.id : '', + descricao: tombo.locais_coletum !== null && tombo.locais_coletum?.descricao !== null ? tombo.locais_coletum.descricao : '', + solo: tombo.solo !== null ? tombo.solo?.nome : '', + relevo: tombo.relevo !== null ? tombo.relevo?.nome : '', + vegetacao: tombo.vegetaco !== null ? tombo.vegetaco?.nome : '', + fase_sucessional: + tombo.locais_coletum !== null && tombo.locais_coletum?.fase_sucessional !== null ? tombo.locais_coletum?.fase_sucessional : '', + }, + taxonomia: { + nome_cientifico: tombo.nome_cientifico !== null ? tombo.nome_cientifico : '', + nome_popular: tombo.nomes_populares !== null ? tombo.nomes_populares : '', + reino: tombo.reino !== null ? tombo.reino?.nome : '', + familia: tombo.familia !== null ? tombo.familia?.nome : '', + sub_familia: tombo.sub_familia !== null ? tombo.sub_familia?.nome : '', + genero: tombo.genero !== null ? tombo.genero?.nome : '', + especie: { + nome: tombo.especy !== null ? tombo.especy?.nome : '', + autor: tombo.especy !== null && tombo.especy?.autor !== null ? tombo.especy?.autor?.nome : '', + }, + sub_especie: { + nome: tombo.sub_especy !== null ? tombo.sub_especy?.nome : '', + autor: tombo.sub_especy !== null && tombo.sub_especy?.autor !== null ? tombo.sub_especy?.autor?.nome : '', + }, + variedade: { + nome: tombo.variedade !== null ? tombo.variedade?.nome : '', + autor: tombo.variedade !== null && tombo.variedade?.autor !== null ? tombo.variedade?.autor?.nome : '', + }, + }, + colecao_anexa: { + tipo: tombo.colecoes_anexa !== null ? tombo.colecoes_anexa?.tipo : '', + observacao: tombo.colecoes_anexa !== null ? tombo.colecoes_anexa?.observacoes : '', + }, + unicata: tombo.unicata ?? null, + }; + let dataCol = ''; + let dataIdent = ''; + + const [tomboIdentificador] = tombo.identificadores; + + if (tombo.data_identificacao_dia !== null) { + dataIdent = `${tombo.data_identificacao_dia}/`; + resposta.data_identificacao_dia = tombo.data_identificacao_dia; + } + if (tombo.data_identificacao_mes !== null) { + dataIdent += `${converteInteiroParaRomano(tombo.data_identificacao_mes)}/`; + resposta.data_identificacao_mes = tombo.data_identificacao_mes; + } + if (tombo.data_identificacao_ano !== null) { + dataIdent += `${tombo.data_identificacao_ano}`; + resposta.data_identificacao_ano = tombo.data_identificacao_ano; + } + + if (tomboIdentificador) { + resposta.identificador_nome = padronizarNomeDarwincore(tomboIdentificador?.nome); + resposta.identificadorInicial = `${tomboIdentificador.id}`; + } else { + resposta.identificadorInicial = ''; + } + + if (tombo.data_coleta_dia !== null) { + dataCol = tombo.data_coleta_dia; + resposta.data_coleta_dia = tombo.data_coleta_dia; + } + if (tombo.data_coleta_mes !== null) { + dataCol += `/${converteInteiroParaRomano(tombo.data_coleta_mes)}`; + resposta.data_coleta_mes = tombo.data_coleta_mes; + } + if (tombo.data_coleta_ano !== null) { + dataCol += `/${tombo.data_coleta_ano}`; + resposta.data_coleta_ano = tombo.data_coleta_ano; + } + + resposta.data_coleta = dataCol; + resposta.data_identificacao = dataIdent === 'undefined' ? '' : dataIdent; + + if (tombo.coletores != null) { + resposta.coletores = tombo.coletores; + } + resposta.retorno = tombo; + return resposta; + }) + .then(() => + Estado.findAll({ + where: { + pais_id: dadosTombo.locais_coletum.cidade?.estado?.paise?.id, + }, + }) + ) + // eslint-disable-next-line no-return-assign + .then(estados => (resposta.estados = estados)) + .then(() => + Cidade.findAll({ + where: { + estado_id: dadosTombo.locais_coletum.cidade?.estado?.id, + }, + }) + ) + // eslint-disable-next-line no-return-assign + .then(cidades => (resposta.cidades = cidades)) + .then(() => + Familia.findAll({ + where: { + id: dadosTombo.familia?.id, + }, + }) + ) + .then(familias => { + resposta.familias = familias; + }) + .then(() => { + if (dadosTombo.familia) { + return Subfamilia.findAll({ + where: { + familia_id: dadosTombo.familia?.id, + }, + include: [ + { + model: Autor, + attributes: ['id', 'nome'], + as: 'autor', + }, + ], + }); + } + return undefined; + }) + .then(subfamilias => { + if (subfamilias) { + resposta.subfamilias = subfamilias; + } else { + resposta.subfamilias = []; + } + }) + .then(() => { + if (dadosTombo.familia) { + return Genero.findAll({ + where: { + familia_id: dadosTombo.familia?.id, + }, + }); + } + return undefined; + }) + .then(generos => { + if (generos) { + resposta.generos = generos; + } else { + resposta.generos = []; + } + }) + .then(() => { + if (dadosTombo.genero) { + return Especie.findAll({ + where: { + genero_id: dadosTombo.genero?.id, + }, + include: [ + { + model: Autor, + attributes: ['id', 'nome'], + as: 'autor', + }, + ], + }); + } + return undefined; + }) + .then(especies => { + if (especies) { + resposta.especies = especies; + } else { + resposta.especies = []; + } + }) + .then(() => { + if (dadosTombo.especy) { + return Subespecie.findAll({ + where: { + especie_id: dadosTombo.especy?.id, + }, + include: [ + { + model: Autor, + attributes: ['id', 'nome'], + as: 'autor', + }, + ], + }); + } + return undefined; + }) + .then(subespecies => { + if (subespecies) { + resposta.subespecies = subespecies; + } else { + resposta.subespecies = []; + } + }) + .then(() => { + if (dadosTombo.especy) { + return Variedade.findAll({ + where: { + especie_id: dadosTombo.especy?.id, + }, + include: [ + { + model: Autor, + attributes: ['id', 'nome'], + as: 'autor', + }, + ], + }); + } + return undefined; + }) + .then(variedades => { + if (variedades) { + resposta.variedades = variedades; + } else { + resposta.variedades = []; + } + }) + .then(() => + Alteracao.findOne({ + where: { + tombo_hcf: dadosTombo.hcf, + status: 'APROVADO', + identificacao: true, + }, + order: [['created_at', 'DESC']], + }) + ) + .then(alter => { + if (alter) { + resposta.identificacao = alter; + } + }) + .then(() => + TomboFoto.findAll({ + where: { + tombo_hcf: id, + }, + attributes: ['id', 'caminho_foto', 'em_vivo'], + }) + ) + .then(fotos => { + const formatoFotos = []; + const fotosExsicata = []; + const fotosEmVivo = []; + + // eslint-disable-next-line no-plusplus + for (let i = 0; i < fotos.length; i++) { + if (!fotos[i].em_vivo) { + fotosExsicata.push({ + id: fotos[i].id, + original: fotos[i].caminho_foto, + thumbnail: fotos[i].caminho_foto, + }); + } else { + fotosEmVivo.push({ + id: fotos[i].id, + original: fotos[i].caminho_foto, + thumbnail: fotos[i].caminho_foto, + }); + } + } + resposta.fotos_exsicata = fotosExsicata; + resposta.fotos_vivo = fotosEmVivo; + fotos.map(foto => + formatoFotos.push({ + id: foto.id, + original: foto.caminho_foto, + thumbnail: foto.caminho_foto, + }) + ); + resposta.fotos = formatoFotos; + response.status(codigos.BUSCAR_UM_ITEM).json(resposta); + }) + .catch(next); + } catch (err) { + next(err); + } +}; + +export const getNumeroTombo = (request, response, next) => { + const { id } = request.params; + Promise.resolve() + .then(() => Tombo.findAll({ + where: { + hcf: { [Op.like]: `%${id}%` }, + }, + attributes: [ + 'hcf', + ], + })) + .then(tombos => { + response.status(codigos.BUSCAR_UM_ITEM) + .json(tombos); + }) + .catch(next); +}; + +export const getNumeroColetor = (request, response, next) => { + const { idColetor } = request.params; + + Promise.resolve() + .then(() => + Tombo.findAll({ + where: { + coletor_id: idColetor, + }, + attributes: ['hcf', 'numero_coleta'], + }) + ) + .then(tombos => { + response.status(codigos.BUSCAR_UM_ITEM).json(tombos); + }) + .catch(next); +}; + +export const getUltimoNumeroTombo = (request, response, next) => { + Promise.resolve() + .then(() => Tombo.findAll({ + attributes: [ + 'hcf', + ], + })) + .then(tombos => { + const maximo = Math.max(...tombos.map(e => e.hcf)); + const tombo = {}; + tombo.hcf = maximo; + Tombo.findOne({ + where: { + hcf: maximo, + }, + attributes: [ + 'hcf', + 'data_tombo', + ], + }).then(tomboDate => { + response.status(codigos.BUSCAR_UM_ITEM) + .json(tomboDate); + }); + }) + .catch(next); +}; + +export async function deletarCodigoBarras(request, response, next) { + try { + const count = await TomboFoto.destroy({ + where: { num_barra: request.params.codigo }, + }); + + if (count === 0) { + return response.status(404).json({ error: 'Código de barras não encontrado' }); + } + return response.status(204).end(); + } catch (err) { + return next(err); + } +} + +export const getUltimoCodigoBarra = async (req, res, next) => { + try { + const row = await TomboFoto.findOne({ + attributes: ['id', 'codigo_barra', 'num_barra', 'caminho_foto'], + order: [ + ['tombo_hcf', 'DESC'], + ['num_barra', 'DESC'], + ['id', 'DESC'], + ], + }); + return res.status(codigos.BUSCAR_UM_ITEM).json(row || null); + } catch (err) { + return next(err); + } +}; + +const toHCFFormat = codigo => { + const codigoStr = String(codigo || '').padStart(9, '0'); + return `HCF${codigoStr}`; +}; + +export const postCodigoBarraTombo = (request, response, next) => { + const criarTransacaoCodigoBarra = transaction => + Promise.resolve().then(() => { + const { hcf, codigo_barra: codigoBarra } = request.body || {}; + + const formattedCodigoBarra = toHCFFormat(codigoBarra); + if (!formattedCodigoBarra) { + throw new BadRequestExeption(417); + } + + const payload = { + tombo_hcf: hcf, + em_vivo: true, + codigo_barra: formattedCodigoBarra, + num_barra: codigoBarra, + caminho_foto: null, + }; + + return TomboFoto.create(payload, { transaction }); + }); + + return sequelize + .transaction(criarTransacaoCodigoBarra) + .then(foto => response.status(201).json(foto)) + .catch(err => { + if (err instanceof ForeignKeyConstraintError) { + return response.status(400).json({ error: 'Violação de chave estrangeira.' }); + } + return next(err); + }); +}; + +export const getUltimoNumeroCodigoBarras = (request, response, next) => { + const { emVivo } = request.params; + Promise.resolve() + .then(() => TomboFoto.findAll({ + where: { + em_vivo: emVivo, + }, + attributes: [ + 'id', + 'codigo_barra', + 'num_barra', + 'caminho_foto', + ], + })) + .then(codBarras => { + const maximoCodBarras = Math.max(...codBarras.map(e => e.id)); + response.status(codigos.BUSCAR_UM_ITEM) + .json(maximoCodBarras); + }) + .catch(next); +}; + +export const getCodigoBarraTombo = (request, response, next) => { + const { idTombo } = request.params; + Promise.resolve() + .then(() => TomboFoto.findAll({ + where: { + tombo_hcf: idTombo, + }, + attributes: [ + 'id', + 'codigo_barra', + 'num_barra', + 'caminho_foto', + ], + })) + .then(tombos => { + response.status(codigos.BUSCAR_UM_ITEM) + .json(tombos); + }) + .catch(next); +}; + +export const atualizaCodigoBarra = (codBarra, novoCod) => TomboFoto.update({ + num_barra: novoCod.numBarra, + codigo_barra: novoCod.codBarra, +}, { + where: { + codigo_barra: codBarra, + }, +}); + +export const editarCodigoBarra = (request, response, next) => { + const { body } = request; + Promise.resolve() + .then(() => atualizaCodigoBarra(body.codBarra, body.novoCod)) + .then(retorno => { + if (!retorno) { + throw new BadRequestExeption(111); + } + response.status(codigos.EDITAR_SEM_RETORNO).send(); + }) + .catch(next); +}; + +export default {}; +>>>>>>> origin/development diff --git a/src/controllers/uploads-controller.js b/src/controllers/uploads-controller.js index 6f13b30..e40afe5 100644 --- a/src/controllers/uploads-controller.js +++ b/src/controllers/uploads-controller.js @@ -28,6 +28,19 @@ function apenasNumeros(string) { export const post = (request, response, next) => { const { file } = request; + // Validate file exists + if (!file) { + return next(new BadRequestExeption(400, 'Nenhum arquivo foi enviado')); + } + + // Additional file validation + const allowedExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp']; + const fileExtension = extname(file.originalname).toLowerCase(); + + if (!allowedExtensions.includes(fileExtension)) { + return next(new BadRequestExeption(400, 'Extensão de arquivo não permitida')); + } + let maximoGlobalCodBarras = ''; const isTrueSet = (request.body.em_vivo === 'true'); const fn = transaction => Promise.resolve() @@ -94,7 +107,7 @@ export const post = (request, response, next) => { return foto; }); - sequelize.transaction(fn) + return sequelize.transaction(fn) .then(imagem => { response.status(201) .json(imagem); diff --git a/src/controllers/usuarios-controller.js b/src/controllers/usuarios-controller.js index c5b17b2..fb2fa29 100644 --- a/src/controllers/usuarios-controller.js +++ b/src/controllers/usuarios-controller.js @@ -12,7 +12,6 @@ const { export const encontraUsuarioAtivoPorEmail = email => { const where = { - ativo: true, email, }; @@ -58,7 +57,6 @@ export const encontrarUsuario = id => Usuario.findOne({ }], where: { id, - ativo: true, }, }); @@ -116,9 +114,7 @@ export const recuperarSenha = (request, response, next) => { export const listagem = (request, response, next) => { const { limite, pagina, offset } = request.paginacao; - const where = { - ativo: true, - }; + const where = {}; const { nome, tipo, email, telefone, @@ -207,18 +203,34 @@ export const editar = (request, response, next) => { export const desativar = (request, response, next) => { const usuarioId = parseInt(request.params.usuario_id); + Promise.resolve() - .then(() => Usuario.update({ - ativo: false, - }, { - where: { - id: usuarioId, - }, + .then(() => Usuario.findOne({ + where: { id: usuarioId }, })) - .then(retorno => { - if (!retorno[0]) { + .then(usuario => { + if (!usuario) { throw new BadRequestExeption(106); } + return usuario; + }) + .then(() => { + const { Alteracao } = models; + return Alteracao.count({ + where: { + usuario_id: usuarioId, + }, + }); + }) + .then(alteracoesCount => { + if (alteracoesCount > 0) { + throw new BadRequestExeption('Usuário não pode ser excluído porque possui dependentes.'); + } + }) + .then(() => Usuario.destroy({ + where: { id: usuarioId }, + })) + .then(() => { response.status(codigos.DESATIVAR).send(); }) .catch(next); @@ -248,7 +260,6 @@ export const obtemColetores = (request, response, next) => { attributes: ['id', 'nome'], order: [['nome', 'ASC']], where: { - ativo: true, nome: { [Op.like]: `%${nome}%` }, }, limit: 10, @@ -283,7 +294,7 @@ export const atualizarSenha = (request, response, next) => { Promise.resolve() .then(() => Usuario.scope(null).findOne({ - where: { id: usuarioId, ativo: true }, + where: { id: usuarioId }, attributes: ['senha'], })) .then(user => { diff --git a/src/database/migration/20251001194607_fix-nome-cientifico.ts b/src/database/migration/20251001194607_fix-nome-cientifico.ts index a1c20c9..54f196f 100644 --- a/src/database/migration/20251001194607_fix-nome-cientifico.ts +++ b/src/database/migration/20251001194607_fix-nome-cientifico.ts @@ -1,3 +1,4 @@ +<<<<<<< HEAD import { Knex } from 'knex' export async function run(knex: Knex): Promise { @@ -41,3 +42,48 @@ export async function run(knex: Knex): Promise { await Promise.all(updates) }) } +======= +import { Knex } from 'knex' + +export async function run(knex: Knex): Promise { + await knex.transaction(async trx => { + const tombos = await trx('tombos') + .select('hcf', 'genero_id', 'especie_id') + .where('hcf', '>=', 42852) + + const updates = tombos.map(async tombo => { + let nomeCientifico = null + + if (tombo.genero_id) { + const genero = await trx('generos') + .select('nome') + .where('id', tombo.genero_id) + .first() + + if (genero) { + nomeCientifico = genero.nome + + if (tombo.especie_id) { + const especie = await trx('especies') + .select('nome') + .where('id', tombo.especie_id) + .first() + + if (especie) { + nomeCientifico = `${genero.nome} ${especie.nome}` + } + } + } + } + + return trx('tombos') + .where('hcf', tombo.hcf) + .update({ + nome_cientifico: nomeCientifico + }) + }) + + await Promise.all(updates) + }) +} +>>>>>>> origin/development diff --git a/src/database/migration/20251008212623_rem_campo_ativo.ts b/src/database/migration/20251008212623_rem_campo_ativo.ts new file mode 100644 index 0000000..614e6c7 --- /dev/null +++ b/src/database/migration/20251008212623_rem_campo_ativo.ts @@ -0,0 +1,31 @@ +import { Knex } from 'knex' + +export async function run(knex: Knex): Promise { + await knex.transaction(async trx => { + const tabelas = [ + 'autores', + 'coletores', + 'especies', + 'familias', + 'generos', + 'herbarios', + 'sub_especies', + 'sub_familias', + 'telefones', + 'tombos_fotos', + 'usuarios', + 'variedades' + ] + + await Promise.all( + tabelas.map(async tabela => { + const hasColumn = await trx.schema.hasColumn(tabela, 'ativo') + if (hasColumn) { + await trx.schema.alterTable(tabela, table => { + table.dropColumn('ativo') + }) + } + }) + ) + }) +} diff --git a/src/database/migration/20251008221402_rem-cor-tombo.ts b/src/database/migration/20251008221402_rem-cor-tombo.ts index 0e5dd9e..8b00aa2 100644 --- a/src/database/migration/20251008221402_rem-cor-tombo.ts +++ b/src/database/migration/20251008221402_rem-cor-tombo.ts @@ -1,10 +1,10 @@ -import { Knex } from 'knex' - -export async function run(knex: Knex): Promise { - const existeColuna = await knex.schema.hasColumn('tombos', 'cor') - if (existeColuna) { - await knex.schema.alterTable('tombos', table => { - table.dropColumn('cor') - }) - } -} +import { Knex } from 'knex' + +export async function run(knex: Knex): Promise { + const existeColuna = await knex.schema.hasColumn('tombos', 'cor') + if (existeColuna) { + await knex.schema.alterTable('tombos', table => { + table.dropColumn('cor') + }) + } +} diff --git a/src/helpers/tokens.js b/src/helpers/tokens.js index cdc91ed..06705ff 100644 --- a/src/helpers/tokens.js +++ b/src/helpers/tokens.js @@ -1,7 +1,6 @@ import jwt from 'jsonwebtoken'; import { secret, expires } from '../config/security'; -import serverConfig from '../config/server'; export const geraTokenUsuario = json => { const token = jwt.sign(json, secret, { @@ -11,9 +10,7 @@ export const geraTokenUsuario = json => { return token; }; -export const decodificaTokenUsuario = token => jwt.verify(token, secret, { - ignoreExpiration: serverConfig.environment === 'development', -}); +export const decodificaTokenUsuario = token => jwt.verify(token, secret); export const constroiPayloadUsuario = usuario => { const { id, nome, email, tipo_usuario_id: tipoUsuarioId } = usuario; diff --git a/src/helpers/tombo.js b/src/helpers/tombo.js index 0a7117e..60721bf 100644 --- a/src/helpers/tombo.js +++ b/src/helpers/tombo.js @@ -1,85 +1,85 @@ -import { converteParaDecimal } from './coordenadas'; - -export default {}; - -export function converteInteiroParaRomano(numero) { - if (numero === 1) { - return 'I'; - } if (numero === 2) { - return 'II'; - } if (numero === 3) { - return 'III'; - } if (numero === 4) { - return 'IV'; - } if (numero === 5) { - return 'V'; - } if (numero === 6) { - return 'VI'; - } if (numero === 7) { - return 'VII'; - } if (numero === 8) { - return 'VIII'; - } if (numero === 9) { - return 'IX'; - } if (numero === 10) { - return 'X'; - } if (numero === 11) { - return 'XI'; - } - return 'XII'; -} - -export function converteRequisicaoParaTombo(requisicao) { - const { - principal, - identificacao, - localidade, - taxonomia, - } = requisicao; - - const { data_coleta: dataColeta } = principal; - const { data_identificacao: dataIdentificacao } = identificacao; - - return { - hcf: null, - nome_popular: principal.nome_popular, - numero_coleta: principal.numero_coleta, - - latitude: converteParaDecimal(localidade.latitude), - longitude: converteParaDecimal(localidade.longitude), - altitude: localidade.altitude, - - data_coleta_dia: dataColeta.dia, - data_coleta_mes: dataColeta.mes, - data_coleta_ano: dataColeta.ano, - - data_identificacao_dia: dataIdentificacao.dia, - data_identificacao_mes: dataIdentificacao.mes, - data_identificacao_ano: dataIdentificacao.ano, - - tipo: { - id: principal.tipo_id, - }, - entidade: { - id: principal.entidade_id, - }, - familia: { - id: taxonomia.familia_id, - }, - sub_familia: { - id: taxonomia.sub_familia_id, - }, - genero: { - id: taxonomia.genero_id, - }, - especie: { - id: taxonomia.especie_id, - }, - sub_especie: { - id: taxonomia.sub_especie_id, - }, - variedade: { - id: taxonomia.variedade_id, - }, - }; -} +import { converteParaDecimal } from './coordenadas'; + +export default {}; + +export function converteInteiroParaRomano(numero) { + if (numero === 1) { + return 'I'; + } if (numero === 2) { + return 'II'; + } if (numero === 3) { + return 'III'; + } if (numero === 4) { + return 'IV'; + } if (numero === 5) { + return 'V'; + } if (numero === 6) { + return 'VI'; + } if (numero === 7) { + return 'VII'; + } if (numero === 8) { + return 'VIII'; + } if (numero === 9) { + return 'IX'; + } if (numero === 10) { + return 'X'; + } if (numero === 11) { + return 'XI'; + } + return 'XII'; +} + +export function converteRequisicaoParaTombo(requisicao) { + const { + principal, + identificacao, + localidade, + taxonomia, + } = requisicao; + + const { data_coleta: dataColeta } = principal; + const { data_identificacao: dataIdentificacao } = identificacao; + + return { + hcf: null, + nome_popular: principal.nome_popular, + numero_coleta: principal.numero_coleta, + + latitude: converteParaDecimal(localidade.latitude), + longitude: converteParaDecimal(localidade.longitude), + altitude: localidade.altitude, + + data_coleta_dia: dataColeta.dia, + data_coleta_mes: dataColeta.mes, + data_coleta_ano: dataColeta.ano, + + data_identificacao_dia: dataIdentificacao.dia, + data_identificacao_mes: dataIdentificacao.mes, + data_identificacao_ano: dataIdentificacao.ano, + + tipo: { + id: principal.tipo_id, + }, + entidade: { + id: principal.entidade_id, + }, + familia: { + id: taxonomia.familia_id, + }, + sub_familia: { + id: taxonomia.sub_familia_id, + }, + genero: { + id: taxonomia.genero_id, + }, + especie: { + id: taxonomia.especie_id, + }, + sub_especie: { + id: taxonomia.sub_especie_id, + }, + variedade: { + id: taxonomia.variedade_id, + }, + }; +} diff --git a/src/herbarium/reflora/main.js b/src/herbarium/reflora/main.js index b44d8f1..3648b92 100644 --- a/src/herbarium/reflora/main.js +++ b/src/herbarium/reflora/main.js @@ -36,13 +36,7 @@ function verificaRequisicoesAgendado(existeExecucaoReflora) { atualizaTabelaConfiguracao(1, existeExecucaoReflora[0].id, getHoraAtual(), null, existeExecucaoReflora[0].periodicidade, moment().day(agendamento) .format('DD/MM/YYYY')); }); - } else { - // eslint-disable-next-line no-console - console.log(`Não tá na hora ${moment().format('HH')}`); } - } else { - // eslint-disable-next-line no-console - console.log(`Não tá no dia ${moment().format('DD/MM/YYYY')}`); } } diff --git a/src/herbarium/reflora/tombos.js b/src/herbarium/reflora/tombos.js index 2ffc649..4af86e3 100644 --- a/src/herbarium/reflora/tombos.js +++ b/src/herbarium/reflora/tombos.js @@ -234,10 +234,6 @@ export function fazComparacaoInformacao(codBarra, informacaoReflora) { const mesIdentificacao = getMesIdentificacao(getInformacaoReflora.dateidentified); const anoIdentificacao = getAnoIdentificacao(getInformacaoReflora.dateidentified); insereAlteracaoSugerida(idUsuario, 'ESPERANDO', getNroTombo, alteracao, diaIdentificacao, mesIdentificacao, anoIdentificacao); - // eslint-disable-next-line no-console - console.log(getInformacaoReflora.identifiedby); - // eslint-disable-next-line no-console - console.log(getInformacaoReflora.dateidentified); }); } else { const diaIdentificacao = getDiaIdentificacao(getInformacaoReflora.dateidentified); @@ -245,10 +241,6 @@ export function fazComparacaoInformacao(codBarra, informacaoReflora) { const anoIdentificacao = getAnoIdentificacao(getInformacaoReflora.dateidentified); const { id } = listaUsuario[0].dataValues; insereAlteracaoSugerida(id, 'ESPERANDO', getNroTombo, alteracao, diaIdentificacao, mesIdentificacao, anoIdentificacao); - // eslint-disable-next-line no-console - console.log(getInformacaoReflora.identifiedby); - // eslint-disable-next-line no-console - console.log(getInformacaoReflora.dateidentified); } }); promessa.resolve(); @@ -280,12 +272,8 @@ export function fazComparacaoTomboReflora() { const throttle = throttledQueue(1, 2000); selectUmaInformacaoReflora().then(informacaoReflora => { if (informacaoReflora.length === 0) { - // eslint-disable-next-line no-console - console.log('akc'); promessa.resolve(true); } else { - // eslint-disable-next-line no-console - console.log('akd'); const getCodBarra = informacaoReflora[0].dataValues.cod_barra; const getInformacaoReflora = processaRespostaReflora(informacaoReflora[0].dataValues.tombo_json); throttle(() => { diff --git a/src/herbarium/specieslink/main.js b/src/herbarium/specieslink/main.js index dda01f7..f277037 100644 --- a/src/herbarium/specieslink/main.js +++ b/src/herbarium/specieslink/main.js @@ -64,13 +64,7 @@ function verificaRequisicoesAgendado(existeExecucaoSpeciesLink) { atualizaTabelaConfiguracao(2, existeExecucaoSpeciesLink[0].id, getHoraAtual(), null, existeExecucaoSpeciesLink[0].periodicidade, moment().day(agendamento) .format('DD/MM/YYYY')); }); - } else { - // eslint-disable-next-line no-console - console.log(`Não tá na hora ${moment().format('HH')}`); } - } else { - // eslint-disable-next-line no-console - console.log(`Não tá no dia ${moment().format('DD/MM/YYYY')}`); } } diff --git a/src/herbarium/specieslink/tombos.js b/src/herbarium/specieslink/tombos.js index c30229a..6e162c2 100644 --- a/src/herbarium/specieslink/tombos.js +++ b/src/herbarium/specieslink/tombos.js @@ -1,3 +1,4 @@ +<<<<<<< HEAD /* Evita o warning de excendo o tamanho da linha */ /* eslint-disable max-len */ import Q from 'q'; @@ -276,3 +277,271 @@ export function fazComparacaoTomboSpecieslink() { }); return promessa.promise; } +======= +/* Evita o warning de excendo o tamanho da linha */ +/* eslint-disable max-len */ +import Q from 'q'; +import throttledQueue from 'throttled-queue'; + +import { + ehIgualFamilia, + ehIgualGenero, + ehIgualEspecie, + existeAlteracaoSugerida, +} from '../comparainformacao'; +import { + selectUmaInformacaoSpecieslink, + selectNroTomboNumBarra, + selectTombo, + atualizaJaComparouTabelaSpecieslink, + insereAlteracaoSugerida, + selectExisteServicoUsuario, + insereIdentificadorUsuario, +} from '../herbariumdatabase'; +import { + processaRespostaSpecieslink, + temResultadoRespostaSpecieslink, +} from './specieslink'; + +/** + * A função fazComparacaoInformacao, é comparado informações do banco de dados com as que + * estão no Specieslink. As informações a serem comparadas são: família, gênero, + * espécie, subespécie e variedade. Depois de comparar cada uma dessas informações + * quando encontrado divergência é adicionado em um JSON. Após realizar todas as comparações + * ele procurar na tabela de alterações e verifica se encontra um JSON parecido com o + * que está no banco de dados, se for encontrado um JSON igual não é adicionado, + * caso não seja encontrado é adicionado um novo registro na tabela de alterações. + * Além disso, alguns detalhes que vale a pena ressaltar é que não é comparado + * informação da subfamília, isso porque no JSON vindo do Specieslink não é retornado + * informação de subfamília. Foram vistos outros sete herbários (UNOP, HUCP, HUEM, + * DVPR, MBM, UNIP, HUFU) e também não retornam esse tipo de informação. + * Uma última coisa que vale a pena ressaltar é que o script feito pela Elaine para gerar o + * DarwinCore, não é feito consultas ao banco de dados referente a subfamília. + * @param {*} nroTombo, é o número do tombo para serem pesquisadas informações no banco de dados. + * @param {*} codBarra, é o código de barra relacionado ao tombo do HCF a qual será gerado o JSON + * de alteração. + * @param {*} informacaoSpecieslink, informação do tombo que irá ser comparado com as presentes no banco + * de dados. + * @return promessa.promise, como é assíncrono ele só retorna quando resolver, ou seja, + * quando acabar de realizar a comparação de informações. + */ +export async function geraJsonAlteracao(nroTombo, codBarra, informacaoSpecieslink) { + const promessa = Q.defer(); + selectTombo(nroTombo).then(async tomboBd => { + if (tomboBd.length === 0) { + promessa.resolve(); + } + let alteracaoInformacao = '{'; + const processaInformacaoBd = tomboBd[0].dataValues; + // família + if (processaInformacaoBd.familia_id !== null) { + await ehIgualFamilia(processaInformacaoBd.familia_id, informacaoSpecieslink.family).then(familia => { + if (familia !== -1) { + alteracaoInformacao += `"familia_nome": "${familia}", `; + alteracaoInformacao += `"autor": "${informacaoSpecieslink.scientificnameauthorship}", `; + } + }); + } + // gênero + if (processaInformacaoBd.genero_id !== null) { + await ehIgualGenero(processaInformacaoBd.genero_id, informacaoSpecieslink.genus).then(genero => { + if (genero !== -1) { + alteracaoInformacao += `"genero_nome": "${genero}", `; + alteracaoInformacao += `"autor": "${informacaoSpecieslink.scientificnameauthorship}", `; + } + }); + } + // espécie + if (processaInformacaoBd.especie_id !== null) { + await ehIgualEspecie(processaInformacaoBd.especie_id, informacaoSpecieslink.specificepithet).then(especie => { + if (especie !== -1) { + alteracaoInformacao += `"especie_nome": "${especie}", `; + alteracaoInformacao += `"autor": "${informacaoSpecieslink.scientificnameauthorship}", `; + } + }); + } + alteracaoInformacao = alteracaoInformacao.substring(0, alteracaoInformacao.lastIndexOf(',')); + alteracaoInformacao += '}'; + atualizaJaComparouTabelaSpecieslink(codBarra); + promessa.resolve(alteracaoInformacao); + }); + return promessa.promise; +} + +/** + * A função getDiaIdentificacao procura na data que foi passada por parâmetro, + * e verifica se existe um dia de identificação, caso exista a mesma é retornada, + * caso não ache é retornado nulo. + * @param {*} dataIdentificacao, é uma string na qual será procurado o dia de identificação. + * @return valorDiaIdentificacao ou null, retorna o dia que foi feita a identificação caso exista, + * caso contrário retorna nulo. + */ +export function getDiaIdentificacao(dataIdentificacao) { + // O s. d. significa sem determinação + if ((dataIdentificacao.length > 0) && (dataIdentificacao !== null) && (dataIdentificacao !== 's. d.')) { + if (dataIdentificacao.indexOf('/') !== dataIdentificacao.lastIndexOf('/')) { + const valorDiaIdentificacao = dataIdentificacao.substring(0, dataIdentificacao.indexOf('/')); + if (valorDiaIdentificacao.length === 0) { + return null; + } + if (Number.isNaN(parseInt(valorDiaIdentificacao))) { + return null; + } + if (parseInt(valorDiaIdentificacao) > 0 && parseInt(valorDiaIdentificacao) < 32) { + return parseInt(valorDiaIdentificacao); + } + return null; + } + } + return null; +} + +/** + * A função getMesIdentificacao procura na data que foi passada por parâmetro, + * e verifica se existe um mês de identificação, caso exista a mesma é retornada, + * caso não ache é retornado nulo. + * @param {*} dataIdentificacao, é uma string na qual será procurado o mês de identificação. + * @return valorDiaIdentificacao ou null, retorna o mês que foi feita a identificação caso exista, + * caso contrário retorna nulo. + */ +export function getMesIdentificacao(dataIdentificacao) { + // O s. d. significa sem determinação + if ((dataIdentificacao.length > 0) && (dataIdentificacao !== null) && (dataIdentificacao !== 's. d.')) { + if (dataIdentificacao.indexOf('/') !== dataIdentificacao.lastIndexOf('/')) { + const valorMesIdentificacao = dataIdentificacao.substring(dataIdentificacao.indexOf('/') + 1, dataIdentificacao.lastIndexOf('/')); + if (valorMesIdentificacao.length === 0) { + return null; + } + if (Number.isNaN(parseInt(valorMesIdentificacao))) { + return null; + } + return parseInt(valorMesIdentificacao); + } + if (dataIdentificacao.indexOf('/') === dataIdentificacao.lastIndexOf('/')) { + const valorMesIdentificacao = dataIdentificacao.substring(0, dataIdentificacao.lastIndexOf('/')); + if (valorMesIdentificacao.length === 0) { + return null; + } + if (Number.isNaN(parseInt(valorMesIdentificacao))) { + return null; + } + if (parseInt(valorMesIdentificacao) > 0 && parseInt(valorMesIdentificacao) < 13) { + return parseInt(valorMesIdentificacao); + } + return null; + } + } + return null; +} + +/** + * A função getAnoIdentificacao procura na data que foi passada por parâmetro, + * e verifica se existe um ano de identificação, caso exista a mesma é retornada, + * caso não ache é retornado nulo. + * @param {*} dataIdentificacao, é uma string na qual será procurado o ano de identificação. + * @return valorDiaIdentificacao ou null, retorna o ano que foi feita a identificação caso exista, + * caso contrário retorna nulo. + */ +export function getAnoIdentificacao(dataIdentificacao) { + // O s. d. significa sem determinação + if ((dataIdentificacao.length > 0) && (dataIdentificacao !== null) && (dataIdentificacao !== 's. d.')) { + const valorAnoIdentificacao = dataIdentificacao.substring(dataIdentificacao.lastIndexOf('/') + 1, dataIdentificacao.length); + if (valorAnoIdentificacao.length === 0) { + return null; + } + if (Number.isNaN(parseInt(valorAnoIdentificacao))) { + return null; + } + if (parseInt(valorAnoIdentificacao) > 0) { + return parseInt(valorAnoIdentificacao); + } + return null; + } + return null; +} + +/** + * A função fazComparacaoInformacao, primeiramente verifica se tem informações + * do Specieslink esperado. Se tem as informações esperada eu pego o número de tombo + * equivalente aquele tombo de código de barra, e com esse valor de número de tombo + * eu consigo pegar informações relacionadas a esse tombo. Comparando as informações + * vindas do Specieslink com as presentes no banco de dados, eu verifico se me gerou + * um JSON. Quando me retorna JSON, eu verifico se existe essa alteração no banco + * de dados se não existe eu insiro ela no banco de dados. + * @param {*} codBarra, é o código de barra relacionado ao tombo do HCF. + * @param {*} informacaoSpecieslink, informação do tombo que está exposta do Specieslink. + * @return promessa.promise, como é assíncrono ele só retorna quando resolver, ou seja, + * quando acabar de realizar a comparação de informações. + */ +export function fazComparacaoInformacao(codBarra, informacaoSpecieslink) { + const promessa = Q.defer(); + if (temResultadoRespostaSpecieslink(informacaoSpecieslink)) { + selectNroTomboNumBarra(codBarra).then(nroTombo => { + if (nroTombo.length > 0) { + const getNroTombo = nroTombo[0].dataValues.tombo_hcf; + const getInformacaoSpecieslink = informacaoSpecieslink.features[0].properties; + geraJsonAlteracao(getNroTombo, codBarra, getInformacaoSpecieslink).then(alteracao => { + if (alteracao.length > 2) { + existeAlteracaoSugerida(getNroTombo, alteracao).then(existe => { + if (!existe) { + const nomeIdentificador = getInformacaoSpecieslink.identifiedby ?? ''; + selectExisteServicoUsuario(nomeIdentificador).then(listaUsuario => { + if (listaUsuario.length === 0) { + insereIdentificadorUsuario(nomeIdentificador).then(idUsuario => { + const diaIdentificacao = getInformacaoSpecieslink.dayidentified; + const mesIdentificacao = getInformacaoSpecieslink.monthidentified; + const anoIdentificacao = getInformacaoSpecieslink.yearidentified; + insereAlteracaoSugerida(idUsuario, 'ESPERANDO', getNroTombo, alteracao, diaIdentificacao, mesIdentificacao, anoIdentificacao); + }); + } else { + const diaIdentificacao = getInformacaoSpecieslink.dayidentified; + const mesIdentificacao = getInformacaoSpecieslink.monthidentified; + const anoIdentificacao = getInformacaoSpecieslink.yearidentified; + const { id } = listaUsuario[0].dataValues; + insereAlteracaoSugerida(id, 'ESPERANDO', getNroTombo, alteracao, diaIdentificacao, mesIdentificacao, anoIdentificacao); + } + }); + promessa.resolve(); + } + promessa.resolve(); + }); + } + promessa.resolve(); + }); + } + }); + } else { + promessa.resolve(); + } + return promessa.promise; +} + +/** + * A função fazComparacaoTomboSpecieslink, faz um select na tabela do specieslink verificando + * se tem algum tombo que já foi comparado ou não. Se o resultado dessa requisição + * é maior que zero, então eu pego o json e começo a realizar as comparações, e depois + * marco que esse json já foi comparado. Após isso, eu chamo novamente essa função + * e faço isso até com que seja comparado todos os json. + * @return promessa.promise, como é assíncrono ele só retorna quando resolver, ou seja, + * quando acabar de realizar a recursão. + */ +export function fazComparacaoTomboSpecieslink() { + const promessa = Q.defer(); + const throttle = throttledQueue(1, 2000); + selectUmaInformacaoSpecieslink().then(informacaoSpecieslink => { + if (informacaoSpecieslink.length === 0) { + promessa.resolve(true); + } else { + const getCodBarra = informacaoSpecieslink[0].dataValues.cod_barra; + const getInformacaoSpecieslink = processaRespostaSpecieslink(informacaoSpecieslink[0].dataValues.tombo_json); + throttle(() => { + fazComparacaoInformacao(getCodBarra, getInformacaoSpecieslink).then(() => { + atualizaJaComparouTabelaSpecieslink(getCodBarra); + promessa.resolve(fazComparacaoTomboSpecieslink()); + }); + }); + } + }); + return promessa.promise; +} +>>>>>>> origin/development diff --git a/src/middlewares/tokens-middleware.js b/src/middlewares/tokens-middleware.js index b56e9b4..2345edc 100644 --- a/src/middlewares/tokens-middleware.js +++ b/src/middlewares/tokens-middleware.js @@ -11,10 +11,14 @@ export const TIPOS_USUARIOS = { export default (tipoUsuarioPermitido = []) => (request, response, next) => { - const token = request.headers['token']; // eslint-disable-line + // Extract token from Authorization header + const authHeader = request.headers.authorization; + const token = authHeader && authHeader.startsWith('Bearer ') + ? authHeader.slice(7) + : null; try { - if (typeof token !== 'string') { + if (!token || typeof token !== 'string') { throw new ForbiddenException(101); } diff --git a/src/models/Autor.js b/src/models/Autor.js index b298409..0287ed9 100644 --- a/src/models/Autor.js +++ b/src/models/Autor.js @@ -28,10 +28,6 @@ export default (Sequelize, DataTypes) => { type: DataTypes.STRING(200), allowNull: true, }, - ativo: { - type: DataTypes.BOOLEAN, - allowNull: true, - }, }; const options = { diff --git a/src/models/Coletor.js b/src/models/Coletor.js index a209e2f..a0715f1 100644 --- a/src/models/Coletor.js +++ b/src/models/Coletor.js @@ -26,10 +26,6 @@ export default (Sequelize, DataTypes) => { type: DataTypes.STRING(200), allowNull: true, }, - ativo: { - type: DataTypes.BOOLEAN, - allowNull: true, - }, }; const options = { diff --git a/src/models/Especie.js b/src/models/Especie.js index 8920bb4..bed2d8f 100644 --- a/src/models/Especie.js +++ b/src/models/Especie.js @@ -42,10 +42,6 @@ export default (Sequelize, DataTypes) => { type: DataTypes.STRING(100), allowNull: false, }, - ativo: { - type: DataTypes.BOOLEAN, - allowNull: true, - }, familia_id: { type: DataTypes.INTEGER, allowNull: false, diff --git a/src/models/Familia.js b/src/models/Familia.js index be10673..6f98f8b 100644 --- a/src/models/Familia.js +++ b/src/models/Familia.js @@ -31,10 +31,6 @@ export default (Sequelize, DataTypes) => { type: DataTypes.STRING(200), allowNull: false, }, - ativo: { - type: DataTypes.BOOLEAN, - allowNull: true, - }, }; const options = { diff --git a/src/models/Genero.js b/src/models/Genero.js index 86a5f23..87c340f 100644 --- a/src/models/Genero.js +++ b/src/models/Genero.js @@ -30,10 +30,6 @@ export default (Sequelize, DataTypes) => { type: DataTypes.STRING(100), allowNull: false, }, - ativo: { - type: DataTypes.BOOLEAN, - allowNull: true, - }, familia_id: { type: DataTypes.INTEGER, allowNull: false, diff --git a/src/models/Herbario.js b/src/models/Herbario.js index 2d438e7..446c4a0 100644 --- a/src/models/Herbario.js +++ b/src/models/Herbario.js @@ -42,10 +42,6 @@ export default (Sequelize, DataTypes) => { type: DataTypes.STRING(200), allowNull: true, }, - ativo: { - type: DataTypes.BOOLEAN, - allowNull: true, - }, }; const options = { diff --git a/src/models/Subespecie.js b/src/models/Subespecie.js index 136dedf..fc1937a 100644 --- a/src/models/Subespecie.js +++ b/src/models/Subespecie.js @@ -44,10 +44,6 @@ export default (Sequelize, DataTypes) => { type: DataTypes.STRING(100), allowNull: false, }, - ativo: { - type: DataTypes.BOOLEAN, - allowNull: true, - }, familia_id: { type: DataTypes.INTEGER, allowNull: false, diff --git a/src/models/Subfamilia.js b/src/models/Subfamilia.js index 905ec3d..3c84c26 100644 --- a/src/models/Subfamilia.js +++ b/src/models/Subfamilia.js @@ -36,10 +36,6 @@ export default (Sequelize, DataTypes) => { type: DataTypes.STRING(100), allowNull: false, }, - ativo: { - type: DataTypes.BOOLEAN, - allowNull: true, - }, familia_id: { type: DataTypes.INTEGER, allowNull: false, diff --git a/src/models/Tombo.js b/src/models/Tombo.js index f9a3548..a61b104 100644 --- a/src/models/Tombo.js +++ b/src/models/Tombo.js @@ -1,279 +1,279 @@ -function associate(modelos) { - const { - LocalColeta, - Tombo, - Variedade, - Herbario, - Tipo, - Especie, - Genero, - Coletor, - ColetorComplementar, - Familia, - Subfamilia, - Subespecie, - ColecaoAnexa, - Usuario, - Alteracao, - // TomboColetor, - Relevo, - Remessa, - Vegetacao, - RetiradaExsiccata, - Solo, - TomboFoto, - TomboIdentificador, - Identificador, - } = modelos; - - Tombo.hasMany(TomboFoto, { - foreignKey: 'tombo_hcf', - }); - - Tombo.belongsToMany(Usuario, { - through: Alteracao, - foreignKey: 'tombo_hcf', - }); - - Tombo.belongsToMany(Identificador, { - as: 'identificadores', - through: TomboIdentificador, - foreignKey: 'tombo_hcf', - otherKey: 'identificador_id', - }); - - Tombo.belongsTo(Solo, { - foreignKey: 'solo_id', - }); - - Tombo.belongsTo(Relevo, { - foreignKey: 'relevo_id', - }); - - Tombo.belongsTo(Vegetacao, { - foreignKey: 'vegetacao_id', - }); - - Tombo.belongsToMany(Remessa, { - through: RetiradaExsiccata, - foreignKey: 'tombo_hcf', - }); - - Tombo.belongsTo(Coletor, { - foreignKey: 'coletor_id', - }); - - // Tombo.belongsToMany(Coletor, { - // through: TomboColetor, - // foreignKey: 'tombo_hcf', - // }); - - // Tombo.hasMany(TomboColetor, { - // foreignKey: 'tombo_hcf', - // }); - Tombo.hasOne(ColetorComplementar, { - foreignKey: 'hcf', - as: 'coletor_complementar', - }); - - Tombo.hasMany(Alteracao, { - as: 'alteracoes_tombos', - foreignKey: 'tombo_hcf', - }); - - Tombo.belongsTo(Herbario, { - foreignKey: 'entidade_id', - }); - - Tombo.belongsTo(LocalColeta, { - foreignKey: 'local_coleta_id', - }); - - Tombo.belongsTo(LocalColeta, { - as: 'local_coleta', - foreignKey: 'local_coleta_id', - }); - - Tombo.belongsTo(Variedade, { - foreignKey: 'variedade_id', - }); - - Tombo.belongsTo(Tipo, { - foreignKey: 'tipo_id', - }); - - Tombo.belongsTo(Especie, { - foreignKey: 'especie_id', - }); - - Tombo.belongsTo(Especie, { - as: 'especie', - foreignKey: 'especie_id', - }); - - Tombo.belongsTo(Genero, { - foreignKey: 'genero_id', - }); - - Tombo.belongsTo(Familia, { - foreignKey: 'familia_id', - }); - - Tombo.belongsTo(Subfamilia, { - foreignKey: 'sub_familia_id', - }); - - Tombo.belongsTo(Subespecie, { - foreignKey: 'sub_especie_id', - }); - - Tombo.belongsTo(ColecaoAnexa, { - foreignKey: 'colecao_anexa_id', - }); -} - -export const defaultScope = { - attributes: { - exclude: ['updated_at', 'created_at'], - }, -}; - -export default (Sequelize, DataTypes) => { - const attributes = { - hcf: { - type: DataTypes.INTEGER, - autoIncrement: true, - primaryKey: true, - }, - data_tombo: { - type: DataTypes.DATE, - allowNull: true, - }, - data_identificacao_dia: { - type: DataTypes.INTEGER, - allowNull: true, - }, - data_identificacao_mes: { - type: DataTypes.INTEGER, - allowNull: true, - }, - data_identificacao_ano: { - type: DataTypes.INTEGER, - allowNull: true, - }, - data_coleta_dia: { - type: DataTypes.INTEGER, - allowNull: true, - }, - data_coleta_mes: { - type: DataTypes.INTEGER, - allowNull: true, - }, - data_coleta_ano: { - type: DataTypes.INTEGER, - allowNull: true, - }, - observacao: { - type: DataTypes.TEXT, - allowNull: true, - }, - nomes_populares: { - type: DataTypes.TEXT, - allowNull: true, - }, - numero_coleta: { - type: DataTypes.INTEGER, - allowNull: true, - }, - latitude: { - type: DataTypes.DOUBLE, - allowNull: true, - }, - longitude: { - type: DataTypes.DOUBLE, - allowNull: true, - }, - altitude: { - type: DataTypes.DOUBLE, - allowNull: true, - }, - situacao: { - type: DataTypes.ENUM('REGULAR', 'PERMUTADO', 'EMPRESTADO', 'DOADO'), - allowNull: true, - }, - nome_cientifico: { - type: DataTypes.TEXT, - allowNull: true, - }, - rascunho: { - type: DataTypes.BOOLEAN, - allowNull: true, - }, - ativo: { - type: DataTypes.BOOLEAN, - allowNull: true, - }, - entidade_id: { - type: DataTypes.INTEGER, - allowNull: true, - }, - local_coleta_id: { - type: DataTypes.INTEGER, - allowNull: true, - }, - variedade_id: { - type: DataTypes.INTEGER, - allowNull: true, - }, - tipo_id: { - type: DataTypes.INTEGER, - allowNull: true, - }, - especie_id: { - type: DataTypes.INTEGER, - allowNull: true, - }, - genero_id: { - type: DataTypes.INTEGER, - allowNull: true, - }, - familia_id: { - type: DataTypes.INTEGER, - allowNull: true, - }, - sub_familia_id: { - type: DataTypes.INTEGER, - allowNull: true, - }, - sub_especie_id: { - type: DataTypes.INTEGER, - allowNull: true, - }, - colecao_anexa_id: { - type: DataTypes.INTEGER, - allowNull: true, - }, - solo_id: { - type: DataTypes.INTEGER, - allowNull: true, - }, - descricao: { - type: DataTypes.TEXT, - allowNull: true, - }, - unicata: { - type: DataTypes.BOOLEAN, - allowNull: true, - }, - }; - - const options = { - defaultScope, - }; - - const Model = Sequelize.define('tombos', attributes, options); - - Model.associate = associate; - - return Model; -}; +function associate(modelos) { + const { + LocalColeta, + Tombo, + Variedade, + Herbario, + Tipo, + Especie, + Genero, + Coletor, + ColetorComplementar, + Familia, + Subfamilia, + Subespecie, + ColecaoAnexa, + Usuario, + Alteracao, + // TomboColetor, + Relevo, + Remessa, + Vegetacao, + RetiradaExsiccata, + Solo, + TomboFoto, + TomboIdentificador, + Identificador, + } = modelos; + + Tombo.hasMany(TomboFoto, { + foreignKey: 'tombo_hcf', + }); + + Tombo.belongsToMany(Usuario, { + through: Alteracao, + foreignKey: 'tombo_hcf', + }); + + Tombo.belongsToMany(Identificador, { + as: 'identificadores', + through: TomboIdentificador, + foreignKey: 'tombo_hcf', + otherKey: 'identificador_id', + }); + + Tombo.belongsTo(Solo, { + foreignKey: 'solo_id', + }); + + Tombo.belongsTo(Relevo, { + foreignKey: 'relevo_id', + }); + + Tombo.belongsTo(Vegetacao, { + foreignKey: 'vegetacao_id', + }); + + Tombo.belongsToMany(Remessa, { + through: RetiradaExsiccata, + foreignKey: 'tombo_hcf', + }); + + Tombo.belongsTo(Coletor, { + foreignKey: 'coletor_id', + }); + + // Tombo.belongsToMany(Coletor, { + // through: TomboColetor, + // foreignKey: 'tombo_hcf', + // }); + + // Tombo.hasMany(TomboColetor, { + // foreignKey: 'tombo_hcf', + // }); + Tombo.hasOne(ColetorComplementar, { + foreignKey: 'hcf', + as: 'coletor_complementar', + }); + + Tombo.hasMany(Alteracao, { + as: 'alteracoes_tombos', + foreignKey: 'tombo_hcf', + }); + + Tombo.belongsTo(Herbario, { + foreignKey: 'entidade_id', + }); + + Tombo.belongsTo(LocalColeta, { + foreignKey: 'local_coleta_id', + }); + + Tombo.belongsTo(LocalColeta, { + as: 'local_coleta', + foreignKey: 'local_coleta_id', + }); + + Tombo.belongsTo(Variedade, { + foreignKey: 'variedade_id', + }); + + Tombo.belongsTo(Tipo, { + foreignKey: 'tipo_id', + }); + + Tombo.belongsTo(Especie, { + foreignKey: 'especie_id', + }); + + Tombo.belongsTo(Especie, { + as: 'especie', + foreignKey: 'especie_id', + }); + + Tombo.belongsTo(Genero, { + foreignKey: 'genero_id', + }); + + Tombo.belongsTo(Familia, { + foreignKey: 'familia_id', + }); + + Tombo.belongsTo(Subfamilia, { + foreignKey: 'sub_familia_id', + }); + + Tombo.belongsTo(Subespecie, { + foreignKey: 'sub_especie_id', + }); + + Tombo.belongsTo(ColecaoAnexa, { + foreignKey: 'colecao_anexa_id', + }); +} + +export const defaultScope = { + attributes: { + exclude: ['updated_at', 'created_at'], + }, +}; + +export default (Sequelize, DataTypes) => { + const attributes = { + hcf: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + }, + data_tombo: { + type: DataTypes.DATE, + allowNull: true, + }, + data_identificacao_dia: { + type: DataTypes.INTEGER, + allowNull: true, + }, + data_identificacao_mes: { + type: DataTypes.INTEGER, + allowNull: true, + }, + data_identificacao_ano: { + type: DataTypes.INTEGER, + allowNull: true, + }, + data_coleta_dia: { + type: DataTypes.INTEGER, + allowNull: true, + }, + data_coleta_mes: { + type: DataTypes.INTEGER, + allowNull: true, + }, + data_coleta_ano: { + type: DataTypes.INTEGER, + allowNull: true, + }, + observacao: { + type: DataTypes.TEXT, + allowNull: true, + }, + nomes_populares: { + type: DataTypes.TEXT, + allowNull: true, + }, + numero_coleta: { + type: DataTypes.INTEGER, + allowNull: true, + }, + latitude: { + type: DataTypes.DOUBLE, + allowNull: true, + }, + longitude: { + type: DataTypes.DOUBLE, + allowNull: true, + }, + altitude: { + type: DataTypes.DOUBLE, + allowNull: true, + }, + situacao: { + type: DataTypes.ENUM('REGULAR', 'PERMUTADO', 'EMPRESTADO', 'DOADO'), + allowNull: true, + }, + nome_cientifico: { + type: DataTypes.TEXT, + allowNull: true, + }, + rascunho: { + type: DataTypes.BOOLEAN, + allowNull: true, + }, + ativo: { + type: DataTypes.BOOLEAN, + allowNull: true, + }, + entidade_id: { + type: DataTypes.INTEGER, + allowNull: true, + }, + local_coleta_id: { + type: DataTypes.INTEGER, + allowNull: true, + }, + variedade_id: { + type: DataTypes.INTEGER, + allowNull: true, + }, + tipo_id: { + type: DataTypes.INTEGER, + allowNull: true, + }, + especie_id: { + type: DataTypes.INTEGER, + allowNull: true, + }, + genero_id: { + type: DataTypes.INTEGER, + allowNull: true, + }, + familia_id: { + type: DataTypes.INTEGER, + allowNull: true, + }, + sub_familia_id: { + type: DataTypes.INTEGER, + allowNull: true, + }, + sub_especie_id: { + type: DataTypes.INTEGER, + allowNull: true, + }, + colecao_anexa_id: { + type: DataTypes.INTEGER, + allowNull: true, + }, + solo_id: { + type: DataTypes.INTEGER, + allowNull: true, + }, + descricao: { + type: DataTypes.TEXT, + allowNull: true, + }, + unicata: { + type: DataTypes.BOOLEAN, + allowNull: true, + }, + }; + + const options = { + defaultScope, + }; + + const Model = Sequelize.define('tombos', attributes, options); + + Model.associate = associate; + + return Model; +}; diff --git a/src/models/Usuario.js b/src/models/Usuario.js index ffad918..1164b52 100644 --- a/src/models/Usuario.js +++ b/src/models/Usuario.js @@ -65,6 +65,7 @@ export default (Sequelize, DataTypes) => { type: DataTypes.STRING(200), allowNull: false, }, +<<<<<<< HEAD ativo: { type: DataTypes.BOOLEAN, allowNull: false, @@ -78,6 +79,8 @@ export default (Sequelize, DataTypes) => { type: DataTypes.DATE, allowNull: true, }, +======= +>>>>>>> origin/development }; const options = { diff --git a/src/models/Variedade.js b/src/models/Variedade.js index edcfebf..b094ab1 100644 --- a/src/models/Variedade.js +++ b/src/models/Variedade.js @@ -44,10 +44,6 @@ export default (Sequelize, DataTypes) => { type: DataTypes.STRING(100), allowNull: false, }, - ativo: { - type: DataTypes.BOOLEAN, - allowNull: true, - }, familia_id: { type: DataTypes.INTEGER, allowNull: false, diff --git a/src/routes/identificador.js b/src/routes/identificador.js index 52c1a46..b2511fd 100644 --- a/src/routes/identificador.js +++ b/src/routes/identificador.js @@ -229,4 +229,47 @@ export default app => { validacoesMiddleware(atualizarIdentificadorEsquema), identificadoresController.atualizaIdentificador, ]); + + /** + * @swagger + * /identificadores/{id}: + * delete: + * summary: Remove um identificador + * tags: [Identificadores] + * description: Remove um identificador pelo ID. Verifica se não há tombos associados antes de remover. + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: integer + * description: ID do identificador + * responses: + * 204: + * description: Identificador removido com sucesso + * '400': + * description: Não é possível excluir - existem tombos associados + * content: + * application/json: + * schema: + * type: object + * properties: + * mensagem: + * type: string + * example: + * mensagem: "Não é possível excluir o identificador. Existem 5 tombo(s) associado(s) a este identificador." + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '404': + * $ref: '#/components/responses/NotFound' + * '500': + * $ref: '#/components/responses/InternalServerError' + */ + app.route('/identificadores/:id') + .delete([ + tokensMiddleware([TIPOS_USUARIOS.CURADOR]), + identificadoresController.excluirIdentificador, + ]); }; diff --git a/src/routes/uploads.js b/src/routes/uploads.js index b26aae6..011c722 100644 --- a/src/routes/uploads.js +++ b/src/routes/uploads.js @@ -5,7 +5,32 @@ import tokensMiddleware, { TIPOS_USUARIOS } from '../middlewares/tokens-middlewa const controller = require('../controllers/uploads-controller'); -const uploadMiddleware = multer({ dest: upload }); +// File upload validation +const fileFilter = (req, file, cb) => { + // Allowed image MIME types + const allowedMimes = [ + 'image/jpeg', + 'image/jpg', + 'image/png', + 'image/gif', + 'image/webp', + ]; + + if (allowedMimes.includes(file.mimetype)) { + cb(null, true); + } else { + cb(new Error('Tipo de arquivo não permitido. Apenas imagens são aceitas.'), false); + } +}; + +const uploadMiddleware = multer({ + dest: upload, + fileFilter, + limits: { + fileSize: 10 * 1024 * 1024, // 10MB limit + files: 1, // Only one file per request + }, +}); /** * @swagger diff --git a/src/routes/usuarios.js b/src/routes/usuarios.js index 01c4502..282a536 100644 --- a/src/routes/usuarios.js +++ b/src/routes/usuarios.js @@ -1,3 +1,4 @@ +<<<<<<< HEAD import listagensMiddleware from '../middlewares/listagens-middleware'; import tokensMiddleware, { TIPOS_USUARIOS } from '../middlewares/tokens-middleware'; import validacoesMiddleware from '../middlewares/validacoes-middleware'; @@ -555,3 +556,504 @@ export default app => { controller.atualizarSenha, ]); }; +======= +import rateLimit from 'express-rate-limit'; + +import listagensMiddleware from '../middlewares/listagens-middleware'; +import tokensMiddleware, { TIPOS_USUARIOS } from '../middlewares/tokens-middleware'; +import validacoesMiddleware from '../middlewares/validacoes-middleware'; +import atualizarUsuarioEsquema from '../validators/usuario-atualiza'; +import atualizarSenhaEsquema from '../validators/usuario-atualiza-senha'; +import cadastrarUsuarioEsquema from '../validators/usuario-cadastro'; +import desativarUsuarioEsquema from '../validators/usuario-desativa'; +import listagemUsuarioEsquema from '../validators/usuario-listagem'; +import usuarioLoginEsquema from '../validators/usuario-login'; + +const controller = require('../controllers/usuarios-controller'); + +// Rate limiting for login attempts +const loginLimiter = rateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 5, // Limit each IP to 5 login requests per windowMs + message: { + error: { + code: 429, + message: 'Muitas tentativas de login. Tente novamente em 15 minutos.', + }, + }, + skipSuccessfulRequests: true, // Don't count successful requests +}); + +/** + * @swagger + * tags: + * name: Usuários + * description: Operações relacionadas aos usuários + */ +export default app => { + /** + * @swagger + * /login: + * post: + * summary: Realiza login do usuário + * tags: [Usuários] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * email: + * type: string + * senha: + * type: string + * required: + * - email + * - senha + * example: + * email: "usuario@email.com" + * senha: "senha123" + * responses: + * 200: + * description: Login realizado com sucesso + * content: + * application/json: + * schema: + * type: object + * properties: + * token: + * type: string + * usuario: + * type: object + * properties: + * id: + * type: integer + * nome: + * type: string + * email: + * type: string + * tipo_usuario_id: + * type: integer + * '400': + * $ref: '#/components/responses/BadRequest' + * '401': + * $ref: '#/components/responses/Unauthorized' + * '500': + * $ref: '#/components/responses/InternalServerError' + */ + app.route('/login') + .post([ + loginLimiter, + validacoesMiddleware(usuarioLoginEsquema), + controller.login, + ]); + + /** + * @swagger + * /coletores-predicao: + * get: + * summary: Lista coletores para predição + * tags: [Usuários] + * responses: + * 200: + * description: Lista de coletores retornada com sucesso + * content: + * application/json: + * schema: + * type: array + * items: + * type: object + * properties: + * id: + * type: integer + * description: ID do coletor + * nome: + * type: string + * description: Nome do coletor + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '500': + * $ref: '#/components/responses/InternalServerError' + */ + app.route('/coletores-predicao') + .get([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + TIPOS_USUARIOS.OPERADOR, + ]), + controller.obtemColetores, + ]); + + /** + * @swagger + * /identificadores-predicao: + * get: + * summary: Lista identificadores para predição + * tags: [Usuários] + * responses: + * 200: + * description: Lista de identificadores retornada com sucesso + * content: + * application/json: + * schema: + * type: array + * items: + * type: object + * properties: + * id: + * type: integer + * description: ID do identificador + * nome: + * type: string + * description: Nome do identificador + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '500': + * $ref: '#/components/responses/InternalServerError' + */ + app.route('/identificadores-predicao') + .get([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + TIPOS_USUARIOS.OPERADOR, + TIPOS_USUARIOS.IDENTIFICADOR, + ]), + controller.obtemIdentificadores, + ]); + + /** + * @swagger + * /usuarios: + * get: + * summary: Lista todos os usuários + * tags: [Usuários] + * responses: + * 200: + * description: Lista de usuários retornada com sucesso + * content: + * application/json: + * schema: + * type: object + * properties: + * metadados: + * type: object + * properties: + * total: + * type: integer + * pagina: + * type: integer + * limite: + * type: integer + * usuarios: + * type: array + * items: + * type: object + * properties: + * id: + * type: integer + * nome: + * type: string + * telefone: + * type: string + * ra: + * type: string + * nullable: true + * email: + * type: string + * tipos_usuario: + * type: object + * properties: + * id: + * type: integer + * tipo: + * type: string + * created_at: + * type: string + * format: date-time + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '500': + * $ref: '#/components/responses/InternalServerError' + * post: + * summary: Cadastra um novo usuário + * tags: [Usuários] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * nome: + * type: string + * minLength: 1 + * email: + * type: string + * format: email + * minLength: 1 + * senha: + * type: string + * minLength: 1 + * tipo_usuario_id: + * type: integer + * herbario_id: + * type: integer + * required: + * - nome + * - email + * - senha + * - tipo_usuario_id + * - herbario_id + * example: + * nome: "Novo Usuário" + * email: "novo@email.com" + * senha: "senha123" + * tipo_usuario_id: 2 + * herbario_id: 1 + * responses: + * 201: + * description: Usuário cadastrado com sucesso + * content: + * application/json: + * schema: + * type: object + * example: + * id: 2 + * nome: "Novo Usuário" + * email: "novo@email.com" + * '400': + * $ref: '#/components/responses/BadRequest' + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '500': + * $ref: '#/components/responses/InternalServerError' + */ + app.route('/usuarios') + .get([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + ]), + validacoesMiddleware(listagemUsuarioEsquema), + listagensMiddleware, + controller.listagem, + ]) + .post([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + ]), + validacoesMiddleware(cadastrarUsuarioEsquema), + controller.cadastro, + ]); + + /** + * @swagger + * /usuarios/{usuario_id}: + * put: + * summary: Edita um usuário + * tags: [Usuários] + * parameters: + * - in: path + * name: usuario_id + * required: true + * schema: + * type: integer + * description: ID do usuário + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * nome: + * type: string + * email: + * type: string + * required: + * - nome + * - email + * example: + * nome: "Usuário Editado" + * email: "editado@email.com" + * responses: + * 200: + * description: Usuário editado com sucesso + * content: + * application/json: + * schema: + * type: object + * example: + * id: 1 + * nome: "Usuário Editado" + * email: "editado@email.com" + * '400': + * $ref: '#/components/responses/BadRequest' + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '404': + * $ref: '#/components/responses/NotFound' + * '500': + * $ref: '#/components/responses/InternalServerError' + * get: + * summary: Busca um usuário pelo ID + * tags: [Usuários] + * parameters: + * - in: path + * name: usuario_id + * required: true + * schema: + * type: integer + * description: ID do usuário + * responses: + * 200: + * description: Dados do usuário encontrados + * content: + * application/json: + * schema: + * type: object + * properties: + * id: + * type: integer + * nome: + * type: string + * telefone: + * type: string + * ra: + * type: string + * nullable: true + * email: + * type: string + * herbario_id: + * type: integer + * tipos_usuario: + * type: object + * properties: + * id: + * type: integer + * tipo: + * type: string + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '404': + * $ref: '#/components/responses/NotFound' + * '500': + * $ref: '#/components/responses/InternalServerError' + * delete: + * summary: Remove um usuário + * tags: [Usuários] + * parameters: + * - in: path + * name: usuario_id + * required: true + * schema: + * type: integer + * description: ID do usuário + * responses: + * 204: + * description: Usuário removido com sucesso + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '404': + * $ref: '#/components/responses/NotFound' + * '500': + * $ref: '#/components/responses/InternalServerError' + */ + app.route('/usuarios/:usuario_id') + .put([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + TIPOS_USUARIOS.OPERADOR, + TIPOS_USUARIOS.IDENTIFICADOR, + ]), + validacoesMiddleware(atualizarUsuarioEsquema), + controller.editar, + ]) + .get([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + TIPOS_USUARIOS.OPERADOR, + TIPOS_USUARIOS.IDENTIFICADOR, + ]), + controller.usuario, + ]) + .delete([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + ]), + validacoesMiddleware(desativarUsuarioEsquema), + controller.desativar, + ]); + + /** + * @swagger + * /usuarios/{usuarioId}/senha: + * put: + * summary: Atualiza a senha de um usuário + * tags: [Usuários] + * parameters: + * - in: path + * name: usuarioId + * required: true + * schema: + * type: integer + * description: ID do usuário + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * senha: + * type: string + * required: + * - senha + * example: + * senha: "novaSenha123" + * responses: + * 200: + * description: Senha atualizada com sucesso + * content: + * application/json: + * schema: + * type: object + * example: + * sucesso: true + * '400': + * $ref: '#/components/responses/BadRequest' + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '404': + * $ref: '#/components/responses/NotFound' + * '500': + * $ref: '#/components/responses/InternalServerError' + */ + app.route('/usuarios/:usuarioId/senha') + .put([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + TIPOS_USUARIOS.OPERADOR, + TIPOS_USUARIOS.IDENTIFICADOR, + ]), + validacoesMiddleware(atualizarSenhaEsquema), + controller.atualizarSenha, + ]); +}; +>>>>>>> origin/development diff --git a/src/validators/coletor-cadastro.js b/src/validators/coletor-cadastro.js index b0fcad3..d7dcf6b 100644 --- a/src/validators/coletor-cadastro.js +++ b/src/validators/coletor-cadastro.js @@ -18,6 +18,6 @@ export default { numero: { in: 'body', isInt: true, - isEmpty: false, + optional: true, }, }; diff --git a/src/validators/especie-atualiza.js b/src/validators/especie-atualiza.js index 675924a..c8b2946 100644 --- a/src/validators/especie-atualiza.js +++ b/src/validators/especie-atualiza.js @@ -1,3 +1,4 @@ +<<<<<<< HEAD export default { nome: { in: 'body', @@ -23,3 +24,32 @@ export default { isEmpty: false, }, }; +======= +export default { + nome: { + in: 'body', + isString: true, + isEmpty: false, + isLength: { + options: [{ min: 3 }], + }, + }, + genero_id: { + in: 'body', + isInt: true, + isEmpty: false, + }, + autor_id: { + in: 'body', + isInt: true, + optional: { + options: { nullable: true }, + }, + }, + especie_id: { + in: 'params', + isInt: true, + isEmpty: false, + }, +}; +>>>>>>> origin/development diff --git a/src/validators/estado-listagem.js b/src/validators/estado-listagem.js index 6395693..25dbe42 100644 --- a/src/validators/estado-listagem.js +++ b/src/validators/estado-listagem.js @@ -9,4 +9,10 @@ export default { optional: true, isInt: true, }, + pais_id: { + in: 'query', + optional: true, + isInt: true, + errorMessage: 'ID do país deve ser um número inteiro.', + }, }; diff --git a/src/validators/localColeta-listagem.js b/src/validators/localColeta-listagem.js index 9a19683..96c7a87 100644 --- a/src/validators/localColeta-listagem.js +++ b/src/validators/localColeta-listagem.js @@ -5,4 +5,16 @@ export default { optional: true, errorMessage: 'ID da cidade deve ser um número inteiro.', }, + estado_id: { + in: ['query'], + isInt: true, + optional: true, + errorMessage: 'ID do estado deve ser um número inteiro.', + }, + pais_id: { + in: ['query'], + isInt: true, + optional: true, + errorMessage: 'ID do país deve ser um número inteiro.', + }, }; diff --git a/src/validators/subespecie-atualiza.js b/src/validators/subespecie-atualiza.js index d3487ef..0fa18aa 100644 --- a/src/validators/subespecie-atualiza.js +++ b/src/validators/subespecie-atualiza.js @@ -7,29 +7,21 @@ export default { options: [{ min: 3 }], }, }, - familia_id: { - in: 'body', - isInt: true, - isEmpty: false, - }, - genero_id: { + especie_id: { in: 'body', isInt: true, isEmpty: false, }, - especie_id: { + autor_id: { in: 'body', isInt: true, - isEmpty: false, + optional: { + options: { nullable: true }, + }, }, subespecie_id: { in: 'params', isInt: true, isEmpty: false, }, - autor_id: { - in: 'body', - isInt: true, - optional: true, - }, }; diff --git a/src/validators/tombo-alteracao.js b/src/validators/tombo-alteracao.js index 132af48..006f6f3 100644 --- a/src/validators/tombo-alteracao.js +++ b/src/validators/tombo-alteracao.js @@ -1,229 +1,229 @@ -import validaColecoesAnexas from './tombo-colecoes-anexas'; -import validaData from './tombo-data'; -import validaDataTombo from './tombo-data-tombo'; - -const validaColetores = coletores => { - if (!Array.isArray(coletores) || coletores.length < 1) { - return false; - } - - const naoInteiros = coletores.filter(Number.isInteger); - return naoInteiros.length === coletores.length; -}; - -export default { - 'principal.nome_popular': { - in: 'body', - isString: true, - optional: { - options: { nullable: true }, - }, - isLength: { - options: [{ min: 3 }], - }, - }, - 'json.principal.entidade_id': { - in: 'body', - isEmpty: false, - isInt: true, - }, - 'json.principal.numero_coleta': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isInt: true, - }, - 'json.principal.data_tombo': { - in: 'body', - custom: { - options: validaDataTombo, - }, - }, - 'json.principal.data_coleta': { - in: 'body', - custom: { - options: validaData, - }, - }, - 'json.principal.tipo_id': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isInt: true, - }, - 'json.taxonomia.familia_id': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isInt: true, - }, - 'json.taxonomia.genero_id': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isInt: true, - }, - 'json.taxonomia.subfamilia_id': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isInt: true, - }, - 'json.taxonomia.especie_id': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isInt: true, - }, - 'json.taxonomia.variedade_id': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isInt: true, - }, - 'json.taxonomia.subespecie_id': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isInt: true, - }, - 'json.localidade.latitude': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isString: true, - }, - 'json.localidade.longitude': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isString: true, - }, - 'json.localidade.altitude': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isInt: true, - }, - 'json.localidade.cidade_id': { - in: 'body', - isEmpty: false, - isInt: true, - }, - 'json.localidade.local_coleta_id': { - in: 'body', - isString: true, - isEmpty: false, - isLength: { - options: [{ min: 3 }], - }, - }, - 'json.paisagem.solo_id': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isInt: true, - }, - 'json.paisagem.relevo_id': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isInt: true, - }, - 'json.paisagem.vegetacao_id': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isInt: true, - }, - 'json.paisagem.fase_sucessional': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isInt: true, - }, - 'json.paisagem.descricao': { - in: 'body', - isString: true, - optional: { - options: { nullable: true }, - }, - isLength: { - options: [{ min: 3 }], - }, - }, - 'json.identificacao.identificador_id': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isInt: true, - }, - 'json.identificacao.data_identificacao': { - in: 'body', - optional: { - options: { nullable: true }, - }, - custom: { - options: validaData, - }, - }, - 'json.coletores': { - in: 'body', - isEmpty: false, - custom: { - options: validaColetores, - }, - }, - 'json.colecoes_anexas.tipo': { - in: 'body', - optional: { - options: { nullable: true }, - }, - custom: { - options: validaColecoesAnexas, - }, - }, - 'json.colecoes_anexas.observacoes': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isString: true, - isLength: { - options: [{ min: 3 }], - }, - }, - 'json.observacoes': { - in: 'body', - isString: true, - optional: { - options: { nullable: true }, - }, - isLength: { - options: [{ min: 3 }], - }, - }, - 'json.unicata': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isBoolean: true, - }, -}; +import validaColecoesAnexas from './tombo-colecoes-anexas'; +import validaData from './tombo-data'; +import validaDataTombo from './tombo-data-tombo'; + +const validaColetores = coletores => { + if (!Array.isArray(coletores) || coletores.length < 1) { + return false; + } + + const naoInteiros = coletores.filter(Number.isInteger); + return naoInteiros.length === coletores.length; +}; + +export default { + 'principal.nome_popular': { + in: 'body', + isString: true, + optional: { + options: { nullable: true }, + }, + isLength: { + options: [{ min: 3 }], + }, + }, + 'json.principal.entidade_id': { + in: 'body', + isEmpty: false, + isInt: true, + }, + 'json.principal.numero_coleta': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isInt: true, + }, + 'json.principal.data_tombo': { + in: 'body', + custom: { + options: validaDataTombo, + }, + }, + 'json.principal.data_coleta': { + in: 'body', + custom: { + options: validaData, + }, + }, + 'json.principal.tipo_id': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isInt: true, + }, + 'json.taxonomia.familia_id': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isInt: true, + }, + 'json.taxonomia.genero_id': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isInt: true, + }, + 'json.taxonomia.subfamilia_id': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isInt: true, + }, + 'json.taxonomia.especie_id': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isInt: true, + }, + 'json.taxonomia.variedade_id': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isInt: true, + }, + 'json.taxonomia.subespecie_id': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isInt: true, + }, + 'json.localidade.latitude': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isString: true, + }, + 'json.localidade.longitude': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isString: true, + }, + 'json.localidade.altitude': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isInt: true, + }, + 'json.localidade.cidade_id': { + in: 'body', + isEmpty: false, + isInt: true, + }, + 'json.localidade.local_coleta_id': { + in: 'body', + isString: true, + isEmpty: false, + isLength: { + options: [{ min: 3 }], + }, + }, + 'json.paisagem.solo_id': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isInt: true, + }, + 'json.paisagem.relevo_id': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isInt: true, + }, + 'json.paisagem.vegetacao_id': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isInt: true, + }, + 'json.paisagem.fase_sucessional': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isInt: true, + }, + 'json.paisagem.descricao': { + in: 'body', + isString: true, + optional: { + options: { nullable: true }, + }, + isLength: { + options: [{ min: 3 }], + }, + }, + 'json.identificacao.identificador_id': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isInt: true, + }, + 'json.identificacao.data_identificacao': { + in: 'body', + optional: { + options: { nullable: true }, + }, + custom: { + options: validaData, + }, + }, + 'json.coletores': { + in: 'body', + isEmpty: false, + custom: { + options: validaColetores, + }, + }, + 'json.colecoes_anexas.tipo': { + in: 'body', + optional: { + options: { nullable: true }, + }, + custom: { + options: validaColecoesAnexas, + }, + }, + 'json.colecoes_anexas.observacoes': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isString: true, + isLength: { + options: [{ min: 3 }], + }, + }, + 'json.observacoes': { + in: 'body', + isString: true, + optional: { + options: { nullable: true }, + }, + isLength: { + options: [{ min: 3 }], + }, + }, + 'json.unicata': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isBoolean: true, + }, +}; diff --git a/src/validators/tombo-cadastro.js b/src/validators/tombo-cadastro.js index 0320603..f211f31 100644 --- a/src/validators/tombo-cadastro.js +++ b/src/validators/tombo-cadastro.js @@ -1,175 +1,175 @@ -import validaColecoesAnexas from './tombo-colecoes-anexas'; -import validaData from './tombo-data'; -import validaDataTombo from './tombo-data-tombo'; - -export default { - 'json.principal.nome_popular': { - in: 'body', - isString: true, - optional: true, - isLength: { - options: [{ min: 3 }], - }, - }, - 'json.principal.entidade_id': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isInt: true, - }, - 'json.principal.numero_coleta': { - in: 'body', - optional: { - options: { nullable: true }, - }, - isInt: true, - }, - 'json.principal.data_tombo': { - in: 'body', - custom: { - options: validaDataTombo, - }, - }, - 'json.principal.data_coleta': { - in: 'body', - custom: { - options: validaData, - }, - }, - 'json.principal.tipo_id': { - in: 'body', - optional: true, - isInt: true, - }, - 'json.taxonomia.familia_id': { - in: 'body', - optional: true, - isInt: true, - }, - 'json.taxonomia.genero_id': { - in: 'body', - optional: true, - isInt: true, - }, - 'json.taxonomia.subfamilia_id': { - in: 'body', - optional: true, - isInt: true, - }, - 'json.taxonomia.especie_id': { - in: 'body', - optional: true, - isInt: true, - }, - 'json.taxonomia.variedade_id': { - in: 'body', - optional: true, - isInt: true, - }, - 'json.taxonomia.subespecie_id': { - in: 'body', - optional: true, - isInt: true, - }, - 'json.localidade.latitude': { - in: 'body', - optional: true, - isString: true, - }, - 'json.localidade.longitude': { - in: 'body', - optional: true, - isString: true, - }, - 'json.localidade.altitude': { - in: 'body', - optional: true, - isInt: true, - }, - 'json.localidade.cidade_id': { - in: 'body', - isEmpty: false, - isInt: true, - }, - 'json.localidade.local_coleta_id': { - in: 'body', - isInt: true, - isEmpty: false, - }, - 'json.paisagem.solo_id': { - in: 'body', - optional: true, - isInt: true, - }, - 'json.paisagem.relevo_id': { - in: 'body', - optional: true, - isInt: true, - }, - 'json.paisagem.vegetacao_id': { - in: 'body', - optional: true, - isInt: true, - }, - 'json.paisagem.fase_sucessional': { - in: 'body', - optional: true, - isInt: true, - }, - 'json.paisagem.descricao': { - in: 'body', - isString: true, - optional: true, - isLength: { - options: [{ min: 3 }], - }, - }, - 'json.identificacao.identificador_id': { - in: 'body', - optional: true, - isInt: true, - }, - 'json.identificacao.data_identificacao': { - in: 'body', - optional: true, - custom: { - options: validaData, - }, - }, - 'json.coletores': { - in: 'body', - isEmpty: false, - // custom: { - // options: validaColetores, - // }, - }, - 'json.colecoes_anexas.tipo': { - in: 'body', - optional: true, - custom: { - options: validaColecoesAnexas, - }, - }, - 'json.colecoes_anexas.observacoes': { - in: 'body', - optional: true, - isString: true, - isLength: { - options: [{ min: 3 }], - }, - }, - 'json.observacoes': { - in: 'body', - isString: true, - optional: true, - isLength: { - options: [{ min: 3 }], - }, - }, - 'json.unicata': { - in: 'body', - optional: true, - isBoolean: true, - }, -}; +import validaColecoesAnexas from './tombo-colecoes-anexas'; +import validaData from './tombo-data'; +import validaDataTombo from './tombo-data-tombo'; + +export default { + 'json.principal.nome_popular': { + in: 'body', + isString: true, + optional: true, + isLength: { + options: [{ min: 3 }], + }, + }, + 'json.principal.entidade_id': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isInt: true, + }, + 'json.principal.numero_coleta': { + in: 'body', + optional: { + options: { nullable: true }, + }, + isInt: true, + }, + 'json.principal.data_tombo': { + in: 'body', + custom: { + options: validaDataTombo, + }, + }, + 'json.principal.data_coleta': { + in: 'body', + custom: { + options: validaData, + }, + }, + 'json.principal.tipo_id': { + in: 'body', + optional: true, + isInt: true, + }, + 'json.taxonomia.familia_id': { + in: 'body', + optional: true, + isInt: true, + }, + 'json.taxonomia.genero_id': { + in: 'body', + optional: true, + isInt: true, + }, + 'json.taxonomia.subfamilia_id': { + in: 'body', + optional: true, + isInt: true, + }, + 'json.taxonomia.especie_id': { + in: 'body', + optional: true, + isInt: true, + }, + 'json.taxonomia.variedade_id': { + in: 'body', + optional: true, + isInt: true, + }, + 'json.taxonomia.subespecie_id': { + in: 'body', + optional: true, + isInt: true, + }, + 'json.localidade.latitude': { + in: 'body', + optional: true, + isString: true, + }, + 'json.localidade.longitude': { + in: 'body', + optional: true, + isString: true, + }, + 'json.localidade.altitude': { + in: 'body', + optional: true, + isInt: true, + }, + 'json.localidade.cidade_id': { + in: 'body', + isEmpty: false, + isInt: true, + }, + 'json.localidade.local_coleta_id': { + in: 'body', + isInt: true, + isEmpty: false, + }, + 'json.paisagem.solo_id': { + in: 'body', + optional: true, + isInt: true, + }, + 'json.paisagem.relevo_id': { + in: 'body', + optional: true, + isInt: true, + }, + 'json.paisagem.vegetacao_id': { + in: 'body', + optional: true, + isInt: true, + }, + 'json.paisagem.fase_sucessional': { + in: 'body', + optional: true, + isInt: true, + }, + 'json.paisagem.descricao': { + in: 'body', + isString: true, + optional: true, + isLength: { + options: [{ min: 3 }], + }, + }, + 'json.identificacao.identificador_id': { + in: 'body', + optional: true, + isInt: true, + }, + 'json.identificacao.data_identificacao': { + in: 'body', + optional: true, + custom: { + options: validaData, + }, + }, + 'json.coletores': { + in: 'body', + isEmpty: false, + // custom: { + // options: validaColetores, + // }, + }, + 'json.colecoes_anexas.tipo': { + in: 'body', + optional: true, + custom: { + options: validaColecoesAnexas, + }, + }, + 'json.colecoes_anexas.observacoes': { + in: 'body', + optional: true, + isString: true, + isLength: { + options: [{ min: 3 }], + }, + }, + 'json.observacoes': { + in: 'body', + isString: true, + optional: true, + isLength: { + options: [{ min: 3 }], + }, + }, + 'json.unicata': { + in: 'body', + optional: true, + isBoolean: true, + }, +}; diff --git a/src/validators/tombo-listagem.js b/src/validators/tombo-listagem.js index ed093e5..3d6a88c 100644 --- a/src/validators/tombo-listagem.js +++ b/src/validators/tombo-listagem.js @@ -8,7 +8,7 @@ const validaSituacao = situacao => { export default { nome_cientifico: { - in: 'body', + in: 'query', isString: true, optional: true, isLength: { @@ -16,7 +16,7 @@ export default { }, }, nome_popular: { - in: 'body', + in: 'query', isString: true, optional: true, isLength: { @@ -24,19 +24,19 @@ export default { }, }, tipo: { - in: 'body', + in: 'query', optional: true, isInt: true, }, situacao: { - in: 'body', + in: 'query', optional: true, custom: { options: validaSituacao, }, }, hcf: { - in: 'body', + in: 'query', isInt: true, optional: true, }, diff --git a/src/validators/variedade-atualiza.js b/src/validators/variedade-atualiza.js index 7f56a0c..1ce2d91 100644 --- a/src/validators/variedade-atualiza.js +++ b/src/validators/variedade-atualiza.js @@ -7,29 +7,21 @@ export default { options: [{ min: 3 }], }, }, - familia_id: { - in: 'body', - isInt: true, - isEmpty: false, - }, - genero_id: { + especie_id: { in: 'body', isInt: true, isEmpty: false, }, - especie_id: { + autor_id: { in: 'body', isInt: true, - isEmpty: false, + optional: { + options: { nullable: true }, + }, }, variedade_id: { in: 'params', isInt: true, isEmpty: false, }, - autor_id: { - in: 'body', - isInt: true, - optional: true, - }, }; diff --git a/tsconfig.json b/tsconfig.json index bd4a71c..d3fd018 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,7 +22,7 @@ "paths": { "~/*": [ "./src/*" - ] + ], }, "typeRoots": [ "./node_modules/@types", diff --git a/yarn.lock b/yarn.lock index 8fddf61..0b5d4e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3561,6 +3561,11 @@ expect@^30.0.0: jest-mock "30.0.5" jest-util "30.0.5" +express-rate-limit@^7.4.1: + version "7.5.1" + resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.5.1.tgz#8c3a42f69209a3a1c969890070ece9e20a879dec" + integrity sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw== + express-validator@7.2.1: version "7.2.1" resolved "https://registry.npmjs.org/express-validator/-/express-validator-7.2.1.tgz#8403deaf810f9bededa0a4fd7116803e46f122c2" @@ -4171,6 +4176,11 @@ hasown@^2.0.2: dependencies: function-bind "^1.1.2" +helmet@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-8.1.0.tgz#f96d23fedc89e9476ecb5198181009c804b8b38c" + integrity sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg== + hexoid@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz" From a2f45ade336138978c28c5dd4a307db904944ceb Mon Sep 17 00:00:00 2001 From: Yuri Baza Date: Tue, 21 Oct 2025 22:13:03 -0300 Subject: [PATCH 4/6] Fix: correcao tombos relatorio local coleta (#262) --- src/controllers/relatorios-controller.js | 35 +++++++++++++++--------- src/helpers/formata-dados-relatorio.js | 2 +- src/reports/templates/LocaisColeta.tsx | 12 ++++++-- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/controllers/relatorios-controller.js b/src/controllers/relatorios-controller.js index cce05da..19c5c5c 100644 --- a/src/controllers/relatorios-controller.js +++ b/src/controllers/relatorios-controller.js @@ -502,24 +502,33 @@ export const obtemDadosDoRelatorioDeLocalDeColeta = async (req, res, next) => { try { const tombos = await Tombo.findAndCountAll({ - attributes: ['hcf', 'numero_coleta', 'nome_cientifico', 'data_coleta_ano', 'data_coleta_mes', 'data_coleta_dia'], + attributes: [ + 'hcf', + 'numero_coleta', + 'familia_id', + 'especie_id', + 'genero_id', + 'nome_cientifico', + 'data_coleta_ano', + 'data_coleta_mes', + 'data_coleta_dia', + ], where: whereData, include: [ + { + model: Familia, + attributes: ['id', 'nome'], + // required: true, + }, + { + model: Genero, + attributes: ['id', 'nome'], + // required: true, + }, { model: Especie, attributes: ['id', 'nome'], - required: true, - include: [ - { - model: Genero, - attributes: ['id', 'nome'], - }, - { - model: Familia, - attributes: ['id', 'nome'], - required: true, - }, - ], + // required: true, }, { model: LocalColeta, diff --git a/src/helpers/formata-dados-relatorio.js b/src/helpers/formata-dados-relatorio.js index 5611df1..45e3571 100644 --- a/src/helpers/formata-dados-relatorio.js +++ b/src/helpers/formata-dados-relatorio.js @@ -229,7 +229,7 @@ export function agruparPorLocal(dados) { const agrupado = {}; let quantidadeTotal = 0; - dados.forEach(entradaOriginal => { + dados.sort((a, b) => a?.familia?.nome.localeCompare(b?.familia?.nome)).forEach(entradaOriginal => { const locaisColetum = entradaOriginal.locais_coletum; const cidade = locaisColetum?.cidade; const estado = cidade?.estado?.nome || 'Desconhecido'; diff --git a/src/reports/templates/LocaisColeta.tsx b/src/reports/templates/LocaisColeta.tsx index c37f8d4..c5d7ba2 100644 --- a/src/reports/templates/LocaisColeta.tsx +++ b/src/reports/templates/LocaisColeta.tsx @@ -15,6 +15,12 @@ interface Registro { nome: string; } } + familia: { + nome: string; + } + genero: { + nome: string; + } coordenadasFormatadas: string; } @@ -76,13 +82,13 @@ function RelacaoLocaisColeta({ dados, total, textoFiltro }: RelacaoLocaisColetaP {registros.map((item, i) => { - const { especy } = item; + const { especy, familia, genero } = item; const cordenadas = obtemCordenadas(item); return ( {criaData(item)} - {especy.familia.nome} - {especy.genero.nome} {especy.nome} + {familia?.nome} + {genero?.nome} {especy?.nome} {cordenadas.latitude} {cordenadas.longitude} {item.hcf} From a9559f92659571fc308dc24ce74d61a7db1beb23 Mon Sep 17 00:00:00 2001 From: Moran <105233020+feliperm17@users.noreply.github.com> Date: Tue, 21 Oct 2025 22:16:25 -0300 Subject: [PATCH 5/6] =?UTF-8?q?adiciona=20migra=C3=A7=C3=A3o=20para=20atua?= =?UTF-8?q?liza=C3=A7=C3=A3o=20de=20nomes=20de=20cidades=20segundo=20IBGE?= =?UTF-8?q?=20(#261)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migration/20251015183457_atualiza_IBGE.ts | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/database/migration/20251015183457_atualiza_IBGE.ts diff --git a/src/database/migration/20251015183457_atualiza_IBGE.ts b/src/database/migration/20251015183457_atualiza_IBGE.ts new file mode 100644 index 0000000..679fe41 --- /dev/null +++ b/src/database/migration/20251015183457_atualiza_IBGE.ts @@ -0,0 +1,31 @@ +import { Knex } from 'knex' + +export async function run(knex: Knex): Promise { + const updates = [ + { old: 'Amparo de São Francisco', new: 'Amparo do São Francisco' }, + { old: 'Augusto Severo (Campo Grande)', new: 'Campo Grande' }, + { old: 'Barão de Monte Alto', new: 'Barão do Monte Alto' }, + { old: 'Biritiba-Mirim', new: 'Biritiba Mirim' }, + { old: 'Dona Eusébia', new: 'Dona Euzébia' }, + { old: 'Florínia', new: 'Florínea' }, + { old: 'Fortaleza do Tabocão', new: 'Tabocão' }, + { old: 'Gracho Cardoso', new: 'Graccho Cardoso' }, + { old: 'Grão Pará', new: 'Grão-Pará' }, + { old: 'Januário Cicco (Boa Saúde)', new: 'Januário Cicco' }, + { old: 'Muquém de São Francisco', new: 'Muquém do São Francisco' }, + { old: 'Olho-d\'Água do Borges', new: 'Olho d\'Água do Borges' }, + { old: 'Olhos d\'Água', new: 'Olhos-d\'Água' }, + { old: 'Passa-Vinte', new: 'Passa Vinte' }, + { old: 'Santo Antônio do Leverger', new: 'Santo Antônio de Leverger' }, + { old: 'São Caetano', new: 'São Caitano' }, + { old: 'São Thomé das Letras', new: 'São Tomé das Letras' } + ] + + const queries = updates.map(({ old, new: novo }) => + knex('cidades') + .where('nome', old) + .update({ nome: novo }) + ) + + await Promise.all(queries) +} From 77a56084a403d8a61a78bb4ab47cc94b084e998c Mon Sep 17 00:00:00 2001 From: Lucas Vaz Date: Wed, 22 Oct 2025 18:06:32 -0300 Subject: [PATCH 6/6] fix: Atualizando conflito com a development --- src/controllers/usuarios-controller.js | 16 +- .../20251001194607_fix-nome-cientifico.ts | 50 +- ...51008193832_add-reset-token-to-usuarios.ts | 15 - ...6_adicionando_token_para_troca_de_senha.ts | 8 + src/routes/usuarios.js | 514 +----------------- src/validators/usuario-atualiza-senha.js | 4 +- src/validators/usuario-redefine-senha.js | 2 +- 7 files changed, 27 insertions(+), 582 deletions(-) delete mode 100644 src/database/migration/20251008193832_add-reset-token-to-usuarios.ts create mode 100644 src/database/migration/20251016200556_adicionando_token_para_troca_de_senha.ts diff --git a/src/controllers/usuarios-controller.js b/src/controllers/usuarios-controller.js index fb2fa29..bbe250e 100644 --- a/src/controllers/usuarios-controller.js +++ b/src/controllers/usuarios-controller.js @@ -290,7 +290,7 @@ export const obtemIdentificadores = (request, response, next) => { export const atualizarSenha = (request, response, next) => { const { usuarioId } = request.params; - const { senhaAtual, novaSenha } = request.body; + const { senha_atual, nova_senha } = request.body; Promise.resolve() .then(() => Usuario.scope(null).findOne({ @@ -305,11 +305,11 @@ export const atualizarSenha = (request, response, next) => { throw new BadRequestExeption(100); } - if (!comparaSenha(senhaAtual, user.senha)) { + if (!comparaSenha(senha_atual, user.senha)) { throw new BadRequestExeption(100); } - const novaSenhaHash = gerarSenha(novaSenha); - return Usuario.update({ senha: novaSenhaHash }, { where: { id: usuarioId } }); + const nova_senhaHash = gerarSenha(nova_senha); + return Usuario.update({ senha: nova_senhaHash }, { where: { id: usuarioId } }); }) .then(() => { response.status(codigos.EDITAR_SEM_RETORNO).send(); @@ -364,10 +364,10 @@ export const solicitarResetSenha = async (request, response, next) => { export const redefinirSenhaComToken = async (request, response, next) => { - const { token, novaSenha } = request.body; + const { token, nova_senha } = request.body; try { - if (!token || !novaSenha) { + if (!token || !nova_senha) { throw new BadRequestExeption(400, 'Token e nova senha são obrigatórios.'); } @@ -386,10 +386,10 @@ export const redefinirSenhaComToken = async (request, response, next) => { }); } - const novaSenhaHash = gerarSenha(novaSenha); + const nova_senhaHash = gerarSenha(nova_senha); await Usuario.update( { - senha: novaSenhaHash, + senha: nova_senhaHash, reset_token: null, reset_token_expiration: null, }, diff --git a/src/database/migration/20251001194607_fix-nome-cientifico.ts b/src/database/migration/20251001194607_fix-nome-cientifico.ts index 54f196f..4ea32ae 100644 --- a/src/database/migration/20251001194607_fix-nome-cientifico.ts +++ b/src/database/migration/20251001194607_fix-nome-cientifico.ts @@ -1,13 +1,12 @@ -<<<<<<< HEAD import { Knex } from 'knex' export async function run(knex: Knex): Promise { - await knex.transaction(async (trx) => { + await knex.transaction(async trx => { const tombos = await trx('tombos') .select('hcf', 'genero_id', 'especie_id') .where('hcf', '>=', 42852) - const updates = tombos.map(async (tombo) => { + const updates = tombos.map(async tombo => { let nomeCientifico = null if (tombo.genero_id) { @@ -42,48 +41,3 @@ export async function run(knex: Knex): Promise { await Promise.all(updates) }) } -======= -import { Knex } from 'knex' - -export async function run(knex: Knex): Promise { - await knex.transaction(async trx => { - const tombos = await trx('tombos') - .select('hcf', 'genero_id', 'especie_id') - .where('hcf', '>=', 42852) - - const updates = tombos.map(async tombo => { - let nomeCientifico = null - - if (tombo.genero_id) { - const genero = await trx('generos') - .select('nome') - .where('id', tombo.genero_id) - .first() - - if (genero) { - nomeCientifico = genero.nome - - if (tombo.especie_id) { - const especie = await trx('especies') - .select('nome') - .where('id', tombo.especie_id) - .first() - - if (especie) { - nomeCientifico = `${genero.nome} ${especie.nome}` - } - } - } - } - - return trx('tombos') - .where('hcf', tombo.hcf) - .update({ - nome_cientifico: nomeCientifico - }) - }) - - await Promise.all(updates) - }) -} ->>>>>>> origin/development diff --git a/src/database/migration/20251008193832_add-reset-token-to-usuarios.ts b/src/database/migration/20251008193832_add-reset-token-to-usuarios.ts deleted file mode 100644 index ad5bd6b..0000000 --- a/src/database/migration/20251008193832_add-reset-token-to-usuarios.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Knex } from 'knex'; - -export async function run(knex: Knex): Promise { - await knex.schema.alterTable('usuarios', table => { - table.string('reset_token').nullable(); - table.timestamp('reset_token_expiration').nullable(); - }); -} - -export async function down(knex: Knex): Promise { - await knex.schema.alterTable('usuarios', table => { - table.dropColumn('reset_token'); - table.dropColumn('reset_token_expiration'); - }); -} diff --git a/src/database/migration/20251016200556_adicionando_token_para_troca_de_senha.ts b/src/database/migration/20251016200556_adicionando_token_para_troca_de_senha.ts new file mode 100644 index 0000000..b57a5c2 --- /dev/null +++ b/src/database/migration/20251016200556_adicionando_token_para_troca_de_senha.ts @@ -0,0 +1,8 @@ +import { Knex } from 'knex'; + +export async function run(knex: Knex): Promise { + await knex.schema.alterTable('usuarios', table => { + table.string('token_troca_senha').nullable(); + table.timestamp('token_troca_senha_expiracao').nullable(); + }); +} diff --git a/src/routes/usuarios.js b/src/routes/usuarios.js index 282a536..1b985af 100644 --- a/src/routes/usuarios.js +++ b/src/routes/usuarios.js @@ -1,4 +1,3 @@ -<<<<<<< HEAD import listagensMiddleware from '../middlewares/listagens-middleware'; import tokensMiddleware, { TIPOS_USUARIOS } from '../middlewares/tokens-middleware'; import validacoesMiddleware from '../middlewares/validacoes-middleware'; @@ -36,14 +35,14 @@ export default app => { * properties: * token: * type: string - * novaSenha: + * nova_senha: * type: string * required: * - token - * - novaSenha + * - nova_senha * example: * token: "a1b2c3d4e5f6..." - * novaSenha: "minhaNovaSenhaSuperSegura123" + * nova_senha: "minhanova_senhaSuperSegura123" * responses: * '204': * description: Senha atualizada com sucesso. @@ -60,7 +59,7 @@ export default app => { /** * @swagger -* /usuarios/solicitar-reset-senha: +* /usuarios/solicitar-redefinicao-senha: * post: * summary: Inicia o processo de reset de senha para um usuário * tags: [Usuários] @@ -86,7 +85,7 @@ export default app => { * '500': * $ref: '#/components/responses/InternalServerError' */ - app.route('/usuarios/solicitar-reset-senha') + app.route('/usuarios/solicitar-redefinicao-senha') .post([ validacoesMiddleware(solicitarResetSenhaEsquema), controller.solicitarResetSenha, @@ -524,7 +523,7 @@ export default app => { * required: * - senha * example: - * senha: "novaSenha123" + * senha: "nova_senha123" * responses: * 200: * description: Senha atualizada com sucesso @@ -556,504 +555,3 @@ export default app => { controller.atualizarSenha, ]); }; -======= -import rateLimit from 'express-rate-limit'; - -import listagensMiddleware from '../middlewares/listagens-middleware'; -import tokensMiddleware, { TIPOS_USUARIOS } from '../middlewares/tokens-middleware'; -import validacoesMiddleware from '../middlewares/validacoes-middleware'; -import atualizarUsuarioEsquema from '../validators/usuario-atualiza'; -import atualizarSenhaEsquema from '../validators/usuario-atualiza-senha'; -import cadastrarUsuarioEsquema from '../validators/usuario-cadastro'; -import desativarUsuarioEsquema from '../validators/usuario-desativa'; -import listagemUsuarioEsquema from '../validators/usuario-listagem'; -import usuarioLoginEsquema from '../validators/usuario-login'; - -const controller = require('../controllers/usuarios-controller'); - -// Rate limiting for login attempts -const loginLimiter = rateLimit({ - windowMs: 15 * 60 * 1000, // 15 minutes - max: 5, // Limit each IP to 5 login requests per windowMs - message: { - error: { - code: 429, - message: 'Muitas tentativas de login. Tente novamente em 15 minutos.', - }, - }, - skipSuccessfulRequests: true, // Don't count successful requests -}); - -/** - * @swagger - * tags: - * name: Usuários - * description: Operações relacionadas aos usuários - */ -export default app => { - /** - * @swagger - * /login: - * post: - * summary: Realiza login do usuário - * tags: [Usuários] - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * email: - * type: string - * senha: - * type: string - * required: - * - email - * - senha - * example: - * email: "usuario@email.com" - * senha: "senha123" - * responses: - * 200: - * description: Login realizado com sucesso - * content: - * application/json: - * schema: - * type: object - * properties: - * token: - * type: string - * usuario: - * type: object - * properties: - * id: - * type: integer - * nome: - * type: string - * email: - * type: string - * tipo_usuario_id: - * type: integer - * '400': - * $ref: '#/components/responses/BadRequest' - * '401': - * $ref: '#/components/responses/Unauthorized' - * '500': - * $ref: '#/components/responses/InternalServerError' - */ - app.route('/login') - .post([ - loginLimiter, - validacoesMiddleware(usuarioLoginEsquema), - controller.login, - ]); - - /** - * @swagger - * /coletores-predicao: - * get: - * summary: Lista coletores para predição - * tags: [Usuários] - * responses: - * 200: - * description: Lista de coletores retornada com sucesso - * content: - * application/json: - * schema: - * type: array - * items: - * type: object - * properties: - * id: - * type: integer - * description: ID do coletor - * nome: - * type: string - * description: Nome do coletor - * '401': - * $ref: '#/components/responses/Unauthorized' - * '403': - * $ref: '#/components/responses/Forbidden' - * '500': - * $ref: '#/components/responses/InternalServerError' - */ - app.route('/coletores-predicao') - .get([ - tokensMiddleware([ - TIPOS_USUARIOS.CURADOR, - TIPOS_USUARIOS.OPERADOR, - ]), - controller.obtemColetores, - ]); - - /** - * @swagger - * /identificadores-predicao: - * get: - * summary: Lista identificadores para predição - * tags: [Usuários] - * responses: - * 200: - * description: Lista de identificadores retornada com sucesso - * content: - * application/json: - * schema: - * type: array - * items: - * type: object - * properties: - * id: - * type: integer - * description: ID do identificador - * nome: - * type: string - * description: Nome do identificador - * '401': - * $ref: '#/components/responses/Unauthorized' - * '403': - * $ref: '#/components/responses/Forbidden' - * '500': - * $ref: '#/components/responses/InternalServerError' - */ - app.route('/identificadores-predicao') - .get([ - tokensMiddleware([ - TIPOS_USUARIOS.CURADOR, - TIPOS_USUARIOS.OPERADOR, - TIPOS_USUARIOS.IDENTIFICADOR, - ]), - controller.obtemIdentificadores, - ]); - - /** - * @swagger - * /usuarios: - * get: - * summary: Lista todos os usuários - * tags: [Usuários] - * responses: - * 200: - * description: Lista de usuários retornada com sucesso - * content: - * application/json: - * schema: - * type: object - * properties: - * metadados: - * type: object - * properties: - * total: - * type: integer - * pagina: - * type: integer - * limite: - * type: integer - * usuarios: - * type: array - * items: - * type: object - * properties: - * id: - * type: integer - * nome: - * type: string - * telefone: - * type: string - * ra: - * type: string - * nullable: true - * email: - * type: string - * tipos_usuario: - * type: object - * properties: - * id: - * type: integer - * tipo: - * type: string - * created_at: - * type: string - * format: date-time - * '401': - * $ref: '#/components/responses/Unauthorized' - * '403': - * $ref: '#/components/responses/Forbidden' - * '500': - * $ref: '#/components/responses/InternalServerError' - * post: - * summary: Cadastra um novo usuário - * tags: [Usuários] - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * nome: - * type: string - * minLength: 1 - * email: - * type: string - * format: email - * minLength: 1 - * senha: - * type: string - * minLength: 1 - * tipo_usuario_id: - * type: integer - * herbario_id: - * type: integer - * required: - * - nome - * - email - * - senha - * - tipo_usuario_id - * - herbario_id - * example: - * nome: "Novo Usuário" - * email: "novo@email.com" - * senha: "senha123" - * tipo_usuario_id: 2 - * herbario_id: 1 - * responses: - * 201: - * description: Usuário cadastrado com sucesso - * content: - * application/json: - * schema: - * type: object - * example: - * id: 2 - * nome: "Novo Usuário" - * email: "novo@email.com" - * '400': - * $ref: '#/components/responses/BadRequest' - * '401': - * $ref: '#/components/responses/Unauthorized' - * '403': - * $ref: '#/components/responses/Forbidden' - * '500': - * $ref: '#/components/responses/InternalServerError' - */ - app.route('/usuarios') - .get([ - tokensMiddleware([ - TIPOS_USUARIOS.CURADOR, - ]), - validacoesMiddleware(listagemUsuarioEsquema), - listagensMiddleware, - controller.listagem, - ]) - .post([ - tokensMiddleware([ - TIPOS_USUARIOS.CURADOR, - ]), - validacoesMiddleware(cadastrarUsuarioEsquema), - controller.cadastro, - ]); - - /** - * @swagger - * /usuarios/{usuario_id}: - * put: - * summary: Edita um usuário - * tags: [Usuários] - * parameters: - * - in: path - * name: usuario_id - * required: true - * schema: - * type: integer - * description: ID do usuário - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * nome: - * type: string - * email: - * type: string - * required: - * - nome - * - email - * example: - * nome: "Usuário Editado" - * email: "editado@email.com" - * responses: - * 200: - * description: Usuário editado com sucesso - * content: - * application/json: - * schema: - * type: object - * example: - * id: 1 - * nome: "Usuário Editado" - * email: "editado@email.com" - * '400': - * $ref: '#/components/responses/BadRequest' - * '401': - * $ref: '#/components/responses/Unauthorized' - * '403': - * $ref: '#/components/responses/Forbidden' - * '404': - * $ref: '#/components/responses/NotFound' - * '500': - * $ref: '#/components/responses/InternalServerError' - * get: - * summary: Busca um usuário pelo ID - * tags: [Usuários] - * parameters: - * - in: path - * name: usuario_id - * required: true - * schema: - * type: integer - * description: ID do usuário - * responses: - * 200: - * description: Dados do usuário encontrados - * content: - * application/json: - * schema: - * type: object - * properties: - * id: - * type: integer - * nome: - * type: string - * telefone: - * type: string - * ra: - * type: string - * nullable: true - * email: - * type: string - * herbario_id: - * type: integer - * tipos_usuario: - * type: object - * properties: - * id: - * type: integer - * tipo: - * type: string - * '401': - * $ref: '#/components/responses/Unauthorized' - * '403': - * $ref: '#/components/responses/Forbidden' - * '404': - * $ref: '#/components/responses/NotFound' - * '500': - * $ref: '#/components/responses/InternalServerError' - * delete: - * summary: Remove um usuário - * tags: [Usuários] - * parameters: - * - in: path - * name: usuario_id - * required: true - * schema: - * type: integer - * description: ID do usuário - * responses: - * 204: - * description: Usuário removido com sucesso - * '401': - * $ref: '#/components/responses/Unauthorized' - * '403': - * $ref: '#/components/responses/Forbidden' - * '404': - * $ref: '#/components/responses/NotFound' - * '500': - * $ref: '#/components/responses/InternalServerError' - */ - app.route('/usuarios/:usuario_id') - .put([ - tokensMiddleware([ - TIPOS_USUARIOS.CURADOR, - TIPOS_USUARIOS.OPERADOR, - TIPOS_USUARIOS.IDENTIFICADOR, - ]), - validacoesMiddleware(atualizarUsuarioEsquema), - controller.editar, - ]) - .get([ - tokensMiddleware([ - TIPOS_USUARIOS.CURADOR, - TIPOS_USUARIOS.OPERADOR, - TIPOS_USUARIOS.IDENTIFICADOR, - ]), - controller.usuario, - ]) - .delete([ - tokensMiddleware([ - TIPOS_USUARIOS.CURADOR, - ]), - validacoesMiddleware(desativarUsuarioEsquema), - controller.desativar, - ]); - - /** - * @swagger - * /usuarios/{usuarioId}/senha: - * put: - * summary: Atualiza a senha de um usuário - * tags: [Usuários] - * parameters: - * - in: path - * name: usuarioId - * required: true - * schema: - * type: integer - * description: ID do usuário - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * senha: - * type: string - * required: - * - senha - * example: - * senha: "novaSenha123" - * responses: - * 200: - * description: Senha atualizada com sucesso - * content: - * application/json: - * schema: - * type: object - * example: - * sucesso: true - * '400': - * $ref: '#/components/responses/BadRequest' - * '401': - * $ref: '#/components/responses/Unauthorized' - * '403': - * $ref: '#/components/responses/Forbidden' - * '404': - * $ref: '#/components/responses/NotFound' - * '500': - * $ref: '#/components/responses/InternalServerError' - */ - app.route('/usuarios/:usuarioId/senha') - .put([ - tokensMiddleware([ - TIPOS_USUARIOS.CURADOR, - TIPOS_USUARIOS.OPERADOR, - TIPOS_USUARIOS.IDENTIFICADOR, - ]), - validacoesMiddleware(atualizarSenhaEsquema), - controller.atualizarSenha, - ]); -}; ->>>>>>> origin/development diff --git a/src/validators/usuario-atualiza-senha.js b/src/validators/usuario-atualiza-senha.js index 58d9485..d06a964 100644 --- a/src/validators/usuario-atualiza-senha.js +++ b/src/validators/usuario-atualiza-senha.js @@ -1,9 +1,9 @@ export default { - senhaAtual: { + senha_atual: { isEmpty: false, isString: true, }, - novaSenha: { + nova_senha: { isEmpty: false, isString: true, isLength: { diff --git a/src/validators/usuario-redefine-senha.js b/src/validators/usuario-redefine-senha.js index f53b218..ece4726 100644 --- a/src/validators/usuario-redefine-senha.js +++ b/src/validators/usuario-redefine-senha.js @@ -3,7 +3,7 @@ export default { isEmpty: false, errorMessage: 'O token é obrigatório.', }, - novaSenha: { + nova_senha: { isEmpty: false, errorMessage: 'A nova senha é obrigatória.', },