Traz para o **core** as atualizações já implementadas no **upload** para o app pid_provider#1449
Open
robertatakenaka wants to merge 11 commits into
Conversation
Propósito: disponibilizar os novos métodos do packtools utilizados pelas refatorações do pid_provider (get_article_data, get_complete_publication_date, deprecated_sps_pkg_name_list, get_body_fragment). Solução técnica: bump de versão fixado via git+https no requirements/base.txt.
Propósito: padronizar os valores possíveis do campo status do modelo XMLURL, substituindo texto livre por opções controladas. Solução técnica: cria XMLURL_STATUS_SUCCESS, XMLURL_STATUS_XML_FETCH_FAILED, XMLURL_STATUS_PID_PROVIDER_XML_FAILED e a tupla XMLURL_STATUS.
Propósito: permitir que is_updated() sinalize, via exceção, que o registro deve ser ignorado (equal ou já atualizado), em vez de retornar dados silenciosamente. Solução técnica: cria a classe SkipSavePidProviderXML(Exception).
…omparação por similaridade Propósito: substituir o cálculo de score aditivo por campo por comparação percentual baseada em similaridade textual, e simplificar o builder de queries centralizando o acesso aos dados do adaptador. Solução técnica: adiciona compare/compare_items/compare_lists usando how_similar; QueryBuilderPidProviderXML passa a usar adapter_data, compare_data e xml_with_pre_data como fonte única, com validate_input_data() e article_location_params novos; remove as antigas cached_property espelhando atributos do xml_adapter.
…e XML e cria auditoria por documento
Propósito: tornar o processo de identificação de documentos já registrados
mais preciso (comparação por similaridade em estágios) e garantir
rastreabilidade de toda tentativa de registro (sucesso, erro, conflito,
skip), substituindo o modelo de eventos XMLEvent.
Solução técnica:
- get_records/get_record/best_matches substituídos por select_records
(generator em estágios: ids, journal-issue-article, journal-article),
select_record e get_best_match, usando percentual_score.
- PidProviderXML.register() reescrito com try/except/finally, sempre
gravando o evento via PidProviderXMLRegistration.record().
- is_updated() passa a levantar SkipSavePidProviderXML em vez de retornar
registered.data.
- Novo PidProviderXMLManager aplicando select_related('current_version')
por padrão.
- Novo campo readable_data em PidProviderXML.
- add_collections extraído de _save(), com fallback via FieldError entre
scielojournal e journalproc (compatibilidade upload/core).
- Corrige bug em merge_records (other_pid.version, não
other_pid.current_version) e em mark_items_as_invalid (persiste o status
calculado via bulk_update).
- XMLURL ganha os campos detail e is_public e o classmethod record().
- Remove modelo XMLEvent e o método add_event().
…o de XMLEvent Propósito: aplicar no banco de dados as mudanças de modelo introduzidas na refatoração do pid_provider. Solução técnica: cria o modelo PidProviderXMLRegistration com seus índices (pid_provide_pkg_nam_2db0b2_idx, pid_provide_event_s_3c9ae7_idx, pid_provide_created_94fb08_idx, pid_provide_pid_pro_c9fb0e_idx); remove os campos creator, ppxml e updated_by de XMLEvent e em seguida exclui o modelo XMLEvent; adiciona readable_data em PidProviderXML; adiciona detail e is_public em XMLURL, altera o campo status (com choices) e cria o índice pid_provide_is_public_idx.
…onViewSet no Wagtail admin Propósito: permitir consulta, pela interface administrativa, das URLs com falha de processamento (XMLURL) e dos eventos de auditoria de registro de XML (PidProviderXMLRegistration). Solução técnica: cria XMLURLViewSet e PidProviderXMLRegistrationViewSet (list_display, list_filter, search_fields e select_related no get_queryset) e os inclui em PidProviderViewSetGroup.
|
@robertatakenaka o pytest do CI está falhando porque está usando o |
patymori
requested changes
Jul 20, 2026
| from wagtailautocomplete.edit_handlers import AutocompletePanel | ||
|
|
||
| from collection.models import Collection | ||
| from core.widgets import ReadOnlyPrettyJSONWidget |
There was a problem hiding this comment.
Ocorreu o seguinte erro:
Traceback (most recent call last):
File "/app/manage.py", line 31, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.11/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.11/site-packages/django/core/management/__init__.py", line 416, in execute
django.setup()
File "/usr/local/lib/python3.11/site-packages/django/__init__.py", line 24, in setup
apps.populate(settings.INSTALLED_APPS)
File "/usr/local/lib/python3.11/site-packages/django/apps/registry.py", line 116, in populate
app_config.import_models()
File "/usr/local/lib/python3.11/site-packages/django/apps/config.py", line 269, in import_models
self.models_module = import_module(models_module_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 940, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "/app/article/models.py", line 47, in <module>
from pid_provider.models import PidProviderXML
File "/app/pid_provider/models.py", line 24, in <module>
from core.widgets import ReadOnlyPrettyJSONWidget
ModuleNotFoundError: No module named 'core.widgets'
patymori
requested changes
Jul 21, 2026
patymori
left a comment
There was a problem hiding this comment.
- Verificar os impactos da remoção do método PidProviderXML.add_event()
- Remoção de testes unitários do módulo invalida um dos pontos dos testes manuais sugeridos no PR
- Sugestão: aumentar a cobertura de testes unitários no módulo article.
| return True | ||
| return False | ||
|
|
||
| def add_event(self, name, proc_status, detail=None, errors=None, exceptions=None): |
There was a problem hiding this comment.
@robertatakenaka encontrei alguns lugares que referenciam este método:
…erXML Propósito: Reverter a remoção do model XMLEvent feita em refatoração anterior — o rastreio de eventos por documento (registration attempts, validation errors, etc.) via XMLEvent ainda é necessário e não deve ser substituído pelo novo PidProviderXMLRegistration, que serve a um propósito complementar (auditoria agregada de register()), não ao histórico de eventos por instância de PidProviderXML. Solução técnica: Reintroduzido o import de BaseEvent em 'from tracker.models import BaseEvent, UnexpectedEvent'. Restaurado o método PidProviderXML.add_event(name, proc_status, detail=None, errors=None, exceptions=None), que atualiza proc_status, salva a instância e delega o registro do evento a XMLEvent.register(). Restaurado o model XMLEvent(BaseEvent, CommonControlField), com o campo ppxml (ParentalKey para PidProviderXML, related_name='events') e o classmethod register(), que cria a instância, marca completed conforme presença de errors/exceptions e delega a finalização a BaseEvent.finish().
Propósito: Consistência com a reversão feita em models.py — como o model XMLEvent voltou a existir no código, a migration 0017 (que removia seus campos creator/ppxml/updated_by e por fim o próprio model via DeleteModel) deixou de refletir o estado real dos models e precisa ser descartada. Solução técnica: Excluído o arquivo pid_provider/migrations/0017_pidproviderxmlregistration_remove_xmlevent_creator_and_more.py. A criação de PidProviderXMLRegistration e os demais campos que essa migration também introduzia (readable_data, XMLURL.detail/is_public, choices de XMLURL.status, índices) precisam ser recriados em uma nova migration, desta vez sem a remoção de XMLEvent — rodar 'python manage.py makemigrations pid_provider' para gerá-la a partir do estado atual dos models.
Member
Author
|
@patymori o foco principal deste PR é para garantir a atribuição / recuperação do pid v3 que não deve ter relacionamento diretamente com o Article, pois se houver o PR vai ficar muito extenso. |
patymori
requested changes
Jul 21, 2026
patymori
left a comment
There was a problem hiding this comment.
Ocorreu um outro erro:
/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py:98: RuntimeWarning: Accessing the database during app initialization is discouraged. To fix this warning, avoid executing queries in AppConfig.ready() or when your app modules are imported.
warnings.warn(self.APPS_NOT_READY_WARNING_MSG, category=RuntimeWarning)
System check identified some issues:
WARNINGS:
?: (urls.W005) URL namespace 'pid_provider' isn't unique. You may not be able to reverse all URLs in this namespace
?: (wagtailadmin.W003) The WAGTAILADMIN_BASE_URL setting is not defined
HINT: This should be the base URL used to access the Wagtail admin site. Without this, admin URLs outside of the admin (e.g. notification emails and the user bar) will not display correctly.
?: settings.ACCOUNT_AUTHENTICATION_METHOD is deprecated, use: settings.ACCOUNT_LOGIN_METHODS = {'username'}
?: settings.ACCOUNT_EMAIL_REQUIRED is deprecated, use: settings.ACCOUNT_SIGNUP_FIELDS = ['email*', 'username*', 'password1*', 'password2*']
pid_provider.FixPidV2.pid_provider_xml: (fields.W342) Setting unique=True on a ForeignKey has the same effect as using a OneToOneField.
HINT: ForeignKey(unique=True) is usually better served by a OneToOneField.
Operations to perform:
Apply all migrations: account, admin, altmetric, article, auth, book, collection, contenttypes, core, core_settings, django_celery_beat, django_celery_results, doi, doi_manager, editorialboard, files_storage, home, institution, issue, journal, journalpage, location, organization, otp_totp, pid_provider, reference, report, researcher, sessions, silk, simple_translation, sites, socialaccount, taggit, thematic_areas, tracker, users, vocabulary, wagtail_2fa, wagtail_localize, wagtailadmin, wagtailcore, wagtaildocs, wagtailembeds, wagtailforms, wagtailimages, wagtailredirects, wagtailsearch, wagtailsearchpromotions, wagtailusers, xml_validation
Running migrations:
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 103, in _execute
return self.cursor.execute(sql)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django_prometheus/db/common.py", line 69, in execute
return super().execute(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
psycopg2.errors.DuplicateTable: relation "pid_provider_pidproviderxmlregistration" already exists
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/app/manage.py", line 31, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.11/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.11/site-packages/django/core/management/__init__.py", line 436, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python3.11/site-packages/django/core/management/base.py", line 416, in run_from_argv
self.execute(*args, **cmd_options)
File "/usr/local/lib/python3.11/site-packages/django/core/management/base.py", line 460, in execute
output = self.handle(*args, **options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/core/management/base.py", line 107, in wrapper
res = handle_func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/core/management/commands/migrate.py", line 353, in handle
post_migrate_state = executor.migrate(
^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/db/migrations/executor.py", line 135, in migrate
state = self._migrate_all_forwards(
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/db/migrations/executor.py", line 167, in _migrate_all_forwards
state = self.apply_migration(
^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/db/migrations/executor.py", line 255, in apply_migration
state = migration.apply(state, schema_editor)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/db/migrations/migration.py", line 132, in apply
operation.database_forwards(
File "/usr/local/lib/python3.11/site-packages/django/db/migrations/operations/models.py", line 97, in database_forwards
schema_editor.create_model(model)
File "/usr/local/lib/python3.11/site-packages/django/db/backends/base/schema.py", line 512, in create_model
self.execute(sql, params or None)
File "/usr/local/lib/python3.11/site-packages/django/db/backends/postgresql/schema.py", line 45, in execute
return super().execute(sql, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/db/backends/base/schema.py", line 204, in execute
cursor.execute(sql, params)
File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 122, in execute
return super().execute(sql, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 79, in execute
return self._execute_with_wrappers(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 92, in _execute_with_wrappers
return executor(sql, params, many, context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 100, in _execute
with self.db.wrap_database_errors:
File "/usr/local/lib/python3.11/site-packages/django/db/utils.py", line 91, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 103, in _execute
return self.cursor.execute(sql)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django_prometheus/db/common.py", line 69, in execute
return super().execute(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
django.db.utils.ProgrammingError: relation "pid_provider_pidproviderxmlregistration" already exists
Member
Author
|
@patymori execute: make django_bashpython manage.py migrate pid_provider 0017 --fake
python manage.py migrate
|
7 tasks
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?
Este PR traz para o core as atualizações já implementadas no upload (1026) para o app
pid_provider, aplicando um conjunto de refatorações no fluxo de correspondência/registro de XML e adicionando um modelo de auditoria por documento. Principais mudanças:get_records/get_record/best_matches(baseados em score aditivo por campo) são substituídos porselect_records(generator com estratégias em estágios:ids→journal-issue-article→journal-article) eselect_record/get_best_match, que comparam candidatos usando funções de similaridade textual (compare,compare_items,compare_listsemquery_params.py), retornandopercentual_scoreem vez de score bruto.QueryBuilderPidProviderXMLrefatorado: centraliza o acesso viaadapter_data,compare_dataexml_with_pre_data, e ganhavalidate_input_data()earticle_location_params.PidProviderXMLRegistration, que grava (viafinallyemregister()) o resultado de cada tentativa (created,updated,skipped,forbidden,conflict,unmatched,bad_request,error), comdetailem JSON. Este modelo substituiXMLEvent, que é removido junto companels_evente o métodoadd_event.0017_pidproviderxmlregistration_remove_xmlevent_creator_and_more.py, que:PidProviderXMLRegistration(com FKscreator,updated_by,pid_provider_xmle índicespid_provide_pkg_nam_2db0b2_idx,pid_provide_event_s_3c9ae7_idx,pid_provide_created_94fb08_idx,pid_provide_pid_pro_c9fb0e_idx);creator,ppxmleupdated_bydeXMLEvente, em seguida, exclui o modeloXMLEvent;readable_data(JSONField) emPidProviderXML;detail(JSONField) eis_public(BooleanField) emXMLURL, altera o campostatus(agora comchoices) e cria o índicepid_provide_is_public_idx.PidProviderXML.register()reescrito: usatry/except/finallypara sempre registrar o evento de auditoria, inclusive quandois_updatedsinaliza que o registro deve ser pulado (novo fluxo via exceçãoSkipSavePidProviderXML, em vez de retornarregistered.datasilenciosamente).merge_records:other_pid.current_version(atributo inexistente emOtherPid) corrigido paraother_pid.version.mark_items_as_invalid: o valor calculado de invalidade agora é de fato persistido viabulk_update.add_collections(extraído de_save): usaFieldErrorpara detectar se a coleção usascielojournaloujournalproc, tratando a divergência estrutural entre upload e core.PidProviderXMLManagercustomizado aplicaselect_related("current_version")em todoPidProviderXML.objects; uso dePrefetch(..., to_attr=...)emmerge_recordspara não quebrar o cache do prefetch ao filtrar.XMLURL: novoclassmethod record()para centralizar a gravação de tentativas de URL com falha, usando os novos camposdetaileis_public.XMLURLViewSetePidProviderXMLRegistrationViewSetregistrados noPidProviderViewSetGroup.packtoolsatualizado de4.15.0para4.16.8(necessário para os novos métodos usados emmodels.py, comoget_article_data,get_complete_publication_date,deprecated_sps_pkg_name_list,get_body_fragment).Onde a revisão poderia começar?
pid_provider/models.py, pelo métodoPidProviderXML.register(). Em seguida,select_records/select_record/get_best_matchno mesmo arquivo ecompare/compare_itemsempid_provider/query_params.py. Por fim, conferir a migração0017_pidproviderxmlregistration_remove_xmlevent_creator_and_more.py, especialmente a remoção do modeloXMLEvent(dado que remove uma tabela existente).Como este poderia ser testado manualmente?
python manage.py migrate pid_provider.0017roda sem erros e que a tabela deXMLEventdeixa de existir (verificar se não há dependências externas quebradas por essa remoção, ex.: relatórios ou dashboards que ainda consultemXMLEvent).PidProviderXML;PidProviderXMLRegistrationcomevent_status="created".SkipSavePidProviderXML).select_record/get_best_matchreconhece o mesmo documento e atualiza (event_status="updated").event_status="conflict"/unmatched.status,is_public,event_status).pid_provider(python manage.py test pid_provider).Algum cenário de contexto que queira dar?
O app
pid_provideré compartilhado entre os sistemas upload e core. As mudanças deste PR já foram desenvolvidas e validadas no upload e este PR traz essas atualizações para o core, mantendo os dois projetos alinhados. A migração inclui a remoção definitiva do modeloXMLEvent(substituído porPidProviderXMLRegistration), portanto é importante avaliar se há dados históricos relevantes emXMLEventantes de aplicar em produção. A atualização dopacktoolspara4.16.8é pré-requisito funcional das mudanças emmodels.py.Screenshots
Não aplicável (mudanças de backend/modelo de dados).
Quais são os tickets relevantes?
scieloorg/scms-upload#1026
Referências
pid_provider(registro e correspondência de XML).proc/package(resultados estruturados emdict).packtoolsentre4.15.0e4.16.8.Segurança da informação (NSI.04)
Este PR manipula dados sensíveis ou pessoais (LGPD)?
readable_datae odetailde auditoria armazenam metadados bibliográficos já presentes no XML público do documento; nenhum dado pessoal sensível é tratado.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?
packtoolsé biblioteca própria da SciELO (scieloorg/packtools), não uma dependência de terceiros; trata-se apenas de bump de versão interno necessário para os novos métodos usados nesta refatoração.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?
Q,filter,Prefetch), sem SQL raw.Este PR expõe novos endpoints, telas ou serviços?
XMLURLViewSet,PidProviderXMLRegistrationViewSet), restritas à área administrativa (login/staff), seguindo as políticas de permissão já aplicadas aos demais snippets do app.Algum segredo, senha, chave ou token está sendo adicionado ao código-fonte?
Boa lembrança — ajusta a leitura de risco. Segue a correção:
Ajustes no texto do PR
No corpo do PR, troque a frase sobre o packtools por:
E no "Algum cenário de contexto que queira dar?", ajuste a última frase para:
Na seção de Segurança da Informação (NSI.04), corrija:
Este PR introduz, atualiza ou remove dependências de terceiros?
packtoolsé biblioteca própria da SciELO (scieloorg/packtools), não uma dependência de terceiros; trata-se apenas de bump de versão interno necessário para os novos métodos usados nesta refatoração.Este PR foi validado pelo pipeline de segurança (SonarQube / Trivy)?