Skip to content

Corrige publicação de PDF entre outras questões v3.0.0rc23 - #1042

Merged
robertatakenaka merged 20 commits into
scieloorg:rcfrom
robertatakenaka:rc_merged_main_1036_1038
Aug 4, 2026
Merged

Corrige publicação de PDF entre outras questões v3.0.0rc23#1042
robertatakenaka merged 20 commits into
scieloorg:rcfrom
robertatakenaka:rc_merged_main_1036_1038

Conversation

@robertatakenaka

Copy link
Copy Markdown
Member

O que esse PR faz?

Este PR consolida a main com as PRs #1036 e #1038, reunindo as correções e refatorações abaixo para viabilizar uma release imediata da v3.x:

  • pid_provider: corrige falso-positivo de QueryDocumentMultipleObjectsReturnedError causado pela lógica OR em article_data_query. Introduz partial_body_query, que passa a comparar z_partial_body com múltiplos candidatos (z_partial_body__in) — hash legado (primeiro parágrafo) e o novo body_fragment_fingerprint (hash do corpo inteiro do artigo) — corrigindo também o bug de z_partial_body__in=(None, None) nunca casar com registros NULL (substituído por z_partial_body__isnull=True). Adiciona get_article_data_query(issue=True/False) para centralizar a composição da query nas branches "journal-issue-article" e "journal-article" de select_records. get_readable_data() passa a ter fallback para xml_with_pre.get_article_data() quando readable_data está vazio. compare_items agora trata None como string vazia ao chamar how_similar.
  • article / upload (PidReservation, PidV2Generator): get_first/PidReservation.get passam a aceitar name_list, permitindo casar contra pkg_name_variations (ou, na ausência, sps_pkg_name + deprecated_sps_pkg_name_list), reduzindo duplicidade de artigos/PIDs por variação de nome de pacote.
  • files_storage: renomeia parâmetros de MinioStorage/MinioConfiguration para minio_bucket, minio_object_name_prefix, minio_public_url, evitando colisão de nomes e deixando explícito o contrato. Adiciona kwargs property em MinioConfiguration para montar os argumentos do MinioStorage, corrigindo bug em que get_files_storage quebrava (AttributeError) ao usar self em vez do obj recuperado no fallback. Reorganiza a suíte de testes para files_storage/tests/.
  • upload (Package): renditions passa a usar path_in_zip (em vez de name) para ler o conteúdo dentro do ZIP, corrigindo leitura de renditions com nomes divergentes. prepare_to_publish/prepare_sps_package recebem force_update, permitindo forçar a reconstrução do SPSPkg mesmo quando já registrado/válido (usado no fluxo de publicação em lote). update_status_and_add_comments deixa de concatenar comments em qa_comment (comentado, decisão de não poluir a caixa de QA). Remove chamadas de logging.info de depuração no fluxo de geração de PID v2.
  • upload/wagtail_hooks: adiciona InspectFirstIndexView, restaurando o comportamento do ModelAdmin legado — clique no item da listagem abre a inspect view (quando disponível) em vez da edit view; a ação "Edit" continua acessível pelo menu "...".
  • package: SPSPkg ignora renditions sem content (evita upload de arquivo vazio/corrompido para o storage).
  • requirements: atualiza packtools de 4.16.8 para 4.16.11.

Onde a revisão poderia começar?

  • pid_provider/query_params.py (partial_body_query, article_data_query, get_article_data_query) — é o núcleo da correção do incidente de falso-positivo.
  • pid_provider/models.py (select_records, get_readable_data) — consumo do novo get_article_data_query.
  • files_storage/models.py (kwargs, minio_bucket, minio_object_name_prefix, minio_public_url) — correção do bug de get_files_storage.

Como este poderia ser testado manualmente?

  1. Rodar a suíte automatizada: pytest pid_provider/tests/test_query_params.py pid_provider/tests/test_select_records.py files_storage/tests/test_minio.py files_storage/tests/test_models.py.
  2. Reprocessar um XML cujo sps_pkg_name tenha variações (ex.: nome atual + nomes deprecated) e confirmar que não gera artigo/PID duplicado.
  3. Registrar dois XMLs com corpo textual distinto, mas com o mesmo rótulo genérico de primeiro parágrafo (ex.: "ARTIGO DE REVISÃO"), e confirmar que não há mais colisão de correspondência.
  4. Em MinioConfiguration.get_files_storage, testar o caminho de fallback (nome de configuração inexistente) e confirmar que não lança AttributeError.
  5. No admin do Upload (PackageViewSet), clicar em um item da listagem e confirmar que abre a tela de inspeção; verificar que "Edit" ainda está disponível no menu de ações.
  6. Publicar um pacote cujo SPSPkg já esteja registered_in_core e válido, forçando force_update=True, e confirmar que o pacote é reconstruído.

