From b09a0da9721a977b4b28081f4dc07c6e461fb721 Mon Sep 17 00:00:00 2001 From: Rossi-Luciano Date: Wed, 1 Apr 2026 11:01:37 -0300 Subject: [PATCH 1/4] fix(compile): fix OAI-PMH record template for AGRIS AP compliance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dc:description: {{ abs }} chamava __str__ de DocumentAbstract, retornando "[None | en] Abstract..." em vez do texto puro. Corrigido para {{ abs.plain_text }} com sub-elemento 'abstract' e wrapper conforme estrutura esperada pelo crosswalk. - dc:date: object.updated (timestamp de modificação Django) era emitido como data de publicação. Corrigido para object.pub_date sob sub-elemento 'issued', alinhado com dc.date.issued do crosswalk. - dc:identifier: todos os identificadores estavam sob 'none', impedindo o crosswalk de qualificá-los por tipo. Reestruturado com sub-elementos nomeados: 'doi' e 'uri'. Identificadores internos (pid_v2, pid_v3) mantidos em 'none'. - dc:rights: object.license é ForeignKey, não M2M. A chamada .all() nunca executava, resultando em dc:rights sempre vazio. Corrigido para acesso direto via object.license.url. - dc:source: object.source retornava vazio para a maioria dos registros. Substituído por construção explícita a partir de object.journal.title e object.pub_date_year. - dc:relation: adicionado via journal.title para indicar o periódico de origem do artigo, conforme recomendação AGRIS AP. - dc:contributor.author: estrutura alterada de dc.creator.none para dc.contributor.author, alinhada com o crosswalk. Nome do autor emitido no formato "Sobrenome, Nome" usando last_name e given_names do modelo ContribPerson. Mantém fallback para person.names quando last_name não está disponível. Ref: AGRIS AP — seção 4.2 Creator https://www.fao.org/4/ae909e/ae909e05.htm Ref: AGRIS AP — seção 4.6 Description Ref: AGRIS AP — seção 4.7 Date Ref: AGRIS AP — seção 4.8 Identifier Ref: AGRIS AP — seção 4.11 Rights Ref: AGRIS AP — seção 4.13 Source --- .../indexes/article/article_compile.txt | 160 +++++++++++------- 1 file changed, 99 insertions(+), 61 deletions(-) diff --git a/article/templates/search/indexes/article/article_compile.txt b/article/templates/search/indexes/article/article_compile.txt index 34c9cacf..adb22eec 100644 --- a/article/templates/search/indexes/article/article_compile.txt +++ b/article/templates/search/indexes/article/article_compile.txt @@ -10,20 +10,23 @@ {% for title in object.titles.all %} {{ title.plain_text }} - {% endfor%} + {% endfor %} - - + + + + {% for person in object.contrib_persons.all %} - {% if person.orcid %} - {{person.names}} - {% else %} - {{person.names}} + {% if person.last_name %} + {{ person.last_name }}{% if person.suffix %} {{ person.suffix }}{% endif %}{% if person.given_names %}, {{ person.given_names }}{% endif %} + {% elif person.names %} + {{ person.names }} {% endif %} {% endfor %} + {% for kwd in object.keywords.all %} @@ -31,74 +34,110 @@ {% endfor %} + + - + {% for abs in object.abstracts.all %} - {{ abs }} + + {{ abs.plain_text }} + {% endfor %} - - - - {{ object.updated|date:"c" }} - - - - - {{ object.article_type }} - - - - - {% for doi in object.doi.all %} - {{ doi.value }} - {% endfor %} + + + + + {{ object.pub_date }} + + + + + + + {{ object.article_type }} + + + + + + {{ object.pid_v2 }} {{ object.pid_v3 }} - + + {% for doi in object.doi.all %} + + + {{ doi.value }} + + + {% endfor %} + {% for collection in object.collections %} {% for lang in object.languages.all %} - http://{{collection.domain}}/scielo.php?script=sci_arttext&pid={{object.pid_v2}}&tlng={{lang.code2}} + + https://{{ collection.domain }}/scielo.php?script=sci_arttext&pid={{ object.pid_v2 }}&tlng={{ lang.code2 }} + {% endfor %} {% endfor %} - - - - - - {% for lang in object.languages.all %} - {{ lang.code2 }} - {% endfor %} - - - - - {% for lic in object.license.all %} - {{ lic }} - {% endfor %} - - - - - {{ object.source }} - - - - - + + + + + + {% for lang in object.languages.all %} + + {{ lang.code2 }} + + {% endfor %} + + + + + + + {% if object.license and object.license.url %} + {{ object.license.url }} + {% endif %} + + + + + + + {% if object.journal %} + {{ object.journal.title }}{% if object.pub_date_year %}, {{ object.pub_date_year }}{% endif %} + {% endif %} + + + + + {% for publisher_name in object.publisher_names %} - {{ publisher_name }} + {{ publisher_name }} {% endfor %} - - - - - text/html - - + + + + + + text/html + + + + + + + {% if object.journal %} + {{ object.journal.title }} + {% endif %} + + + + @@ -111,4 +150,3 @@ - From 959b4ca77220c4a66d0918868d6ad08af1c7835a Mon Sep 17 00:00:00 2001 From: Rossi-Luciano Date: Wed, 1 Apr 2026 11:02:20 -0300 Subject: [PATCH 2/4] fix(search_indexes): fix prepare_license and prepare_creator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit prepare_license: retornava o código interno "CC BY 4.0" em vez da URL da licença Creative Commons. Refatorado para usar License.url, que reconstrói a URL correta a partir do license_type. prepare_creator: retornava person.names (nome completo sem inversão, em caixa alta). O AGRIS AP exige o formato "Sobrenome, Nome" para autores pessoais. Corrigido para construir o nome a partir dos campos separados last_name, given_names e suffix do modelo ContribPerson. Mantém fallback para person.names quando last_name não está disponível. Ref: AGRIS AP — seção 4.2 Creator https://www.fao.org/4/ae909e/ae909e05.htm Ref: AGRIS AP — seção 4.11 Rights --- article/search_indexes.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/article/search_indexes.py b/article/search_indexes.py index c14cb2a8..e06bb475 100644 --- a/article/search_indexes.py +++ b/article/search_indexes.py @@ -447,13 +447,18 @@ def prepare_titles(self, obj): return set([title.plain_text for title in obj.titles.all()]) def prepare_creator(self, obj): - """The list of authors is the contrib_persons on the models.""" - if obj.contrib_persons.exists(): - return set([ - person.names - for person in obj.contrib_persons.all() - if person.names - ]) + if not obj.contrib_persons.exists(): + return None + result = set() + for person in obj.contrib_persons.all(): + if person.last_name: + suffix = f" {person.suffix}" if person.suffix else "" + given = f", {person.given_names}" if person.given_names else "" + result.add(f"{person.last_name}{suffix}{given}") + elif person.names: + # fallback: nome completo sem inversão + result.add(person.names) + return result or None def prepare_collab(self, obj): """This is the instituional author.""" @@ -519,8 +524,9 @@ def prepare_identifier(self, obj): return idents def prepare_license(self, obj): - if obj.license and obj.license.license_type: - return [obj.license.license_type] + if obj.license and obj.license.url: + return [obj.license.url] + return None def prepare_sources(self, obj): # property no article. @@ -534,5 +540,6 @@ def get_model(self): return Article def index_queryset(self, using=None): - return self.get_model().objects.filter(is_classic_public=True) + # return self.get_model().objects.filter(is_classic_public=True) + return self.get_model().objects.all() From adc426f0ea0afcb164469f635d297041720adc1e Mon Sep 17 00:00:00 2001 From: Rossi-Luciano Date: Wed, 1 Apr 2026 11:03:01 -0300 Subject: [PATCH 3/4] fix(models): fix License.url to correctly reconstruct CC license URL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A property License.url existia mas gerava URLs inválidas porque usava license_type ("CC BY 4.0") diretamente no path da URL. O campo license_type segue o formato "CC {CODE} {VERSION}" com version=None (ex.: "CC BY 4.0", "CC BY-NC 4.0", "CC BY-SA 4.0"). Corrigido para parsear o formato e reconstruir a URL: "CC BY 4.0" → https://creativecommons.org/licenses/by/4.0/ "CC BY-NC 4.0" → https://creativecommons.org/licenses/by-nc/4.0/ "CC BY-SA 4.0" → https://creativecommons.org/licenses/by-sa/4.0/ --- core/models.py | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/core/models.py b/core/models.py index cbefb5bc..2f7dc6ac 100755 --- a/core/models.py +++ b/core/models.py @@ -399,7 +399,7 @@ def get_or_create( institution=institution, user=user, ) - + @classmethod def create(cls, raw_text, initial_date=None, final_date=None, user=None, institution=None): history = cls() @@ -446,7 +446,7 @@ def data(self): class OrganizationNameMixin(models.Model): """ Mixin that provides organization name and acronym fields. - + Fields: name: The organization's full name acronym: The organization's acronym @@ -483,7 +483,7 @@ def __str__(self): class VisualIdentityMixin(models.Model): """ Mixin that provides visual identity fields for organizations. - + Fields: logo: The organization's logo image url: The organization's website URL @@ -645,10 +645,18 @@ def create_or_update(cls, user, license_type=None, version=None): return cls.get(license_type=license_type, version=version) except cls.DoesNotExist: return cls.create(user, license_type, version) - + @property def url(self): - return f"https://creativecommons.org/licenses/{self.license_type}/{self.version or '4.0'}/" + """Reconstrói a URL CC a partir do license_type no formato 'CC {CODE} {VERSION}'""" + if not self.license_type: + return None + parts = self.license_type.split() + if len(parts) == 3 and parts[0].upper() == "CC": + code = parts[1].lower() # "BY" → "by", "BY-NC" → "by-nc" + version = parts[2] # "4.0" + return f"https://creativecommons.org/licenses/{code}/{version}/" + return None @property def data(self): @@ -743,7 +751,7 @@ def create_or_update(cls, user, license, language=None, url=None, license_p=None def parse_url(url): """ Parse Creative Commons license URL. - + Exemplos de URLs: - https://creativecommons.org/licenses/by/4.0/ - https://creativecommons.org/licenses/by-nc/3.0/br/ @@ -754,32 +762,32 @@ def parse_url(url): url = url.lower().rstrip("/") url_parts = [p for p in url.split("/") if p] - + if not url_parts: return {} license_types = dict(choices.LICENSE_TYPES) - + for i, part in enumerate(url_parts): if part not in license_types: continue - + license_type = part remaining = url_parts[i + 1:] license_version = None license_language = None - + if remaining: version_candidate = remaining[0] if all(c.isdigit() or c == "." for c in version_candidate): license_version = version_candidate remaining = remaining[1:] - + if remaining: lang_candidate = remaining[0] if lang_candidate.isalpha() and 2 <= len(lang_candidate) <= 3: license_language = lang_candidate - + return { "license_type": license_type, "license_version": license_version, @@ -853,7 +861,7 @@ def initial_date_isoformat(self): if self.initial_date: return self.initial_date.isoformat() return None - + @property def final_date_isoformat(self): if self.final_date: @@ -1305,7 +1313,7 @@ def create(cls, pid, collection, data=None, user=None, url=None, processing_date obj.creator = user obj.save() return obj - + @classmethod def create_or_update(cls, pid, collection, data=None, user=None, url=None, status=None, processing_date=None, force_update=None, new_record=None): try: From 261d19694013c1455c1a778789eea7a36fb72798 Mon Sep 17 00:00:00 2001 From: Rossi-Luciano Date: Wed, 1 Apr 2026 11:05:31 -0300 Subject: [PATCH 4/4] Habilita o filtro --- article/search_indexes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/article/search_indexes.py b/article/search_indexes.py index e06bb475..20e7261a 100644 --- a/article/search_indexes.py +++ b/article/search_indexes.py @@ -540,6 +540,6 @@ def get_model(self): return Article def index_queryset(self, using=None): - # return self.get_model().objects.filter(is_classic_public=True) - return self.get_model().objects.all() + return self.get_model().objects.filter(is_classic_public=True) + # return self.get_model().objects.all()