Skip to content

Corrige questões do fluxo de journal: coleta de dados do core e publicação no site qa ou público - #1047

Merged
robertatakenaka merged 9 commits into
scieloorg:mainfrom
robertatakenaka:atualiza_main_com_rc_1
Aug 6, 2026
Merged

Corrige questões do fluxo de journal: coleta de dados do core e publicação no site qa ou público#1047
robertatakenaka merged 9 commits into
scieloorg:mainfrom
robertatakenaka:atualiza_main_com_rc_1

Conversation

@robertatakenaka

@robertatakenaka robertatakenaka commented Aug 6, 2026

Copy link
Copy Markdown
Member

O que esse PR faz?

Corrige a troca de ISSN eletrônico/impresso na publicação de periódicos (publication/api/journal.py), impede que sponsor/publisher vazios entrem no payload de publicação, otimiza a deduplicação de nomes em publication/utils/journal.py, corrige a inicialização de detail em caminhos de exceção de proc/source_classic_website.py, consolida a criação de instituições em proc/source_core_api.py (evitando chamadas duplicadas a Institution.get_or_create quando a mesma instituição aparece como owner/publisher/sponsor) e trata o caso de previous_journal_title/next_journal_title retornarem como dict aninhado. Também corrige a tradução de "Publisher" em es/pt_BR, reorganiza os painéis de instituições no admin do Journal em uma aba única, remove campos de auditoria de search_fields do Institution e aumenta o max_length de next_journal_title.

Onde a revisão poderia começar?

publication/api/journal.py, função publish_journal — é onde está o bug de maior impacto (troca de ISSN). Em seguida, proc/source_core_api.py para a consolidação da criação de instituições.

Como este poderia ser testado manualmente?

  1. Publicar um periódico com ISSN eletrônico e impresso distintos e verificar no website que cada um foi gravado no campo correto.
  2. Publicar um periódico sem sponsor e/ou sem publisher e verificar que o payload não contém entradas vazias.
  3. Salvar um OfficialJournal com next_journal_title acima de 128 caracteres.
  4. Abrir o admin do Journal e confirmar aba única "Instituições" com owner, publisher e sponsor.
  5. Migrar via source_core_api um journal cuja mesma instituição apareça como owner e publisher; confirmar (via logs/queries) que Institution.get_or_create é chamado apenas uma vez para esse nome.
  6. Forçar uma exceção antes da montagem completa de detail em migrate_journal/migrate_issue e confirmar que event.finish() não quebra.

Algum cenário de contexto que queira dar?

Estas correções surgiram durante a estabilização do fluxo de publicação de periódicos no scms-upload v3.x. Os bugs de ISSN trocado e payload com campos vazios têm impacto direto no website (dados publicados incorretamente), enquanto a consolidação em source_core_api.py é uma otimização de performance/consistência identificada durante a migração de dados do Core.

Screenshots

Não aplicável (mudanças de backend/API; a reorganização do admin do Journal pode ser ilustrada se necessário).

Quais são os tickets relevantes?

Closes #1046

Referências

Não aplicável.


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

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:
  • 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): [preencher após execução do pipeline no CI]

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.): os dados externos (nomes de instituições vindos da API do Core) são usados exclusivamente via Django ORM (Institution.get_or_create), sem concatenação manual de SQL; não há execução de HTML/JS dinâmico a partir dessa entrada.
  • Não

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

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)

Motivação: a tradução anterior ('Editor') causava ambiguidade com o papel
editorial do periódico, confundindo usuários da interface em espanhol.

Técnico: msgstr de journal/models.py:277,288 atualizado de 'Editor' para
'Publicador'.
Motivação: mesma correção de ambiguidade aplicada à interface em espanhol,
mantendo consistência entre os dois idiomas.

Técnico: msgstr de journal/models.py:277,288 atualizado de 'Editor' para
'Publicador'.
…e campos de auditoria da busca

Motivação: campos de auditoria (creator, updated, created, updated_by) em
search_fields geravam busca textual sobre timestamps/FKs, sem utilidade
prática e com custo de performance na listagem de Institution.

Técnico: institution_type migrado de search_fields para list_filter (filtro
lateral, mais adequado por ser campo de escolha); creator/updated/created/
updated_by removidos de search_fields.
…iza painéis do Journal em aba única de Instituições

Motivação: títulos de periódicos sucessores frequentemente excedem 128
caracteres, causando truncamento/erro ao salvar via API do Core. Além
disso, ter abas separadas para Owner e Publisher no admin fragmentava
a edição das instituições relacionadas ao journal.

Técnico:
- OfficialJournal.next_journal_title: max_length 128 -> 500.
- Migration 0015 gerada via makemigrations (AlterField).
- Journal: panels_owner e panels_publisher substituídos por
  panels_institution único, agrupando InlinePanel de owner, publisher e
  sponsor (antes sponsor não aparecia em nenhum panel dedicado).
- edit_handler: ObjectList 'Owners' e 'Publisher' unificados em
  ObjectList 'Instituições'.
…ios no payload

Propósito: dois problemas distintos neste arquivo. (1) Em publish_journal,
issn_electronic e issn_print estavam invertidos na chamada a
fetch_and_create_journal, fazendo o ISSN eletrônico ser gravado como
impresso e vice-versa. (2) Valores None/vazios de sponsor ou nome de
publisher podiam ser incluídos no payload de publicação, gerando
entradas inválidas na API do website.