Algum cenário de contexto que queira dar?

Este PR é o merge da main com as PRs #1036 e #1038, feito com o objetivo de consolidar rapidamente as correções pendentes (principalmente a correção do incidente de falso-positivo em article_data_query) e viabilizar uma release imediata da versão v3.x. Por ser um merge consolidador, o diff cobre múltiplas áreas (pid_provider, files_storage, upload, article, package) que foram revisadas individualmente em suas PRs de origem.

Screenshots

Não aplicável (mudanças de backend/lógica de dados; a única alteração de UI é o comportamento de clique na listagem do Upload, sem alteração visual).

Quais são os tickets relevantes?

Referências


Segurança da informação (NSI.04)

Seção obrigatória. Marque as opções aplicáveis e justifique quando necessário. Referência: NSI.04 - Norma de Desenvolvimento Seguro.

Este PR manipula dados sensíveis ou pessoais (LGPD)?

  • Sim — descreva os controles de proteção aplicados (criptografia, mascaramento, anonimização, etc.):
  • Não

Este PR altera autenticação, autorização, controle de acesso ou gerenciamento de sessão?

  • Sim — descreva o que mudou e por quê:
  • Não (a mudança em wagtail_hooks.py altera apenas a navegação da listagem — para onde o clique leva —, sem impacto em permissões, autenticação ou sessão)

Este PR introduz, atualiza ou remove dependências de terceiros?

  • Sim — as novas dependências foram verificadas no SBOM/Trivy sem vulnerabilidades críticas/altas em aberto?
    • Verificado e aprovado
    • Pendente / vulnerabilidade aceita com justificativa: atualização do packtools de 4.16.8 para 4.16.11, necessária para suportar pkg_name_variations/body_fragment_fingerprint; verificação SBOM/Trivy a confirmar antes do merge final.
  • Não

Este PR foi validado pelo pipeline de segurança (SonarQube / Trivy)?

  • Sim — link do job:
  • Não aplicável a este PR (justifique): pendente de execução — a confirmar antes da release, dado o carácter de merge consolidador para release imediata.

Este PR concatena, monta ou executa comandos SQL, HTML ou JavaScript a partir de entrada externa?

  • Sim — confirme que há sanitização/parametrização (prepared statements, escaping, etc.):
  • Não (as queries usam o ORM do Django via Q()/filtros nomeados, sem concatenação de strings)

Este PR expõe novos endpoints, telas ou serviços?

  • Sim — HTTPS obrigatório está garantido e o acesso segue o princípio de menor privilégio?
  • Não (reaproveita views e endpoints já existentes; InspectFirstIndexView apenas customiza o comportamento de uma view já registrada)

Algum segredo, senha, chave ou token está sendo adicionado ao código-fonte?

  • Não, nenhum segredo foi commitado
  • Sim (bloquear merge e corrigir antes de prosseguir)

robertatakenaka and others added 20 commits July 26, 2026 15:29
…e todos os campos textuais

Propósito: eliminar falso positivo de correspondência na estratégia journal-article, onde um candidato de outro artigo (mesmo periódico, nenhum outro dado em comum) entrava como unmatched só por bater em um único hash textual (ex.: z_partial_body genérico 'ARTIGO DE REVISÃO'), causando QueryDocumentMultipleObjectsReturnedError indevido no registro de artigos novos.

Solução técnica: article_data_query deixou de montar OR condicional entre z_surnames/z_collab/z_links/z_partial_body e passou a sempre retornar uma query AND exigindo correspondência simultânea dos 4 campos. Adicionado o método get_article_data_query(issue: bool), que compõe explicitamente a busca com fascículo (dados textuais + issue_params + article_location_params) e sem fascículo (dados textuais + volume/number/suppl/elocation_id/fpage/lpage nulos no candidato).
…s e adiciona fallback em get_readable_data

Propósito: corrigir o mesmo incidente de correspondência indevida na origem — select_records montava a query da branch journal-article sem nenhuma restrição de fascículo/localização, e data_to_compare/data ficavam sem article_titles/body_fragment quando readable_data estava vazio (registros antigos).

Solução técnica: select_records passa a chamar qbuilder.get_article_data_query(issue=True) na branch journal-issue-article e get_article_data_query(issue=False) na branch journal-article, em vez de montar a query manualmente. Adicionado PidProviderXML.get_readable_data(), usado em data_to_compare e em data, que recalcula os dados legíveis via xml_with_pre.get_article_data() quando readable_data estiver vazio ou nulo.
…cobertura de get_article_data_query

