diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index ed3da3b..a11d89a 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -45,7 +45,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - name: Run scanner - uses: aquasecurity/trivy-action@0.28.0 + uses: aquasecurity/trivy-action@0.34.2 with: scan-type: filesystem scan-ref: . diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..cbcb85f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,65 @@ +name: Date Release + +on: + push: + branches: + - master + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # important to fetch all tags + + - name: Generate version based on date + id: version + run: | + BASE_VERSION=$(date -u +'%Y.%-m.%-d') + echo "Base version: $BASE_VERSION" + + # Fetch tags + git fetch --tags + + # Find existing tags for today + MATCHING_TAGS=$(git tag -l "${BASE_VERSION}*") + + if [ -z "$MATCHING_TAGS" ]; then + FINAL_VERSION=$BASE_VERSION + else + # Extract numeric suffixes + MAX_SUFFIX=$(echo "$MATCHING_TAGS" \ + | grep -E "^${BASE_VERSION}-[0-9]+$" \ + | sed -E "s/^${BASE_VERSION}-//" \ + | sort -n \ + | tail -n 1) + + if [ -z "$MAX_SUFFIX" ]; then + FINAL_VERSION="${BASE_VERSION}-1" + else + NEXT=$((MAX_SUFFIX + 1)) + FINAL_VERSION="${BASE_VERSION}-${NEXT}" + fi + fi + + echo "Final version: $FINAL_VERSION" + echo "version=$FINAL_VERSION" >> $GITHUB_OUTPUT + + - name: Create tag + run: | + git config user.name "github-actions" + git config user.email "github-actions@github.com" + git tag ${{ steps.version.outputs.version }} + git push origin ${{ steps.version.outputs.version }} + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.version.outputs.version }} + name: ${{ steps.version.outputs.version }} diff --git a/README.md b/README.md index e2e7568..a67e7c0 100644 --- a/README.md +++ b/README.md @@ -37,3 +37,18 @@ Using "development" environment Master 18385 is running Worker 18385 started on port 3000 ``` + +--- + +- adicionar busca pelo código de barras da foto +- colocar um alerta no painel quando estiver em ambiente de desenvolvimento +- issue para corrigir o DarwinCore (problema com o botão, quando clica não está funcionando) +- issue para o incremento do hcf na api ao invés do painel +- relatorio de quantidade de tombos por periodo + - relatorio tem que ter um grafico, mostrando quantos tombos foram cadastrados por periodo, somente quantitativo + +- alteração na ficha tombo + +nome cientifico = genero, especie, subespecie (se tiver), variedade (se tiver) +um unico tombo tem variedade e subespecie. como devemos exibir no nome cientifico? +inverter a ordem, colocar subespecie e depois variedade diff --git a/docker-compose.yml b/docker-compose.yml index 1beb67d..993aee3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: postgres: - image: postgres:18 + image: docker.io/postgis/postgis:18-3.6 container_name: herbario_postgresql environment: POSTGRES_DB: $PG_DATABASE @@ -25,7 +25,7 @@ services: nginx: image: nginx:1.17-alpine - container_name: berbario_nginx + container_name: herbario_nginx volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf - ./nginx/conf.d:/etc/nginx/conf.d diff --git a/script/database-sync/database-sync.sh b/script/database-sync/database-sync.sh index 866b6bf..431a01b 100755 --- a/script/database-sync/database-sync.sh +++ b/script/database-sync/database-sync.sh @@ -1,19 +1,6 @@ #!/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) - if [ -n "$table" ]; then - EXCLUDE_PARAMS="$EXCLUDE_PARAMS --exclude-table=$table" - fi - done - echo "Excluding tables: $SYNC_EXCLUDE_TABLES" -fi +set -euo pipefail echo "Starting synchronization process..." @@ -21,18 +8,18 @@ PGPASSWORD="$SYNC_SOURCE_PASSWORD" pg_dump \ -h "$SYNC_SOURCE_HOST" \ -p "$SYNC_SOURCE_PORT" \ -U "$SYNC_SOURCE_USER" \ + -d "$SYNC_SOURCE_DATABASE" \ + --no-owner \ + --no-privileges \ --clean \ --if-exists \ - --no-owner \ - --no-acl \ - --format plain \ - $EXCLUDE_PARAMS \ - "$SYNC_SOURCE_DATABASE" | \ -PGPASSWORD="$SYNC_DEST_PASSWORD" psql \ + --format=c | \ +PGPASSWORD="$SYNC_DEST_PASSWORD" pg_restore \ -h "$SYNC_DEST_HOST" \ -p "$SYNC_DEST_PORT" \ -U "$SYNC_DEST_USER" \ -d "$SYNC_DEST_DATABASE" \ - --single-transaction + --clean \ + --if-exists echo "Synchronization completed successfully: ${SYNC_SOURCE_DATABASE} -> ${SYNC_DEST_DATABASE}" diff --git a/script/database-sync/docker-compose.yml b/script/database-sync/docker-compose.yml index 2aa8e08..b88a7a6 100644 --- a/script/database-sync/docker-compose.yml +++ b/script/database-sync/docker-compose.yml @@ -4,16 +4,15 @@ services: container_name: database-sync build: . environment: - SYNC_SOURCE_HOST: "127.0.0.1" + SYNC_SOURCE_HOST: "10.0.10.80" SYNC_SOURCE_PORT: "5432" SYNC_SOURCE_USER: "postgres" SYNC_SOURCE_PASSWORD: "masterkey" SYNC_SOURCE_DATABASE: "herbario_prod" - SYNC_DEST_HOST: "127.0.0.1" + SYNC_DEST_HOST: "10.0.10.80" SYNC_DEST_PORT: "5432" SYNC_DEST_USER: "postgres" SYNC_DEST_PASSWORD: "masterkey" SYNC_DEST_DATABASE: "herbario_dev" - SYNC_EXCLUDE_TABLES: "" CRON_SCHEDULE: "*/2 * * * *" TZ: "America/Sao_Paulo" diff --git a/script/database-sync/entrypoint.sh b/script/database-sync/entrypoint.sh index 69adea0..52ec210 100755 --- a/script/database-sync/entrypoint.sh +++ b/script/database-sync/entrypoint.sh @@ -1,6 +1,6 @@ #!/bin/sh -echo "Configuring cron job with schedule: $CRON_SCHEDULE (timezone: $TZ)" +echo "Configuring cron job with schedule: $CRON_SCHEDULE ($TZ)" # ensure environment variables are passed to the cron job printenv | grep -E "^SYNC_" >> /etc/environment diff --git a/src/controllers/fichas-tombos-controller.js b/src/controllers/fichas-tombos-controller.js index 6ecdb7d..0addb97 100644 --- a/src/controllers/fichas-tombos-controller.js +++ b/src/controllers/fichas-tombos-controller.js @@ -166,7 +166,7 @@ export default function fichaTomboController(request, response, next) { }; const where = { - identificacao: 1, + identificacao: true, status: 'APROVADO', tombo_hcf: tombo.hcf, }; diff --git a/src/controllers/locais-coleta-controller.js b/src/controllers/locais-coleta-controller.js index 9c00020..7ca28e0 100644 --- a/src/controllers/locais-coleta-controller.js +++ b/src/controllers/locais-coleta-controller.js @@ -208,7 +208,7 @@ export const buscarFasesSucessionais = (request, response, next) => { export const cadastrarLocalColeta = async (request, response, next) => { try { - const dados = pick(request.body, ['descricao', 'complemento', 'cidade_id', 'fase_sucessional_id']); + const dados = pick(request.body, ['descricao', 'cidade_id', 'fase_sucessional_id']); const localColeta = await LocalColeta.create(dados); response.status(201).json(localColeta); } catch (error) { @@ -321,7 +321,7 @@ export const buscarLocalColetaPorId = async (request, response, next) => { export const atualizarLocalColeta = async (request, response, next) => { try { const { id } = request.params; - const dados = pick(request.body, ['descricao', 'complemento', 'cidade_id', 'fase_sucessional_id']); + const dados = pick(request.body, ['descricao', 'cidade_id', 'fase_sucessional_id']); const [updated] = await LocalColeta.update(dados, { where: { id }, }); diff --git a/src/controllers/pendencias-controller.js b/src/controllers/pendencias-controller.js index 520a3fa..993ac8f 100644 --- a/src/controllers/pendencias-controller.js +++ b/src/controllers/pendencias-controller.js @@ -42,7 +42,7 @@ export const listagem = (request, response, next) => { resultado: {}, }; let where = { - ativo: 1, + ativo: true, }; let whereUsuario = {}; if (status) { @@ -113,7 +113,7 @@ export const desativar = (request, response, next) => { const callback = transaction => Promise.resolve() .then(() => Alteracao.findOne({ where: { - ativo: 1, + ativo: true, id, }, transaction, @@ -123,7 +123,7 @@ export const desativar = (request, response, next) => { throw new BadRequestExeption(800); } return Alteracao.update({ - ativo: 0, + ativo: false, }, { where: { id, @@ -1738,7 +1738,7 @@ export async function visualizar(request, response, next) { try { const id = request.params.pendencia_id; const alteracao = await Alteracao.findOne({ - where: { ativo: 1, id }, + where: { ativo: true, id }, }); if (!alteracao) { @@ -2151,14 +2151,14 @@ export function aceitarPendencia(request, response, next) { status, }, { where: { - ativo: 1, + ativo: true, id, }, transaction, })) .then(() => Alteracao.findOne({ where: { - ativo: 1, + ativo: true, id, }, transaction, diff --git a/src/controllers/relatorios-controller.js b/src/controllers/relatorios-controller.js index c019c38..ee4cc3b 100644 --- a/src/controllers/relatorios-controller.js +++ b/src/controllers/relatorios-controller.js @@ -213,7 +213,7 @@ export const obtemDadosDoRelatorioDeColetaPorLocalEIntervaloDeData = async (req, }, { model: LocalColeta, - attributes: ['id', 'descricao', 'complemento'], + attributes: ['id', 'descricao'], where: whereLocal, required: true, }, @@ -578,7 +578,7 @@ export const obtemDadosDoRelatorioDeLocalDeColeta = async (req, res, next) => { }, { model: LocalColeta, - attributes: ['id', 'descricao', 'complemento'], + attributes: ['id', 'descricao'], where: whereLocal, required: true, include: { diff --git a/src/controllers/taxonomias-controller.js b/src/controllers/taxonomias-controller.js index 7040b72..253eab9 100644 --- a/src/controllers/taxonomias-controller.js +++ b/src/controllers/taxonomias-controller.js @@ -1341,9 +1341,9 @@ export const editarVariedade = (request, response, next) => { // //////////////////AUTORES////////////////// export const cadastrarAutores = (request, response, next) => { - let { nome, iniciais } = request.body; + let { nome, observacao } = request.body; nome = limparEspacos(nome); - iniciais = limparEspacos(iniciais); + observacao = limparEspacos(observacao); const callback = transaction => Promise.resolve() .then(() => Autor.findOne({ where: { @@ -1356,7 +1356,7 @@ export const cadastrarAutores = (request, response, next) => { throw new BadRequestExeption(513); } }) - .then(() => Autor.create({ nome, iniciais }, transaction)); + .then(() => Autor.create({ nome, observacao }, transaction)); sequelize.transaction(callback) .then(autorCriado => { if (!autorCriado) { @@ -1409,7 +1409,7 @@ export const buscarAutores = async (request, response, next) => { ]; const result = await Autor.findAndCountAll({ - attributes: ['id', 'nome', 'iniciais'], + attributes: ['id', 'nome', 'observacao'], order, limit: limite, offset, @@ -1476,9 +1476,9 @@ export const excluirAutores = (request, response, next) => { }; export const editarAutores = (request, response, next) => { - let { nome, iniciais } = request.body; + let { nome, observacao } = request.body; nome = limparEspacos(nome); - iniciais = limparEspacos(iniciais); + observacao = limparEspacos(observacao); const autorId = parseInt(request.params.autor_id); const callback = transaction => Promise.resolve() @@ -1493,7 +1493,7 @@ export const editarAutores = (request, response, next) => { throw new BadRequestExeption(517); } }) - .then(() => Autor.update({ nome, iniciais }, { + .then(() => Autor.update({ nome, observacao }, { where: { id: autorId, }, diff --git a/src/controllers/tombos-controller.js b/src/controllers/tombos-controller.js index 6059717..671ac3f 100644 --- a/src/controllers/tombos-controller.js +++ b/src/controllers/tombos-controller.js @@ -17,7 +17,7 @@ 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 }, + ColecaoAnexa, Especie, Herbario, Tombo, Alteracao, TomboIdentificador, ColetorComplementar, Sequelize: { Op, fn, col }, } = models; function parseDataTombo(valor) { @@ -397,8 +397,8 @@ export const cadastro = (request, response, next) => { usuario_id: request.usuario.id, status, tombo_json: JSON.stringify(tomboData), - ativo: 1, - identificacao: 1, + ativo: true, + identificacao: true, }; tomboCriado = tombo; @@ -486,8 +486,8 @@ function alteracaoIdentificador(request, transaction) { usuario_id: request.usuario.id, status: 'ESPERANDO', tombo_json: JSON.stringify(update), - ativo: 1, - identificacao: 1, + ativo: true, + identificacao: true, }, { transaction })) .then(alteracaoIdent => { if (request.usuario.tipo_usuario_id === 3) { @@ -612,8 +612,8 @@ function alteracaoCuradorouOperador(request, response, transaction) { usuario_id: request.usuario.id, status: 'ESPERANDO', tombo_json: JSON.stringify(update), - ativo: 1, - identificacao: 1, + ativo: true, + identificacao: true, }, { transaction }) .then(alteracaoCriada => { if (request.usuario.tipo_usuario_id === 1) { @@ -1472,7 +1472,7 @@ export const obterTombo = async (request, response, next) => { where: { tombo_hcf: dadosTombo.hcf, status: 'APROVADO', - identificacao: 1, + identificacao: true, }, order: [['created_at', 'DESC']], }), @@ -1551,15 +1551,20 @@ export const getNumeroColetor = (request, response, next) => { Promise.resolve() .then(() => - Tombo.findAll({ + Tombo.findOne({ where: { coletor_id: idColetor, }, - attributes: ['hcf', 'numero_coleta'], + attributes: [ + [fn('MAX', col('numero_coleta')), 'max_numero_coleta'], + ], + raw: true, }), ) - .then(tombos => { - response.status(codigos.BUSCAR_UM_ITEM).json(tombos); + .then(resultado => { + const maxNumero = resultado?.max_numero_coleta; + const proximoNumero = maxNumero ? Number(maxNumero) + 1 : 1; + response.status(codigos.BUSCAR_UM_ITEM).json({ proximo_numero_coleta: proximoNumero }); }) .catch(next); }; diff --git a/src/database/migration/20251215003403_altera-tipos-data-configuracao.ts b/src/database/migration/20251215003403_altera-tipos-data-configuracao.ts deleted file mode 100644 index 79332d5..0000000 --- a/src/database/migration/20251215003403_altera-tipos-data-configuracao.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Knex } from 'knex' - -export async function run(knex: Knex): Promise { - await knex.raw(` - ALTER TABLE configuracao - MODIFY hora_inicio TIME NOT NULL, - MODIFY hora_fim TIME NULL, - MODIFY data_proxima_atualizacao DATETIME NULL; - `) -} diff --git a/src/database/migration/20260211011159_fix_remove_autores_duplicados.ts b/src/database/migration/20260211011159_fix_remove_autores_duplicados.ts new file mode 100644 index 0000000..80ded0b --- /dev/null +++ b/src/database/migration/20260211011159_fix_remove_autores_duplicados.ts @@ -0,0 +1,105 @@ +import { Knex } from 'knex' + +type DupGroupRow = { + nome: string + observacao: string | null + keep_id: number + ids: number[] + qtde: number +} + +export async function run(knex: Knex): Promise { + await knex.transaction(async trx => { + const hasIniciais = await trx.schema.hasColumn('autores', 'iniciais') + const hasObservacao = await trx.schema.hasColumn('autores', 'observacao') + + if (hasIniciais && !hasObservacao) { + await trx.schema.alterTable('autores', table => { + table.renameColumn('iniciais', 'observacao') + }) + } + + const hasObservacaoNow = await trx.schema.hasColumn('autores', 'observacao') + + if (hasObservacaoNow) { + await trx.schema.alterTable('autores', table => { + table.string('observacao', 500).nullable().alter() + }) + } + + const dupGroups = (await trx('autores') + .select([ + 'nome', + 'observacao', + trx.raw('MIN(id)::int as keep_id'), + trx.raw('ARRAY_AGG(id ORDER BY id) as ids'), + trx.raw('COUNT(*)::int as qtde') + ]) + .groupBy(['nome', 'observacao']) + .havingRaw('COUNT(*) > 1')) as unknown as DupGroupRow[] + + if (!dupGroups.length) return + + const pairs: Array<{ keep_id: number; drop_id: number }> = [] + + for (const g of dupGroups) { + const keepId = Number(g.keep_id) + const ids = (g.ids ?? []).map(n => Number(n)).filter(Number.isFinite) + + for (const id of ids) { + if (id !== keepId) pairs.push({ keep_id: keepId, drop_id: id }) + } + } + + if (!pairs.length) return + + await trx.raw('DROP TABLE IF EXISTS autor_merge') + + await trx.schema.createTable('autor_merge', table => { + table.integer('keep_id').notNullable() + table.integer('drop_id').notNullable().primary() + }) + + await trx('autor_merge').insert(pairs) + + await trx.raw(` + UPDATE especies e + SET autor_id = m.keep_id + FROM autor_merge m + WHERE e.autor_id = m.drop_id + `) + + await trx.raw(` + UPDATE sub_especies se + SET autor_id = m.keep_id + FROM autor_merge m + WHERE se.autor_id = m.drop_id + `) + + await trx.raw(` + UPDATE variedades v + SET autor_id = m.keep_id + FROM autor_merge m + WHERE v.autor_id = m.drop_id + `) + + const hasSubFamiliasAutorId = await trx.schema.hasColumn('sub_familias', 'autor_id') + + if (hasSubFamiliasAutorId) { + await trx.raw(` + UPDATE sub_familias sf + SET autor_id = m.keep_id + FROM autor_merge m + WHERE sf.autor_id = m.drop_id + `) + } + + await trx.raw(` + DELETE FROM autores a + USING autor_merge m + WHERE a.id = m.drop_id + `) + + await trx.schema.dropTable('autor_merge') + }) +} diff --git a/src/database/migration/20260304120000_convert_smallint_to_boolean.ts b/src/database/migration/20260304120000_convert_smallint_to_boolean.ts new file mode 100644 index 0000000..c99cbd6 --- /dev/null +++ b/src/database/migration/20260304120000_convert_smallint_to_boolean.ts @@ -0,0 +1,29 @@ +import { Knex } from 'knex' + +export async function run(knex: Knex): Promise { + await knex.transaction(async trx => { + await trx.schema.alterTable('alteracoes', table => { + table.smallint('ativo_backup').nullable() + table.smallint('identificacao_backup').nullable() + }) + + await trx.raw('UPDATE alteracoes SET ativo_backup = ativo, identificacao_backup = identificacao') + + await trx.schema.alterTable('alteracoes', table => { + table.dropColumn('ativo') + table.dropColumn('identificacao') + }) + + await trx.schema.alterTable('alteracoes', table => { + table.boolean('ativo').nullable() + table.boolean('identificacao').nullable() + }) + + await trx.raw('UPDATE alteracoes SET ativo = (ativo_backup = 1), identificacao = (identificacao_backup = 1)') + + await trx.schema.alterTable('alteracoes', table => { + table.dropColumn('ativo_backup') + table.dropColumn('identificacao_backup') + }) + }) +} diff --git a/src/helpers/formata-dados-relatorio.js b/src/helpers/formata-dados-relatorio.js index 5a01156..da688bf 100644 --- a/src/helpers/formata-dados-relatorio.js +++ b/src/helpers/formata-dados-relatorio.js @@ -58,9 +58,7 @@ const defineNomeCientifico = dado => { export const formatarDadosParaRelatorioDeColetaPorLocalEIntervaloDeData = dados => { const romanos = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII']; const dadosFormatados = dados.map(dado => ({ - local: dado.locais_coletum?.complemento - ? `${dado.locais_coletum.descricao} ${dado.locais_coletum.complemento}` - : dado.locais_coletum?.descricao, + local: dado.locais_coletum?.descricao, data: `${String(dado.data_coleta_dia).padStart(2, '0')}/${romanos[dado.data_coleta_mes - 1]}/${dado.data_coleta_ano}`, tombo: dado?.hcf, numeroColeta: dado.numero_coleta || '-', diff --git a/src/herbarium/herbariumdatabase.js b/src/herbarium/herbariumdatabase.js index b87f3fd..fe0a985 100644 --- a/src/herbarium/herbariumdatabase.js +++ b/src/herbarium/herbariumdatabase.js @@ -796,7 +796,7 @@ export function insereAlteracaoSugerida(idUsuario, statusAlteracao, idTombo, tom status: statusAlteracao, tombo_hcf: idTombo, tombo_json: tomboJson, - identificacao: 1, + identificacao: true, data_identificacao_dia: diaIdentificacao, data_identificacao_mes: mesIdentificacao, data_identificacao_ano: anoIdentificacao, diff --git a/src/models/Alteracao.js b/src/models/Alteracao.js index dc9af65..a9ca697 100644 --- a/src/models/Alteracao.js +++ b/src/models/Alteracao.js @@ -41,11 +41,11 @@ export default (Sequelize, DataTypes) => { allowNull: false, }, ativo: { - type: DataTypes.SMALLINT, + type: DataTypes.BOOLEAN, allowNull: true, }, identificacao: { - type: DataTypes.SMALLINT, + type: DataTypes.BOOLEAN, allowNull: true, }, }; diff --git a/src/models/Autor.js b/src/models/Autor.js index 0287ed9..7848efa 100644 --- a/src/models/Autor.js +++ b/src/models/Autor.js @@ -24,8 +24,8 @@ export default (Sequelize, DataTypes) => { type: DataTypes.STRING(200), allowNull: false, }, - iniciais: { - type: DataTypes.STRING(200), + observacao: { + type: DataTypes.STRING(500), allowNull: true, }, }; diff --git a/src/models/LocalColeta.js b/src/models/LocalColeta.js index 62c7589..d9652c4 100644 --- a/src/models/LocalColeta.js +++ b/src/models/LocalColeta.js @@ -35,10 +35,7 @@ export default (Sequelize, DataTypes) => { type: DataTypes.TEXT, allowNull: true, }, - complemento: { - type: DataTypes.TEXT, - allowNull: true, - }, + cidade_id: { type: DataTypes.INTEGER, allowNull: true, diff --git a/src/routes/taxonomias.js b/src/routes/taxonomias.js index 3c88bee..8aa16c5 100644 --- a/src/routes/taxonomias.js +++ b/src/routes/taxonomias.js @@ -38,8 +38,7 @@ const generosOrdenacaoMiddleware = criaOrdenacaoMiddleware(['genero', 'familia', const especiesOrdenacaoMiddleware = criaOrdenacaoMiddleware(['especie', 'reino', 'familia', 'genero', 'familia', 'autor'], 'nome', 'asc'); const subEspeciesOrdenacaoMiddleware = criaOrdenacaoMiddleware(['subespecie', 'reino', 'familia', 'genero', 'especie', 'autor'], 'nome', 'asc'); const variedadesOrdenacaoMiddleware = criaOrdenacaoMiddleware(['variedade', 'reino', 'familia', 'genero', 'especie', 'autor'], 'nome', 'asc'); -const autorOrdenacaoMiddleware = criaOrdenacaoMiddleware(['autor', 'iniciais'], 'nome', 'asc'); - +const autorOrdenacaoMiddleware = criaOrdenacaoMiddleware(['autor', 'observacao'], 'nome', 'asc'); /** * @swagger * tags: @@ -1534,10 +1533,15 @@ export default app => { * properties: * nome: * type: string + * observacao: + * type: string + * nullable: true + * maxLength: 500 * required: * - nome * example: * nome: "A. Author" + * observacao: "Observação opcional sobre o autor" * responses: * 201: * description: Autor cadastrado com sucesso @@ -1548,6 +1552,7 @@ export default app => { * example: * id: 1 * nome: "A. Author" + * observacao: "Observação opcional sobre o autor" * '400': * $ref: '#/components/responses/BadRequest' * '401': @@ -1600,9 +1605,10 @@ export default app => { * type: integer * nome: * type: string - * iniciais: + * observacao: * type: string * nullable: true + * maxLength: 500 * '400': * $ref: '#/components/responses/BadRequest' * '401': diff --git a/src/routes/tombos.js b/src/routes/tombos.js index e1006ab..114938d 100644 --- a/src/routes/tombos.js +++ b/src/routes/tombos.js @@ -76,7 +76,7 @@ export default app => { * @swagger * /tombos/numeroColetor/{idColetor}: * get: - * summary: Obtém o número do coletor pelo ID + * summary: Obtém o próximo número de coleta do coletor * tags: [Tombos] * parameters: * - in: path @@ -87,19 +87,15 @@ export default app => { * description: ID do coletor * responses: * 200: - * description: Lista de HCF e números de coleta retornada com sucesso + * description: Próximo número de coleta retornado com sucesso * content: * application/json: * schema: - * type: array - * items: - * type: object - * properties: - * hcf: - * type: integer - * numero_coleta: - * type: integer - * nullable: true + * type: object + * properties: + * proximo_numero_coleta: + * type: integer + * description: Próximo número de coleta disponível (MAX + 1) * '404': * $ref: '#/components/responses/NotFound' * '500': diff --git a/src/validators/autor-atualiza.js b/src/validators/autor-atualiza.js index 8724754..d85fb1e 100644 --- a/src/validators/autor-atualiza.js +++ b/src/validators/autor-atualiza.js @@ -2,19 +2,22 @@ export default { nome: { in: 'body', isString: true, - isEmpty: false, + notEmpty: true, isLength: { options: [{ min: 3 }], }, }, - iniciais: { + observacao: { in: 'body', isString: true, optional: true, + isLength: { + options: [{ max: 500 }], + }, }, autor_id: { in: 'params', isInt: true, - isEmpty: false, + notEmpty: true, }, }; diff --git a/src/validators/autor-cadastro.js b/src/validators/autor-cadastro.js index 89e8243..5f0554c 100644 --- a/src/validators/autor-cadastro.js +++ b/src/validators/autor-cadastro.js @@ -7,7 +7,7 @@ export default { options: [{ min: 3 }], }, }, - iniciais: { + observacao: { in: 'body', isString: true, optional: true, diff --git a/src/validators/localColeta-cadastro.js b/src/validators/localColeta-cadastro.js index 6f1c853..c88a8a3 100644 --- a/src/validators/localColeta-cadastro.js +++ b/src/validators/localColeta-cadastro.js @@ -5,11 +5,7 @@ export default { notEmpty: true, errorMessage: 'Descrição é obrigatória.', }, - complemento: { - in: ['body'], - isString: true, - optional: true, - }, + cidade_id: { in: ['body'], isInt: true, diff --git a/src/views/ficha-tombo.ejs b/src/views/ficha-tombo.ejs index 28615bc..acced25 100644 --- a/src/views/ficha-tombo.ejs +++ b/src/views/ficha-tombo.ejs @@ -141,7 +141,7 @@
Herbário da Universidade Tecnológica Federal do Paraná -
Campus Campo Mourão
- +
HCF <%- tombo.hcf %> @@ -156,7 +156,7 @@
<% if (familia && familia.nome) { %>
- Família: + Família: <% if (familia && familia.nome.toLowerCase() !== 'indeterminada') { %> <%- tombo.familia.nome %> <% } %> @@ -177,18 +177,18 @@ <% 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 %> <% } %> + <% if (variedade && variedade.nome) { %> + var. <%- variedade.nome %> + <% } %> + <% if (variedade && variedade.autor) { %> + <%- variedade.autor.nome %> + <% } %>
@@ -213,9 +213,7 @@
Local de Coleta: - <% if (localColeta && localColeta.complemento) { %> - <%- localColeta.complemento %> - <% } %> + <% if (localColeta && localColeta.descricao) { %> <%- localColeta.descricao %> <% } %> @@ -275,7 +273,7 @@
nº: <%- tombo.numero_coleta %>
- +
Data: <%- romano_data_coleta %>