feat: adiciona status NOT_PUBLIC para evitar requisições a documentos despublicados#1453
Open
robertatakenaka wants to merge 14 commits into
Open
feat: adiciona status NOT_PUBLIC para evitar requisições a documentos despublicados#1453robertatakenaka wants to merge 14 commits into
robertatakenaka wants to merge 14 commits into
Conversation
Propósito: Evitar requisição HTTP desnecessária para documentos que estão temporária ou efetivamente despublicados, identificados via is_public. Solução técnica: - Novo status NOT_PUBLIC em ArticleSource.StatusChoices. - create() e create_or_update() passam a aceitar is_public: quando False, o status é definido como NOT_PUBLIC em vez de PENDING. - create_or_update(): quando is_public volta a True e o status atual é NOT_PUBLIC, o status retorna para PENDING, reabrindo o pipeline. obj.save() só é chamado quando algo de fato mudou (changed). - add_pid_provider(): adiciona guarda no início — se o status é NOT_PUBLIC e force_update não foi passado, retorna sem executar request_xml nem request_pid. Notas adicionais (fora do escopo de is_public, incluídas neste diff): - is_completed deixa de chamar self.save() ao marcar COMPLETED. - ContribPerson passa a usar affiliation.set_normalized(...) em vez de add_normalized_affiliation(...).
Propósito:
Fornecer o dado de publicação/despublicação já na coleta (harvest),
para que o pipeline possa decidir sem precisar de requisição extra.
Solução técnica:
Inclui "is_public": item.get("status") no dict retornado por
OPACHarvester. Nome do campo de origem manteve-se status (herdado da
fonte); mapeado para is_public no dict de saída.
Propósito:
Propagar o sinal de publicação/despublicação coletado pelo harvester
até o ponto de despacho da task, para que chegue a
task_process_article_pipeline.
Solução técnica:
Adiciona "is_public": document.get("is_public") ao dict yield de
_iter_from_harvest.
Propósito: Fechar o fluxo do sinal is_public até ArticleSource.create_or_update, permitindo que o pipeline marque/reabra o status NOT_PUBLIC. Solução técnica: Novo parâmetro is_public em task_process_article_pipeline, repassado para ArticleSource.create_or_update(...).
Propósito: Criar o pacote de testes do app article. Solução técnica: Arquivo __init__.py vazio, necessário para o Django/pytest reconhecer o diretório como pacote de testes.
Propósito: Fornecer mixins/utilitários de teste reutilizáveis pelas demais suítes do app article (setup de dados, mocks comuns, supressão de logging do OpenSearch em ambiente de teste). Solução técnica: Novo arquivo test_mixins.py.
Propósito: Cobrir com testes unitários os models do app article (Article, ArticleSource, ContribPerson, etc.). Solução técnica: Novo arquivo test_models.py, usando os mixins de test_mixins.py e unittest.mock para isolar dependências externas.
Propósito: Cobrir com testes unitários as tasks do app article (task_dispatch_articles, task_process_article_pipeline, etc.) e o ArticleIteratorBuilder. Solução técnica: Novo arquivo test_tasks.py, usando mock-based testing (unittest.mock) e os mixins de test_mixins.py.
Propósito:
Persistir no banco a nova choice not_public do campo status de
ArticleSource, introduzida para suportar documentos temporária ou
efetivamente despublicados.
Solução técnica:
Migração gerada automaticamente (AlterField) a partir da alteração em
ArticleSource.StatusChoices, adicionando ("not_public", "Not public")
à lista de choices do campo status.
…Harvester
Propósito:
Permitir coletar documentos de um periódico específico, em vez de
sempre buscar a coleção inteira.
Solução técnica:
- AMHarvester: novo parâmetro journal (ISSN); quando informado, é
incluído como issn nos params da requisição.
- OPACHarvester: novo parâmetro journal (acrônimo); quando informado,
é incluído como journal na querystring. URL base (main_url) é
montada uma única vez fora do loop de paginação, e cada página
apenas concatena &page={page}, evitando reconstruir toda a URL a
cada iteração.
Propósito:
Usar o novo suporte a filtro por periódico dos harvesters, permitindo
respeitar journal_acron_list e reduzir o volume de cada requisição de
harvest (por periódico em vez de coleção inteira).
Solução técnica:
- Import de SciELOJournal em journal.models.
- _iter_from_harvest passa a consultar SciELOJournal (com
select_related('collection')) filtrando por collection_acron_list e
journal_acron_list, obtendo tuplas (collection__acron3,
journal_acron, issn_scielo) distintas.
- Para cada tupla, _build_harvester é chamado passando journal_acron
(OPAC) ou issn_scielo (ArticleMeta), instanciando um harvester por
periódico em vez de um único harvester por coleção.
- _build_harvester ganha os parâmetros journal_acron e journal_id,
repassados ao harvester correspondente (OPACHarvester ou
AMHarvester) via kwargs['journal'].
- Remove logging.info residual (collection_acron, harvester) do loop
anterior.
…CHarvester Propósito: Permitir interromper a coleta de documentos do OPAC após um número máximo de páginas, útil para testes e execuções controladas sem depender apenas de total_pages. Solução técnica: Novo parâmetro stop em OPACHarvester.__init__. Dentro do loop de paginação de harvest_documents, após incrementar page, encerra o loop (break) se stop for informado e page ultrapassar esse limite — checagem feita antes da verificação de total_pages.
Propósito: Expor o novo limite de páginas (stop) do OPACHarvester através do ArticleIteratorBuilder, para uso em _iter_from_harvest. Solução técnica: Novo parâmetro stop em ArticleIteratorBuilder.__init__, armazenado em self.stop. Em _build_harvester, quando a coleção é 'scl' e self.stop está definido, o valor é incluído em kwargs['stop'] antes de instanciar o OPACHarvester. Corrige também a URL padrão do OPAC (www.scielo.br -> https://www.scielo.br).
…Builder Propósito: Permitir configurar, a partir da task orquestradora, o limite de páginas (stop) usado no harvest via OPAC. Solução técnica: Novos parâmetros verify e stop na assinatura de task_dispatch_articles; stop é repassado à instanciação de ArticleIteratorBuilder. Nota: verify é aceito na assinatura mas não é utilizado em nenhum ponto deste diff — confirmar se é uso futuro intencional ou parâmetro remanescente antes de mergear.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
O que esse PR faz?
Implementa suporte a filtragem por periódico (
journal_acron) na coleta de artigos e adiciona tratamento de artigos não públicos (is_public), além de expandir a cobertura de testes unitários do apparticle.Principais mudanças:
ArticleIteratorBuilder(article/controller.py): a iteração por coleção passou a ser feita viaSciELOJournal(join comCollection), permitindo filtrar porjournal_acron_listalém decollection_acron_list. O harvester agora recebe o periódico (journal_acron/journal_id) e um novo parâmetrostop(limite de páginas). O item retornado pelo iterator passou a incluiris_public.ArticleSource(article/models.py): novo statusNOT_PUBLICnoStatusChoices.create/create_or_updateagora recebemis_publice ajustam o status de acordo (defineNOT_PUBLICquandois_public=False; retorna aPENDINGse um artigo antes não-público se tornar público). O método de processamento passa a interromper artigos marcados comoNOT_PUBLIC, a menos queforce_update=Trueseja passado. Correção:complete()não fazia maisself.save()redundante.add_normalized_affiliation→set_normalizedna chamada feita porContribPerson.task_dispatch_articles/task_process_article_pipeline(article/tasks.py): novos parâmetrosverify,stopeis_public, propagados atéArticleSource.create_or_update.core/utils/harvesters.py):AMHarvester: novo parâmetrojournal, incluído comoissnna query da API do ArticleMeta.OPACHarvester: novos parâmetrosjournalestop; extração do campois_publica partir deitem.get("status")retornado pela API do OPAC; paginação agora respeitastop; URL base passou a usarhttps://explicitamente.0049_alter_articlesource_status.py: adiciona a choiceNOT_PUBLICao campostatusdeArticleSource.article/tests/test_mixins.py,test_models.pyetest_tasks.py.Onde a revisão poderia começar?
Sugiro começar por
article/models.py(lógica deis_public/NOT_PUBLICemArticleSource), seguido dearticle/controller.py(mudança na fonte de iteração de coleções paraSciELOJournal) ecore/utils/harvesters.py(novos parâmetrosjournal/stope extração deis_public).Como este poderia ser testado manualmente?
article:task_dispatch_articlesinformandocollection_acron_listejournal_acron_listpara validar o filtro por periódico viaSciELOJournal.statusindicando não-público e verificar que oArticleSourcecorrespondente recebestatus=not_publice que o processamento é interrompido (semforce_update).force_update=Truesobre umArticleSourceemNOT_PUBLICpara confirmar que ele volta a ser processado.OPACHarvestercomstopdefinido (ex.:stop=2) para confirmar que a coleta é interrompida na página esperada.Conferir as datas de atualização de Pid Provider XML e Article
Algum cenário de contexto que queira dar?
Este PR resolve a necessidade de: (1) coletar artigos filtrando por periódico específico dentro de uma coleção (antes só era possível por coleção inteira); (2) tratar corretamente artigos que a fonte (OPAC) sinaliza como não públicos, evitando reprocessamento desnecessário até que se tornem públicos ou até um
force_updateexplícito. A migração adiciona apenas uma nova choice ao campostatus, sem impacto em dados existentes.Screenshots
Não aplicável (mudança de backend/lógica de processamento).
Quais são os tickets relevantes?
Relacionado com #1449
Referências
A preencher, se houver documentação ou discussão relacionada (ex. issue do OPAC sobre campo
status/visibilidade).Segurança da informação (NSI.04)
Este PR manipula dados sensíveis ou pessoais (LGPD)?
is_public/NOT_PUBLICrefere-se à visibilidade editorial do artigo (status de publicação), não a dado pessoal de indivíduo. Os testes emtest_models.pyetest_tasks.pyque envolvem nomes, e-mails e ORCID deContribPerson/ArticleAffiliation/ResearcherIdentifierusam exclusivamente dados fictícios/de exemplo e cobrem funcionalidade já existente, não introduzida por este PR.Este PR altera autenticação, autorização, controle de acesso ou gerenciamento de sessão?
Este PR introduz, atualiza ou remove dependências de terceiros?
test_models.pypassa a importarfreezegun(usado para congelar datas na criação de artigos em testes de deduplicação). Se ainda não constar norequirements/SBOM do projeto, é necessário adicioná-la e submetê-la à verificação de vulnerabilidades antes do merge.Este PR foi validado pelo pipeline de segurança (SonarQube / Trivy)?
Este PR concatena, monta ou executa comandos SQL, HTML ou JavaScript a partir de entrada externa?
filter,values_list,select_related) com parâmetros tipados; as chamadas HTTP feitas pelos harvesters usamurlencodepara montar a query string, sem concatenação direta de entrada externa em SQL/HTML/JS.Este PR expõe novos endpoints, telas ou serviços?
OPACHarvesterfoi corrigida dewww.scielo.br(sem esquema) parahttps://www.scielo.br, reforçando o uso de HTTPS nas requisições já existentes. Recomenda-se confirmar queverify=True(verificação de certificado SSL) permanece o padrão em produção, já queAMHarvester/OPACHarvesteraceitamverify=False.Algum segredo, senha, chave ou token está sendo adicionado ao código-fonte?