Corrige questões do fluxo de journal: coleta de dados do core e publicação no site qa ou público - #1047
Conversation
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
left a comment
There was a problem hiding this comment.
Há trechos que podem (avalie) ser beneficiados com o uso de .get().
| issn_electronic=journal.issn_print, | ||
| issn_print=journal.issn_electronic, | ||
| issn_electronic=journal.issn_electronic, | ||
| issn_print=journal.issn_print, |
|
|
||
| # Processa publishers | ||
| institution_names = set() | ||
| for item in result.get("publisher") or []: |
There was a problem hiding this comment.
é garantido que result.get("publisher") sempre retorna um iterável?
| 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, | ||
| ) |
There was a problem hiding this comment.
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"),
)| for item in result.get("publisher") or []: | ||
| institution = Institution.get_or_create( | ||
| inst_name=item["name"], | ||
| institution_names.add(item["name"]) |
There was a problem hiding this comment.
não seria mais seguro usar item.get("name") or ""
|
|
||
| # Processa owners | ||
| for item in result.get("owner") or []: | ||
| institution_names.add(item["name"]) |
There was a problem hiding this comment.
não seria mais seguro usar item.get("name") or ""
| institution_names.add(item["name"]) | ||
|
|
||
| for item in result.get("sponsor") or []: | ||
| institution_names.add(item["name"]) |
There was a problem hiding this comment.
não seria mais seguro usar item.get("name") or ""
|
|
||
| # Processa publishers | ||
| for item in result.get("publisher") or []: | ||
| institution = institutions.get(item["name"]) |
There was a problem hiding this comment.
não seria mais seguro usar item.get("name") or ""
| location=None, | ||
| user=user, | ||
| ) | ||
| institution = institutions.get(item["name"]) |
There was a problem hiding this comment.
não seria mais seguro usar item.get("name") or ""
| location=None, | ||
| user=user, | ||
| ) | ||
| institution = institutions.get(item["name"]) |
There was a problem hiding this comment.
não seria mais seguro usar item.get("name") or ""
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 empublication/utils/journal.py, corrige a inicialização dedetailem caminhos de exceção deproc/source_classic_website.py, consolida a criação de instituições emproc/source_core_api.py(evitando chamadas duplicadas aInstitution.get_or_createquando a mesma instituição aparece como owner/publisher/sponsor) e trata o caso deprevious_journal_title/next_journal_titleretornarem comodictaninhado. 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 desearch_fieldsdo Institution e aumenta omax_lengthdenext_journal_title.Onde a revisão poderia começar?
publication/api/journal.py, funçãopublish_journal— é onde está o bug de maior impacto (troca de ISSN). Em seguida,proc/source_core_api.pypara a consolidação da criação de instituições.Como este poderia ser testado manualmente?
OfficialJournalcomnext_journal_titleacima de 128 caracteres.source_core_apium journal cuja mesma instituição apareça como owner e publisher; confirmar (via logs/queries) queInstitution.get_or_createé chamado apenas uma vez para esse nome.detailemmigrate_journal/migrate_issuee confirmar queevent.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-uploadv3.x. Os bugs de ISSN trocado e payload com campos vazios têm impacto direto no website (dados publicados incorretamente), enquanto a consolidação emsource_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)
Este PR manipula dados sensíveis ou pessoais (LGPD)?
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?
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?
Institution.get_or_create), sem concatenação manual de SQL; não há execução de HTML/JS dinâmico a partir dessa entrada.Este PR expõe novos endpoints, telas ou serviços?
Algum segredo, senha, chave ou token está sendo adicionado ao código-fonte?