Solução técnica: corrigida a passagem de argumentos para
issn_electronic=journal.issn_electronic e issn_print=journal.issn_print
(antes estavam trocados); adicionadas guard clauses (if not sponsor /
if not name: return) em add_sponsor e add_publisher antes de popular
self.data.
…er e ignora nomes vazios

Motivação: a lista 'names' com checagem manual 'if name not in names'
era O(n) por inserção e não tratava nomes vazios/None, podendo enviar
publishers duplicados ou inválidos para o payload de publicação.

Técnico: build_journal substitui list 'names' por set(); adiciona guarda
'if not name: continue' antes de builder.add_publisher, tanto para
journal.owner quanto para journal.publisher.
…urnal/migrate_issue

Motivação: em caminhos de exceção anteriores ao bloco onde 'detail' é
populado, o event.finish(detail=detail) recebia None, causando erro ao
tentar fazer .update() ou serializar detail como dict em outros pontos
do tracker.

Técnico: detail = None substituído por detail = {} nas funções
migrate_journal e migrate_issue, garantindo tipo consistente mesmo antes
da atribuição completa do dicionário.
…uplicadas a Institution.get_or_create

Motivação: publisher, owner e sponsor eram processados em três blocos
independentes, cada um chamando Institution.get_or_create para o mesmo
nome de instituição quando ela aparecia em mais de um papel (ex.: mesma
instituição como owner e publisher), gerando queries redundantes e risco
de inconsistência entre as três criações.

Técnico:
- Novo set institution_names coleta nomes únicos de publisher/owner/sponsor
  antes de qualquer criação.
- Dict institutions = {nome: Institution.get_or_create(...)} criado uma
  única vez por nome.
- Os três loops de associação (publisher/owner/sponsor) agora buscam a
  instituição já criada em institutions.get(item['name']), com
  'continue' se não encontrada.
- add_related_journal: previous_journal_title e next_journal_title agora
  tratam o caso do resultado vir como dict (result.get(...) pode retornar
  um dict aninhado em vez de string), extraindo o valor correto com
  isinstance(x, dict) antes de passar ao método.
…explicitamente sem token

Propósito: a verificação de site desabilitado (self.enabled) ocorria em
post_data, mas get_token podia ser chamado antes disso (ou de forma
independente) sem essa checagem; além disso, get_token_url ausente ou
token vazio retornado pela API falhavam silenciosamente (return None),
mascarando erros de configuração e causando falhas posteriores difíceis
de diagnosticar em post_data.

Solução técnica: removida a checagem de self.enabled de post_data e
movida para o início de get_token, garantindo que a validação ocorra
antes de qualquer tentativa de autenticação; get_token_url ausente agora
levanta ValueError explícito em vez de retornar silenciosamente; após
obter o token, é validado que resp.get('token') não é vazio, levantando
Exception com get_token_url, username e resposta completa caso a API
não retorne um token válido.

@pitangainnovare pitangainnovare left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Há trechos que podem (avalie) ser beneficiados com o uso de .get().

Comment on lines -23 to +24
issn_electronic=journal.issn_print,
issn_print=journal.issn_electronic,
issn_electronic=journal.issn_electronic,
issn_print=journal.issn_print,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:)

Comment thread proc/source_core_api.py

# Processa publishers
institution_names = set()
for item in result.get("publisher") or []:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

é garantido que result.get("publisher") sempre retorna um iterável?

Comment thread proc/source_core_api.py
Comment on lines +367 to 372
next_jt = result.get("next_journal_title")
prev_jt = result.get("previous_journal_title")
official_journal.add_related_journal(
result.get("previous_journal_title"),
result.get("next_journal_title"),
prev_jt.get("previous_journal_title") if isinstance(prev_jt, dict) else prev_jt,
next_jt.get("next_journal_title") if isinstance(next_jt, dict) else next_jt,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

poderia usar um helper como:

def extract_title(value, key):
    return value.get(key) if isinstance(value, dict) else value

official_journal.add_related_journal(
    extract_title(result.get("previous_journal_title"), "previous_journal_title"),
    extract_title(result.get("next_journal_title"), "next_journal_title"),
)

Comment thread proc/source_core_api.py
for item in result.get("publisher") or []:
institution = Institution.get_or_create(
inst_name=item["name"],
institution_names.add(item["name"])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

não seria mais seguro usar item.get("name") or ""

Comment thread proc/source_core_api.py

# Processa owners
for item in result.get("owner") or []:
institution_names.add(item["name"])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

não seria mais seguro usar item.get("name") or ""

Comment thread proc/source_core_api.py
institution_names.add(item["name"])

for item in result.get("sponsor") or []:
institution_names.add(item["name"])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

não seria mais seguro usar item.get("name") or ""

Comment thread proc/source_core_api.py

# Processa publishers
for item in result.get("publisher") or []:
institution = institutions.get(item["name"])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

não seria mais seguro usar item.get("name") or ""

Comment thread proc/source_core_api.py
location=None,
user=user,
)
institution = institutions.get(item["name"])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

não seria mais seguro usar item.get("name") or ""

Comment thread proc/source_core_api.py
location=None,
user=user,
)
institution = institutions.get(item["name"])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

não seria mais seguro usar item.get("name") or ""

@robertatakenaka
robertatakenaka merged commit f935eec into scieloorg:main Aug 6, 2026
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.

Correções e refatorações em i18n, Institution/Journal, Publication API e Proc (scms-upload v2.x)

2 participants