Propósito: refletir a correção de article_data_query (fim do branch OR) e cobrir o novo método get_article_data_query, evitando regressão do bug de falso match relatado em produção.

Solução técnica: ArticleDataQueryTests reescrita para validar a query AND pura (sem merge com article_location_params) e garantir que a versão OR antiga não é mais produzida. Nova classe GetArticleDataQueryTests cobre issue=True/False e confirma que os dois ramos geram queries distintas. CompareItemsTests ganhou testes de regressão para o fallback de how_similar com None.
…_article_data_query

Propósito: manter a suíte compatível com a nova implementação de select_records, que não monta mais a query da branch journal-article/journal-issue-article manualmente.

Solução técnica: mock_qbuilder.get_article_data_query recebe side_effect parametrizado por issue (True/False), substituindo o mock direto de issue_params/article_data_query. Testes passam a verificar também a ordem e os argumentos das chamadas a get_article_data_query, incluindo o teste de lazy evaluation do generator.
…forçar match textual

Propósito: eliminar falso-positivo de correspondência na estratégia journal-article, onde um candidato de outro artigo (mesmo periódico, nenhum outro dado em comum) era classificado como unmatched só por bater em z_partial_body genérico (ex.: rótulo de seção 'ARTIGO DE REVISÃO'), causando QueryDocumentMultipleObjectsReturnedError indevido em artigos novos.

Solução técnica: QueryBuilderPidProviderXML passa a ler xml_adapter.xml_with_pre.body_fragment_fingerprint (fingerprint sha256 do corpo inteiro do artigo, já existente em XMLWithPre), sem necessidade de mudança no packtools/adapter. Novo método partial_body_query monta z_partial_body__in com os hashes disponíveis (legado + novo fingerprint), reaproveitando a coluna z_partial_body sem migração; quando nenhum hash está disponível, usa z_partial_body__isnull=True em vez de __in=(None, None), que em SQL nunca casaria com candidatos NULL. article_data_query simplificada para delegar o campo de corpo a partial_body_query.
…dy e documenta o campo

Propósito: persistir o novo sinal de correspondência (corpo inteiro do artigo) sem exigir migração de banco, reaproveitando a coluna z_partial_body já existente.

Solução técnica: _add_data passa a gravar xml_adapter.xml_with_pre.body_fragment_fingerprint em z_partial_body (antes gravava o hash de xml_adapter.z_partial_body, baseado só no primeiro parágrafo). Adicionado help_text no campo explicando que registros antigos mantêm o formato legado e que a query de match (partial_body_query) compara com ambos os formatos via IN.
… fingerprint do corpo inteiro

Propósito: validar a correção do falso-match do incidente e travar a regressão do IN (NULL, NULL), que nunca casaria com candidatos sem hash de corpo.

Solução técnica: nova classe PartialBodyQueryTests cobre os 4 cenários (só legado, só fingerprint, ambos, nenhum) e garante isnull=True no caso 'nenhum'. ArticleDataQueryTests atualizada para refletir a delegação a partial_body_query, incluindo teste de que dois artigos com mesmo z_partial_body legado mas fingerprints de corpo diferentes produzem queries distintas.
…dade_no_resultados_de_article_data_query

Remove ambiguidade no resultados de article data query
## Propósito
Atualizar a dependência packtools de 4.16.8 para 4.16.11, disponibilizando
recursos necessários para os ajustes subsequentes em Article, SPSPkg e
Package (pkg_name_variations, deprecated_sps_pkg_name_list,
get_complete_publication_date e path_in_zip em renditions).

## Solução técnica
Bump de versão da referência git no requirements/base.txt
(packtools.git@4.16.8 -> packtools.git@4.16.11).
…orage

## Propósito
Evitar chamada de upload_to_the_cloud com content=None quando o item não
possui conteúdo disponível (após KeyError tratado em item["content"]).

## Solução técnica
Adicionado `if not content: continue` antes da chamada de
upload_to_the_cloud, pulando itens sem conteúdo em vez de tentar enviá-los.
…xistente

## Propósito
Corrigir falha em localizar um Article já existente quando o sps_pkg_name
do pacote mudou entre versões (nomes depreciados), o que causava criação
de registros duplicados em vez de atualização do existente.

## Solução técnica
- get_first passa a aceitar o parâmetro name_list e inclui
  Q(sps_pkg__sps_pkg_name__in=name_list) na busca.
- create_or_update tenta obter xml_with_pre.pkg_name_variations; se o
  atributo não existir (AttributeError), monta a lista manualmente a
  partir de sps_pkg_name + deprecated_sps_pkg_name_list, e passa essa
  lista para get_first.
## Propósito
Corrigir múltiplos pontos relacionados à publicação de pacotes:
leitura incorreta do conteúdo de renditions dentro do zip, ausência de
fallback na extração da data de publicação, impossibilidade de forçar
reprocessamento do SPSPkg já registrado no Core, e falha na localização
de PidReservation/pid_v2 quando o nome do pacote mudou entre versões.
Também remove logs de depuração (logging.info) que não agregam valor
em produção e renomeia variável para refletir seu real significado.

## Solução técnica
- upload_package_directory_path: renomeia variável sps_pkg_name para
  xml_name, já que representa o nome do arquivo e não necessariamente
  o nome do pacote SPS.
- PackageZip.xmls: remove logging.info supérfluo.
- Package.renditions: passa a ler o conteúdo via
  zf.read(rendition["path_in_zip"]) em vez de rendition["name"], já que
  o path dentro do zip pode diferir do nome exibido.
- Package.set_pid_v2_and_publication_date: adiciona fallback para
  xml_with_pre.get_complete_publication_date() quando
  article_publication_date não está disponível/é inválida.
- Package.prepare_sps_package / prepare_to_publish: adicionam o
  parâmetro force_update, permitindo forçar a atualização do SPSPkg
  mesmo quando já registrado e válido no Core; ajustado o filtro de
  pdf_langs em renditions removendo a checagem redundante contra
  xml_with_pre.filenames.
- PidReservation.get: passa a aceitar name_list, permitindo buscar por
  múltiplas variações de pkg_name (pkg_name__in).
- PidV2Generator.generate: usa xml_with_pre.pkg_name_variations (com
  fallback para sps_pkg_name + deprecated_sps_pkg_name_list) ao
  consultar PidReservation, evitando falha na resolução de pid_v2
  quando o nome do pacote mudou; remove logs de depuração
  (logging.info) intermediários do fluxo.
…tar colisão de nomes

Propósito:
Os parâmetros do construtor de MinioStorage (bucket, object_name_prefix,
public_url) tinham nomes genéricos que colidiam semanticamente com
properties de mesmo nome em MinioConfiguration, dificultando o
rastreamento de onde cada valor era originado.

Solução técnica:
Renomeados os parâmetros do __init__ para minio_bucket,
minio_object_name_prefix e minio_public_url, deixando explícito que
são valores específicos de configuração do Minio. Atributos internos
(self.bucket, self.object_name_prefix, self.public_url) mantidos
inalterados para não impactar o restante da classe.
…com host_root_dir

Propósito:
get_files_storage montava o MinioStorage usando 'obj.host_root_dir or
obj.bucket' diretamente na chamada, sem centralizar essa regra, e a
property public_url aplicava o prefixo de host_root_dir por cima da
public_base_url informada pelo usuário, alterando um valor que deveria
ser respeitado como está.

Solução técnica:
- Introduzida a property kwargs em MinioConfiguration, centralizando a
  montagem dos argumentos usados por MinioStorage (agora com os nomes
  minio_bucket, minio_object_name_prefix, minio_public_url).
- Criada a property minio_bucket, que resolve a precedência entre
  host_root_dir e bucket.
- Property object_name_prefix renomeada para minio_object_name_prefix
  (mesma lógica: bucket vira prefixo somente quando host_root_dir
  existe).
- Property public_url renomeada para minio_public_url e corrigida:
  quando public_base_url é informado, ele é usado exatamente como
  está (sem concatenar prefixo); quando ausente, a URL é montada a
  partir do host e, nesse caso, o minio_bucket é anexado como
  subcaminho.
- get_files_storage agora usa obj.kwargs + minio_http_client, evitando
  duplicar a lógica de resolução de bucket/prefixo/url na chamada.
…ublic_url

Propósito:
Os testes existentes validavam os nomes antigos de parâmetros e a
regra antiga de public_url (que sempre concatenava o prefixo por cima
da public_base_url informada).

Solução técnica:
Testes ajustados para os nomes minio_bucket, minio_object_name_prefix
e minio_public_url, e para o novo comportamento de minio_public_url:
- Quando public_base_url é informada, é usada exatamente como está,
  mesmo havendo host_root_dir.
- Quando ausente, a URL é montada a partir do host, anexando
  minio_bucket como subcaminho.
Removidas notas de docstring que descreviam o contrato antigo.
@robertatakenaka
robertatakenaka merged commit 124eac6 into scieloorg:rc Aug 4, 2026
1 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant