From 55ce27d74a021e514ff081f1a074f37d69f13cca Mon Sep 17 00:00:00 2001 From: GitInno <86991526+gitnnolabs@users.noreply.github.com> Date: Thu, 30 Apr 2026 08:01:14 -0300 Subject: [PATCH 1/7] =?UTF-8?q?Garante=20as=20URL=20em=20arquivo=20de=20co?= =?UTF-8?q?nfigura=C3=A7=C3=A3o=20e=20com=20envs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/settings/base.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/config/settings/base.py b/config/settings/base.py index 1e70c7a..f15b604 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -301,5 +301,18 @@ LLAMA_ENABLED = env.bool("LLAMA_ENABLED", default=True) MODEL_LLAMA = "llama-3.2-3b-instruct-q4_k_m.gguf" +# Core API +CORE_API_DOMAIN = env("CORE_API_DOMAIN", default="https://core.scielo.org") +CORE_COLLECTION_API_ENDPOINT = env( + "CORE_COLLECTION_API_ENDPOINT", + default="/api/v2/pid/collection/", +) +CORE_JOURNAL_API_ENDPOINT = env( + "CORE_JOURNAL_API_ENDPOINT", + default="/api/v2/pid/journal/", +) +CORE_COLLECTION_API_URL = f"{CORE_API_DOMAIN}{CORE_COLLECTION_API_ENDPOINT}" +CORE_JOURNAL_API_URL = f"{CORE_API_DOMAIN}{CORE_JOURNAL_API_ENDPOINT}" + #Aumento en el límite de campos DATA_UPLOAD_MAX_NUMBER_FIELDS = 10000 \ No newline at end of file From 8676339df6ab8f1573998ffd7baf895a2a161711 Mon Sep 17 00:00:00 2001 From: GitInno <86991526+gitnnolabs@users.noreply.github.com> Date: Thu, 30 Apr 2026 08:01:49 -0300 Subject: [PATCH 2/7] Ajusta os choices para utilizar aspas. --- markup_doc/choices.py | 176 ++++++++++++++++-------------------------- 1 file changed, 65 insertions(+), 111 deletions(-) diff --git a/markup_doc/choices.py b/markup_doc/choices.py index d113911..8ebae82 100644 --- a/markup_doc/choices.py +++ b/markup_doc/choices.py @@ -1,121 +1,75 @@ front_labels = [ - ('', ''), - ('', ''), - ('', ''), - ('', ''), - ('', ''), - ('', ''), - ('', ''), - ('', ''), - ('', ''), - ('', ''), - ('', ''), - ('', ''), - ('', ''), - ('', ''), - ('', ''), - ('

', '

'), - ('', ''), - ('', ''), - ('', ''), - ('', '
'), - ('', ''), - ('', '<title>'), - ('<trans-abstract>', '<trans-abstract>'), - ('<trans-title>', '<trans-title>'), - ('<translate-front>', '<translate-front>'), - ('<translate-body>', '<translate-body>'), - ('<disp-formula>', '<disp-formula>'), - ('<inline-formula>', '<inline-formula>'), - ('<formula>', '<formula>'), - + ("<abstract>", "<abstract>"), + ("<abstract-title>", "<abstract-title>"), + ("<aff>", "<aff>"), + ("<article-id>", "<article-id>"), + ("<article-title>", "<article-title>"), + ("<author-notes>", "<author-notes>"), + ("<contrib>", "<contrib>"), + ("<date-accepted>", "<date-accepted>"), + ("<date-received>", "<date-received>"), + ("<fig>", "<fig>"), + ("<fig-attrib>", "<fig-attrib>"), + ("<history>", "<history>"), + ("<kwd-title>", "<kwd-title>"), + ("<kwd-group>", "<kwd-group>"), + ("<list>", "<list>"), + ("<p>", "<p>"), + ("<sec>", "<sec>"), + ("<sub-sec>", "<sub-sec>"), + ("<subject>", "<subject>"), + ("<table>", "<table>"), + ("<table-foot>", "<table-foot>"), + ("<title>", "<title>"), + ("<trans-abstract>", "<trans-abstract>"), + ("<trans-title>", "<trans-title>"), + ("<translate-front>", "<translate-front>"), + ("<translate-body>", "<translate-body>"), + ("<disp-formula>", "<disp-formula>"), + ("<inline-formula>", "<inline-formula>"), + ("<formula>", "<formula>"), ] order_labels = { - '<article-id>':{ - 'pos' : 1, - 'next' : '<subject>' - }, - '<subject>':{ - 'pos' : 2, - 'next' : '<article-title>' - }, - '<article-title>':{ - 'pos' : 3, - 'next' : '<trans-title>', - 'lan' : True - }, - '<trans-title>':{ - 'size' : 14, - 'bold' : True, - 'lan' : True, - 'next' : '<contrib>' - }, - '<contrib>':{ - 'reset' : True, - 'size' : 12, - 'next' : '<aff>' - }, - '<aff>':{ - 'reset' : True, - 'size' : 12, - }, - '<abstract>':{ - 'size' : 12, - 'bold' : True, - 'lan' : True, - 'next' : '<p>' - }, - '<p>':{ - 'size' : 12, - 'next' : '<p>', - 'repeat' : True - }, - '<trans-abstract>':{ - 'size' : 12, - 'bold' : True, - 'lan' : True, - 'next' : '<p>' - }, - '<kwd-group>':{ - 'size' : 12, - 'regex' : r'(?i)(palabra.*clave.*:|keyword.*:)', - }, - '<history>':{ - 'size' : 12, - 'regex' : r'\d{2}/\d{2}/\d{4}', - }, - '<corresp>':{ - 'size' : 12, - 'regex' : r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' - }, - '<sec>':{ - 'size' : 16, - 'bold' : True, - 'next' : None - }, - '<sub-sec>':{ - 'size' : 12, - 'italic' : True, - 'next' : None - }, - '<sub-sec-2>':{ - 'size' : 14, - 'bold' : True, - 'next' : None - }, + "<article-id>": {"pos": 1, "next": "<subject>"}, + "<subject>": {"pos": 2, "next": "<article-title>"}, + "<article-title>": {"pos": 3, "next": "<trans-title>", "lan": True}, + "<trans-title>": {"size": 14, "bold": True, "lan": True, "next": "<contrib>"}, + "<contrib>": {"reset": True, "size": 12, "next": "<aff>"}, + "<aff>": { + "reset": True, + "size": 12, + }, + "<abstract>": {"size": 12, "bold": True, "lan": True, "next": "<p>"}, + "<p>": {"size": 12, "next": "<p>", "repeat": True}, + "<trans-abstract>": {"size": 12, "bold": True, "lan": True, "next": "<p>"}, + "<kwd-group>": { + "size": 12, + "regex": r"(?i)(palabra.*clave.*:|keyword.*:)", + }, + "<history>": { + "size": 12, + "regex": r"\d{2}/\d{2}/\d{4}", + }, + "<corresp>": { + "size": 12, + "regex": r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", + }, + "<sec>": {"size": 16, "bold": True, "next": None}, + "<sub-sec>": {"size": 12, "italic": True, "next": None}, + "<sub-sec-2>": {"size": 14, "bold": True, "next": None}, } order_labels_body = { - '<sec>':{ - 'size' : 16, - 'bold' : True, + "<sec>": { + "size": 16, + "bold": True, }, - '<sub-sec>':{ - 'size' : 12, - 'italic' : True, + "<sub-sec>": { + "size": 12, + "italic": True, }, - '<p>':{ - 'size' : 12, + "<p>": { + "size": 12, }, -} \ No newline at end of file +} From 16cd7acf5cbcdf96ff418013bd09d5f5863a9a29 Mon Sep 17 00:00:00 2001 From: GitInno <86991526+gitnnolabs@users.noreply.github.com> Date: Thu, 30 Apr 2026 08:02:07 -0300 Subject: [PATCH 3/7] =?UTF-8?q?Remove=20imports=20desnecess=C3=A1rio.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- markup_doc/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/markup_doc/forms.py b/markup_doc/forms.py index e8abe2e..8b13789 100644 --- a/markup_doc/forms.py +++ b/markup_doc/forms.py @@ -1 +1 @@ -from wagtail.admin.forms.models import WagtailAdminModelForm + From bb356013c904890ad85f1f9e58538ae4547103ec Mon Sep 17 00:00:00 2001 From: GitInno <86991526+gitnnolabs@users.noreply.github.com> Date: Thu, 30 Apr 2026 08:02:31 -0300 Subject: [PATCH 4/7] Aplica o black. --- ...0002_alter_articledocx_estatus_and_more.py | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/markup_doc/migrations/0002_alter_articledocx_estatus_and_more.py b/markup_doc/migrations/0002_alter_articledocx_estatus_and_more.py index 600fba0..7ab4524 100644 --- a/markup_doc/migrations/0002_alter_articledocx_estatus_and_more.py +++ b/markup_doc/migrations/0002_alter_articledocx_estatus_and_more.py @@ -6,18 +6,28 @@ class Migration(migrations.Migration): dependencies = [ - ('markup_doc', '0001_initial'), + ("markup_doc", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='articledocx', - name='estatus', - field=models.IntegerField(blank=True, choices=[(1, 'Processing'), (2, 'Processed')], default=1, verbose_name='Process estatus'), + model_name="articledocx", + name="estatus", + field=models.IntegerField( + blank=True, + choices=[(1, "Processing"), (2, "Processed")], + default=1, + verbose_name="Process estatus", + ), ), migrations.AlterField( - model_name='articledocxmarkup', - name='estatus', - field=models.IntegerField(blank=True, choices=[(1, 'Processing'), (2, 'Processed')], default=1, verbose_name='Process estatus'), + model_name="articledocxmarkup", + name="estatus", + field=models.IntegerField( + blank=True, + choices=[(1, "Processing"), (2, "Processed")], + default=1, + verbose_name="Process estatus", + ), ), ] From 12d4f13b7fb8cea1d01f7fa13a34e6eaf4e9617e Mon Sep 17 00:00:00 2001 From: GitInno <86991526+gitnnolabs@users.noreply.github.com> Date: Thu, 30 Apr 2026 08:05:09 -0300 Subject: [PATCH 5/7] =?UTF-8?q?Aplica=20black,=20remove=20imports=20denece?= =?UTF-8?q?ss=C3=A1rio,=20garante=20que=20os=20=5F=5Fstr=5F=5F=20n=C3=A3o?= =?UTF-8?q?=20tenha=20gere=20erro,=20remove=20o=20doi=20do=20classmethod?= =?UTF-8?q?=20ArticleDocxMarkup.create?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- markup_doc/models.py | 312 +++++++++++++++++++------------------------ 1 file changed, 141 insertions(+), 171 deletions(-) diff --git a/markup_doc/models.py b/markup_doc/models.py index bfd4722..a7e4ab5 100644 --- a/markup_doc/models.py +++ b/markup_doc/models.py @@ -1,29 +1,19 @@ -import os -import sys -import requests - -from django.db import models -from django.utils.translation import gettext_lazy as _ from django import forms -from django.utils.html import format_html +from django.db import models from django.urls import reverse - -from modelcluster.fields import ParentalKey +from django.utils.html import format_html +from django.utils.translation import gettext_lazy as _ from modelcluster.models import ClusterableModel -from wagtail.admin.panels import FieldPanel, InlinePanel, ObjectList, TabbedInterface +from wagtail.admin.panels import FieldPanel, ObjectList, TabbedInterface +from wagtail.blocks import ChoiceBlock, StreamBlock, StructBlock, TextBlock +from wagtail.fields import StreamField +from wagtail.images.blocks import ImageChooserBlock from wagtailautocomplete.edit_handlers import AutocompletePanel -from wagtail.documents.models import Document -from core.forms import CoreAdminModelForm from core.choices import LANGUAGE -from core.models import ( - CommonControlField, - Language, - TextWithLang -) -from wagtail.fields import StreamField -from wagtail.blocks import StructBlock, TextBlock, CharBlock, ChoiceBlock, ListBlock, StreamBlock -from wagtail.images.blocks import ImageChooserBlock +from core.forms import CoreAdminModelForm +from core.models import CommonControlField + from .choices import front_labels @@ -36,26 +26,28 @@ class ReadOnlyFileWidget(forms.Widget): def render(self, name, value, attrs=None, renderer=None): if value: # Muestra el archivo como un enlace de descarga - #return format_html('<a href="{}" target="_blank" download>{}</a>', value.url, value.name.split('/')[-1]) + # return format_html('<a href="{}" target="_blank" download>{}</a>', value.url, value.name.split('/')[-1]) instance = value.instance - url = reverse('generate_xml', args=[instance.pk]) - return format_html('<a href="{}" target="_blank" download>Download XML</a>', url) + url = reverse("generate_xml", args=[instance.pk]) + return format_html( + '<a href="{}" target="_blank" download>Download XML</a>', url + ) return "" -# Create your models here. + class ArticleDocx(CommonControlField): title = models.TextField(_("Document Title"), null=True, blank=True) file = models.FileField( null=True, blank=True, verbose_name=_("Document"), - upload_to='uploads_docx/', + upload_to="uploads_docx/", ) estatus = models.IntegerField( _("Process estatus"), choices=ProcessStatus.choices, blank=True, - default=ProcessStatus.PROCESSING + default=ProcessStatus.PROCESSING, ) panels = [ @@ -69,12 +61,11 @@ def __unicode__(self): return f"{self.title} | {self.estatus}" def __str__(self): - return f"{self.title} | {self.estatus}" + title = self.title or "" + return f"{title} | {self.estatus}" @classmethod - def get( - cls, - title): + def get(cls, title): return cls.objects.get(title=title) @classmethod @@ -90,16 +81,8 @@ def update(cls, title, estatus): class ParagraphWithLanguageBlock(StructBlock): - label = ChoiceBlock( - choices=front_labels, - required=False, - label=_("Label") - ) - language = ChoiceBlock( - choices=LANGUAGE, - required=False, - label="Language" - ) + label = ChoiceBlock(choices=front_labels, required=False, label=_("Label")) + language = ChoiceBlock(choices=LANGUAGE, required=False, label="Language") paragraph = TextBlock(required=False, label=_("Title")) class Meta: @@ -107,11 +90,7 @@ class Meta: class ParagraphBlock(StructBlock): - label = ChoiceBlock( - choices=front_labels, - required=False, - label=_("Label") - ) + label = ChoiceBlock(choices=front_labels, required=False, label=_("Label")) paragraph = TextBlock(required=False, label=_("Paragraph")) class Meta: @@ -119,27 +98,23 @@ class Meta: class CompoundParagraphBlock(StructBlock): - label = ChoiceBlock( - choices=front_labels, - required=False, - label=_("Label") - ) + label = ChoiceBlock(choices=front_labels, required=False, label=_("Label")) eid = TextBlock(required=False, label=_("Equation id")) - content = StreamBlock([ - ('text', TextBlock(label=_("Text"))), - ('formula', TextBlock(label=_("Formula"))), - ], label=_("Content"), required=True) + content = StreamBlock( + [ + ("text", TextBlock(label=_("Text"))), + ("formula", TextBlock(label=_("Formula"))), + ], + label=_("Content"), + required=True, + ) class Meta: label = _("Compound paragraph") class ImageBlock(StructBlock): - label = ChoiceBlock( - choices=front_labels, - required=False, - label=_("Label") - ) + label = ChoiceBlock(choices=front_labels, required=False, label=_("Label")) figid = TextBlock(required=False, label=_("Fig id")) figlabel = TextBlock(required=False, label=_("Fig label")) title = TextBlock(required=False, label=_("Title")) @@ -151,11 +126,7 @@ class Meta: class TableBlock(StructBlock): - label = ChoiceBlock( - choices=front_labels, - required=False, - label=_("Label") - ) + label = ChoiceBlock(choices=front_labels, required=False, label=_("Label")) tabid = TextBlock(required=False, label=_("Table id")) tablabel = TextBlock(required=False, label=_("Table label")) title = TextBlock(required=False, label=_("Title")) @@ -202,10 +173,14 @@ class RefNameBlock(StructBlock): class RefParagraphBlock(ParagraphBlock): reftype = TextBlock(required=False, label=_("Ref type")) refid = TextBlock(required=False, label=_("Ref id")) - #authors = ListBlock(RefNameBlock(), label=_("Authors")) - authors = StreamBlock([ - ('Author', RefNameBlock()), - ], label=_("Authors"), required=False) + # authors = ListBlock(RefNameBlock(), label=_("Authors")) + authors = StreamBlock( + [ + ("Author", RefNameBlock()), + ], + label=_("Authors"), + required=False, + ) date = TextBlock(required=False, label=_("Date")) title = TextBlock(required=False, label=_("Title")) chapter = TextBlock(required=False, label=_("Chapter")) @@ -245,7 +220,9 @@ def __str__(self): class CollectionModel(models.Model): - collection = models.ForeignKey(CollectionValuesModel, null=True, blank=True, on_delete=models.SET_NULL) + collection = models.ForeignKey( + CollectionValuesModel, null=True, blank=True, on_delete=models.SET_NULL + ) autocomplete_search_field = "collection.acron" @@ -253,11 +230,14 @@ def autocomplete_label(self): return str(self) panels = [ - AutocompletePanel('collection'), + AutocompletePanel("collection"), ] def __str__(self): - return f"{self.collection.acron.upper()} - {self.collection.acron}" + if not self.collection: + return "" + acron = self.collection.acron or "" + return f"{acron.upper()} - {acron}" class JournalModel(models.Model): @@ -273,21 +253,21 @@ class JournalModel(models.Model): autocomplete_search_field = "title" class Meta: - unique_together = ('title',) + unique_together = ("title",) def autocomplete_label(self): return str(self) def __str__(self): - return self.title + return self.title or "" def get_default_collection_acron(): try: - obj = CollectionModel.objects.select_related('collection').first() - return obj.collection.acron if obj and obj.collection else '' + obj = CollectionModel.objects.select_related("collection").first() + return obj.collection.acron if obj and obj.collection else "" except Exception: - return '' + return "" class ArticleDocxMarkup(CommonControlField, ClusterableModel): @@ -296,17 +276,19 @@ class ArticleDocxMarkup(CommonControlField, ClusterableModel): null=True, blank=True, verbose_name=_("Document"), - upload_to='uploads_docx/', + upload_to="uploads_docx/", ) estatus = models.IntegerField( _("Process estatus"), choices=ProcessStatus.choices, blank=True, - default=ProcessStatus.PROCESSING + default=ProcessStatus.PROCESSING, ) collection = models.CharField(max_length=10, default=get_default_collection_acron) - journal = models.ForeignKey(JournalModel, null=True, blank=True, on_delete=models.SET_NULL) + journal = models.ForeignKey( + JournalModel, null=True, blank=True, on_delete=models.SET_NULL + ) journal_title = models.TextField(_("Journal Title"), null=True, blank=True) acronym = models.TextField(_("Acronym"), null=True, blank=True) @@ -318,31 +300,14 @@ class ArticleDocxMarkup(CommonControlField, ClusterableModel): nimtitle = models.TextField(_("Nimtitle"), null=True, blank=True) pubname = models.TextField(_("Publisher Name"), null=True, blank=True) license = models.URLField( - max_length=500, - blank=True, - null=True, - verbose_name=_("License (URL)") - ) - vol = models.IntegerField( - verbose_name=_("Volume"), - null=True, - blank=True + max_length=500, blank=True, null=True, verbose_name=_("License (URL)") ) + vol = models.IntegerField(verbose_name=_("Volume"), null=True, blank=True) supplvol = models.IntegerField( - verbose_name=_("Suppl Volume"), - null=True, - blank=True - ) - issue = models.IntegerField( - verbose_name=_("Issue"), - null=True, - blank=True - ) - supplno = models.IntegerField( - verbose_name=_("Suppl Num"), - null=True, - blank=True + verbose_name=_("Suppl Volume"), null=True, blank=True ) + issue = models.IntegerField(verbose_name=_("Issue"), null=True, blank=True) + supplno = models.IntegerField(verbose_name=_("Suppl Num"), null=True, blank=True) issid_part = models.TextField(_("Isid Part"), null=True, blank=True) dateiso = models.TextField(_("Dateiso"), null=True, blank=True) month = models.TextField(_("Month/Season"), null=True, blank=True) @@ -354,11 +319,7 @@ class ArticleDocxMarkup(CommonControlField, ClusterableModel): pagcount = models.TextField(_("Pag count"), null=True, blank=True) doctopic = models.TextField(_("Doc Topic"), null=True, blank=True) language = models.CharField( - _("Language"), - max_length=10, - choices=LANGUAGE, - null=True, - blank=True + _("Language"), max_length=10, choices=LANGUAGE, null=True, blank=True ) spsversion = models.TextField(_("Sps version"), null=True, blank=True) artdate = models.DateField(_("Artdate"), null=True, blank=True) @@ -368,60 +329,70 @@ class ArticleDocxMarkup(CommonControlField, ClusterableModel): null=True, blank=True, verbose_name=_("Document xml"), - upload_to='generate_xml/', + upload_to="generate_xml/", ) text_xml = models.TextField(_("Text XML"), null=True, blank=True) - content = StreamField([ - ('paragraph_with_language', ParagraphWithLanguageBlock()), - ('paragraph', ParagraphBlock()), - ('author_paragraph', AuthorParagraphBlock()), - ('aff_paragraph', AffParagraphBlock()), - ], blank=True, use_json_field=True) - - content_body = StreamField([ - ('paragraph', ParagraphBlock()), - ('paragraph_with_language', ParagraphWithLanguageBlock()), - ('compound_paragraph', CompoundParagraphBlock()), - ('image', ImageBlock()), - ('table', TableBlock()), - ], blank=True, use_json_field=True) - - content_back = StreamField([ - ('paragraph', ParagraphBlock()), - ('ref_paragraph', RefParagraphBlock()), - ], blank=True, use_json_field=True) + content = StreamField( + [ + ("paragraph_with_language", ParagraphWithLanguageBlock()), + ("paragraph", ParagraphBlock()), + ("author_paragraph", AuthorParagraphBlock()), + ("aff_paragraph", AffParagraphBlock()), + ], + blank=True, + use_json_field=True, + ) + + content_body = StreamField( + [ + ("paragraph", ParagraphBlock()), + ("paragraph_with_language", ParagraphWithLanguageBlock()), + ("compound_paragraph", CompoundParagraphBlock()), + ("image", ImageBlock()), + ("table", TableBlock()), + ], + blank=True, + use_json_field=True, + ) + + content_back = StreamField( + [ + ("paragraph", ParagraphBlock()), + ("ref_paragraph", RefParagraphBlock()), + ], + blank=True, + use_json_field=True, + ) panels = [ FieldPanel("title"), FieldPanel("file"), FieldPanel("collection"), - AutocompletePanel("journal") + AutocompletePanel("journal"), ] def __unicode__(self): return f"{self.title} | {self.estatus}" def __str__(self): - return f"{self.title} | {self.estatus}" + title = self.title or "" + return f"{title} | {self.estatus}" @property def url_download(self): return self.file_xml.url if self.file_xml else None @classmethod - def create(cls, title, doi): + def create(cls, title): obj = cls() obj.title = title - obj.doi = doi obj.save() return obj @classmethod - def get( - cls, - title): + def get(cls, title): return cls.objects.get(title=title) @classmethod @@ -456,55 +427,54 @@ class Meta: class MarkupXML(ArticleDocxMarkup): panels_front = [ - FieldPanel('content'), - #InlinePanel("element_docx", label=_("Elements Docx")), + FieldPanel("content"), + # InlinePanel("element_docx", label=_("Elements Docx")), ] panels_body = [ - FieldPanel('content_body'), + FieldPanel("content_body"), ] panels_back = [ - FieldPanel('content_back'), + FieldPanel("content_back"), ] panels_xml = [ - FieldPanel('file_xml', widget=ReadOnlyFileWidget()), - FieldPanel('text_xml'), + FieldPanel("file_xml", widget=ReadOnlyFileWidget()), + FieldPanel("text_xml"), ] panels_details = [ - FieldPanel('collection'), - AutocompletePanel('journal'), - FieldPanel('journal_title'), - FieldPanel('short_title'), - FieldPanel('title_nlm'), - FieldPanel('acronym'), - FieldPanel('issn'), - FieldPanel('pissn'), - FieldPanel('eissn'), - FieldPanel('nimtitle'), - FieldPanel('pubname'), - FieldPanel('license'), - FieldPanel('vol'), - FieldPanel('supplvol'), - FieldPanel('issue'), - FieldPanel('supplno'), - FieldPanel('issid_part'), - - FieldPanel('dateiso'), - FieldPanel('month'), - FieldPanel('fpage'), - FieldPanel('seq'), - FieldPanel('lpage'), - FieldPanel('elocatid'), - FieldPanel('order'), - FieldPanel('pagcount'), - FieldPanel('doctopic'), - FieldPanel('language'), - FieldPanel('spsversion'), - FieldPanel('artdate'), - FieldPanel('ahpdate'), + FieldPanel("collection"), + AutocompletePanel("journal"), + FieldPanel("journal_title"), + FieldPanel("short_title"), + FieldPanel("title_nlm"), + FieldPanel("acronym"), + FieldPanel("issn"), + FieldPanel("pissn"), + FieldPanel("eissn"), + FieldPanel("nimtitle"), + FieldPanel("pubname"), + FieldPanel("license"), + FieldPanel("vol"), + FieldPanel("supplvol"), + FieldPanel("issue"), + FieldPanel("supplno"), + FieldPanel("issid_part"), + FieldPanel("dateiso"), + FieldPanel("month"), + FieldPanel("fpage"), + FieldPanel("seq"), + FieldPanel("lpage"), + FieldPanel("elocatid"), + FieldPanel("order"), + FieldPanel("pagcount"), + FieldPanel("doctopic"), + FieldPanel("language"), + FieldPanel("spsversion"), + FieldPanel("artdate"), + FieldPanel("ahpdate"), ] edit_handler = TabbedInterface( @@ -518,4 +488,4 @@ class MarkupXML(ArticleDocxMarkup): ) class Meta: - proxy = True \ No newline at end of file + proxy = True From 6f8c83629ba88a450856610ad5200c7599175709 Mon Sep 17 00:00:00 2001 From: GitInno <86991526+gitnnolabs@users.noreply.github.com> Date: Thu, 30 Apr 2026 08:05:42 -0300 Subject: [PATCH 6/7] =?UTF-8?q?Ajusta=20imports,=20garante=20o=20reuso=20d?= =?UTF-8?q?e=20fun=C3=A7=C3=B5es=20internas=20para=20obter=20dados=20vi=20?= =?UTF-8?q?APIs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- markup_doc/sync_api.py | 185 ++++++++++++++++++----------------------- 1 file changed, 81 insertions(+), 104 deletions(-) diff --git a/markup_doc/sync_api.py b/markup_doc/sync_api.py index 0eb945d..fd34af3 100644 --- a/markup_doc/sync_api.py +++ b/markup_doc/sync_api.py @@ -1,128 +1,105 @@ -import requests +import logging + +from django.conf import settings from django.db import transaction -from markup_doc.models import CollectionValuesModel, JournalModel, CollectionModel + +from core.utils.requester import fetch_data as fetch +from markup_doc.models import CollectionModel, CollectionValuesModel, JournalModel + +logger = logging.getLogger(__name__) + def sync_collection_from_api(): - url = "https://core.scielo.org/api/v2/pid/collection/" + url = settings.CORE_COLLECTION_API_URL all_results = [] while url: - print(url) - response = requests.get(url, headers={"Accept": "application/json"}, timeout=(10, 60)) - data = response.json() - all_results.extend(data['results']) - url = data['next'] - - # Borra todo - print('Borrando...') + logger.info("Syncing collections page: %s", url) + data = fetch( + url, headers={"Accept": "application/json"}, json=True, timeout=(10, 60) + ) + all_results.extend(data["results"]) + url = data["next"] + + logger.info("Deleting existing collection data before sync") CollectionModel.objects.all().delete() - deleted_count, _ = CollectionValuesModel.objects.all().delete() - print('Borrado...') + CollectionValuesModel.objects.all().delete() for item in all_results: - acron = item.get('acron3') - name = item.get('main_name', '').strip() + acron = item.get("acron3") + name = item.get("main_name", "").strip() if acron and name: - print(name) CollectionValuesModel.objects.update_or_create( - acron=acron, - defaults={'name': name} + acron=acron, defaults={"name": name} ) def sync_journals_from_api(): journals = JournalModel.objects.all() if journals.exists(): - deleted_count, _ = journals.delete() + journals.delete() - obj = CollectionModel.objects.select_related('collection').first() + obj = CollectionModel.objects.select_related("collection").first() acron_selected = obj.collection.acron if obj and obj.collection else None + if not acron_selected: + logger.warning("No collection selected; skipping journal sync") + return new_journals = [] - if acron_selected: - - url = "https://core.scielo.org/api/v2/pid/journal/" - retries = 3 - - while url: - try: - response = requests.get(url, headers={"Accept": "application/json"}, timeout=(10, 60)) - response.raise_for_status() - data = response.json() - retries = 3 - - for item in data["results"]: - title = item.get("title", None) - short_title = item.get("short_title", None) - acronym = item.get("acronym", None) - pissn = item.get("official", {}).get("issn_print", None) - eissn = item.get("official", {}).get("issn_electronic", None) - acronym = item.get("acronym", None) - pubname = item.get("publisher", []) - title_in_database = item.get("title_in_database", []) - title_nlm = None - - if title_in_database: - for t in title_in_database: - if t.get("name", None) == 'MEDLINE': - title_nlm = t.get("title", None) - - if pubname: - pubname = pubname[0].get("name", None) - - scielo_journals = item.get("scielo_journal", []) - - # Obtener la primera colección asociada, si existe - collection_acron = None - if scielo_journals: - collection_acron = scielo_journals[0].get("collection_acron") - issn_scielo = scielo_journals[0].get("issn_scielo", None) - - if not title or acron_selected != collection_acron: - continue # Saltar si falta el título - - #collection_instance = None - #if collection_acron: - # collection_instance, _ = CollectionModel.objects.get_or_create( - # acron=collection_acron, - # defaults={'name': collection_acron.upper()} - # ) - - # Crear o actualizar el journal - print(title) - print(item) - journal = JournalModel( - title=title, - short_title=short_title or None, - title_nlm = title_nlm or None, - acronym=acronym or None, - issn=issn_scielo or None, - pissn=pissn or None, - eissn=eissn or None, - pubname=pubname or None, - # collection=collection_instance, - # defaults={} - ) - new_journals.append(journal) - - url = data.get("next") - except requests.exceptions.ChunkedEncodingError as e: - print("ERROR:", e) - retries -= 1 - if retries == 0: - break - continue - except Exception as e: - print("**ERROR url") - print("URL:", url) - print("TIPO:", type(e).__name__) - print("ERROR:", str(e)) - url = None - - # Guardar todo junto - if new_journals: - with transaction.atomic(): - JournalModel.objects.bulk_create(new_journals, ignore_conflicts=True) + url = settings.CORE_JOURNAL_API_URL + while url: + logger.info("Syncing journals page: %s", url) + data = fetch( + url, headers={"Accept": "application/json"}, json=True, timeout=(10, 60) + ) + + for item in data["results"]: + title = item.get("title", None) + short_title = item.get("short_title", None) + acronym = item.get("acronym", None) + pissn = item.get("official", {}).get("issn_print", None) + eissn = item.get("official", {}).get("issn_electronic", None) + acronym = item.get("acronym", None) + pubname = item.get("publisher", []) + title_in_database = item.get("title_in_database", []) + title_nlm = None + + if title_in_database: + for t in title_in_database: + if t.get("name", None) == "MEDLINE": + title_nlm = t.get("title", None) + + if pubname: + pubname = pubname[0].get("name", None) + + scielo_journals = item.get("scielo_journal", []) + + # Obtener la primera colección asociada, si existe + collection_acron = None + issn_scielo = None + if scielo_journals: + collection_acron = scielo_journals[0].get("collection_acron") + issn_scielo = scielo_journals[0].get("issn_scielo", None) + + if not title or acron_selected != collection_acron: + continue # Saltar si falta el título + + journal = JournalModel( + title=title, + short_title=short_title or None, + title_nlm=title_nlm or None, + acronym=acronym or None, + issn=issn_scielo or None, + pissn=pissn or None, + eissn=eissn or None, + pubname=pubname or None, + ) + new_journals.append(journal) + + url = data.get("next") + if new_journals: + with transaction.atomic(): + JournalModel.objects.bulk_create(new_journals, ignore_conflicts=True) From 9d013c751435e78235f7ee851b6a100dc1ce2591 Mon Sep 17 00:00:00 2001 From: GitInno <86991526+gitnnolabs@users.noreply.github.com> Date: Thu, 30 Apr 2026 08:06:19 -0300 Subject: [PATCH 7/7] =?UTF-8?q?Aplica=20o=20black,=20remove=20os=20imports?= =?UTF-8?q?=20denecess=C3=A1rio.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- markup_doc/wagtail_hooks.py | 92 +++++++++++-------------------------- 1 file changed, 27 insertions(+), 65 deletions(-) diff --git a/markup_doc/wagtail_hooks.py b/markup_doc/wagtail_hooks.py index d3f1428..2e4677c 100644 --- a/markup_doc/wagtail_hooks.py +++ b/markup_doc/wagtail_hooks.py @@ -1,54 +1,39 @@ from django.http import HttpResponseRedirect -from django.utils.translation import gettext_lazy as _ -from django.contrib import messages from django.template.response import TemplateResponse -from wagtail_modeladmin.options import ModelAdmin - +from django.utils.translation import gettext_lazy as _ +from wagtail.admin import messages +from wagtail.snippets.models import register_snippet from wagtail.snippets.views.snippets import ( CreateView, EditView, SnippetViewSet, - SnippetViewSetGroup + SnippetViewSetGroup, ) +from wagtail_modeladmin.options import ModelAdmin -from markup_doc.models import ( +from markup_doc.models import ( ArticleDocx, ArticleDocxMarkup, - UploadDocx, - MarkupXML, CollectionModel, JournalModel, - ProcessStatus + MarkupXML, + ProcessStatus, + UploadDocx, ) - -from config.menu import get_menu_order +from markup_doc.sync_api import sync_collection_from_api from markup_doc.tasks import task_sync_journals_from_api -from django.urls import path, reverse -from django.utils.html import format_html -from wagtail.admin import messages -from wagtail.admin.views import generic - -from django.shortcuts import redirect, get_object_or_404 -from django.views import View - -from wagtail.snippets.models import register_snippet -from django.db.models.signals import post_save -from django.dispatch import receiver -from django.db import transaction - -from wagtail import hooks -from django.templatetags.static import static -from markup_doc.sync_api import sync_collection_from_api, sync_journals_from_api class ArticleDocxCreateView(CreateView): - #def get_form_class(self): + # def get_form_class(self): def dispatch(self, request, *args, **kwargs): if not CollectionModel.objects.exists(): messages.warning(request, "Debes seleccionar primero una colección.") return HttpResponseRedirect(self.get_success_url()) if not JournalModel.objects.exists(): - messages.warning(request, "Espera un momento, aún no existen elementos en Journal.") + messages.warning( + request, "Espera un momento, aún no existen elementos en Journal." + ) return HttpResponseRedirect(self.get_success_url()) return super().dispatch(request, *args, **kwargs) @@ -77,10 +62,7 @@ class ArticleDocxAdmin(ModelAdmin): False # or True to exclude pages of this type from Wagtail's explorer view ) list_per_page = 20 - list_display = ( - "title", - "get_estatus_display" - ) + list_display = ("title", "get_estatus_display") class ArticleDocxMarkupCreateView(CreateView): @@ -111,10 +93,7 @@ class UploadDocxViewSet(SnippetViewSet): add_to_settings_menu = False exclude_from_explorer = False list_per_page = 20 - list_display = ( - "title", - "get_estatus_display" # Usar estatus, não status - ) + list_display = ("title", "get_estatus_display") # Usar estatus, não status search_fields = ("title",) list_filter = ("estatus",) # Usar estatus, não status @@ -128,19 +107,10 @@ class MarkupXMLViewSet(SnippetViewSet): menu_order = 1 add_to_settings_menu = False exclude_from_explorer = False - list_display=("title", ) + list_display = ("title",) list_per_page = 20 search_fields = ("title",) -""" -class MarkupAdminGroup(ModelAdminGroup): - menu_label = _("Markup") - menu_icon = "folder-open-inverse" - menu_order = 1 - items = (UploadDocxAdmin, MarkupXMLAdmin) - -modeladmin_register(MarkupAdminGroup) -""" class CollectionModelCreateView(CreateView): def get_context_data(self, **kwargs): @@ -152,13 +122,6 @@ def form_valid(self, form): form.instance.save() task_sync_journals_from_api.delay() return HttpResponseRedirect(self.get_success_url()) - - """ - def get_initial(self): - initial = super().get_initial() - initial["campo"] = "valor inicial dinámico" - return initial - """ class CollectionModelViewSet(SnippetViewSet): @@ -170,9 +133,7 @@ class CollectionModelViewSet(SnippetViewSet): add_to_settings_menu = False exclude_from_explorer = False list_per_page = 20 - list_display = ( - "collection", - ) + list_display = ("collection",) class JournalModelCreateView(CreateView): @@ -190,9 +151,7 @@ class JournalModelViewSet(SnippetViewSet): add_to_settings_menu = False exclude_from_explorer = False list_per_page = 20 - list_display = ( - "title", - ) + list_display = ("title",) def index_view(self, request): response = super().index_view(request) @@ -205,7 +164,10 @@ def index_view(self, request): return response if not JournalModel.objects.exists(): - messages.warning(request, "Sincronizando journals desde la API, espera unos momentos…") + messages.warning( + request, + "Sincronizando journals desde la API, espera unos momentos…", + ) response.context_data["can_add"] = False response.context_data["can_add_snippet"] = False return response @@ -214,16 +176,16 @@ def index_view(self, request): class MarkupSnippetViewSetGroup(SnippetViewSetGroup): - menu_name = 'docx_files' # Renomeado de 'docx_processor' - menu_label = _('DOCX Files') + menu_name = "docx_files" # Renomeado de 'docx_processor' + menu_label = _("DOCX Files") menu_icon = "folder-open-inverse" menu_order = 0 # Mudado de 1 para 0 para ficar na primeira posição items = ( UploadDocxViewSet, MarkupXMLViewSet, CollectionModelViewSet, - JournalModelViewSet + JournalModelViewSet, ) -register_snippet(MarkupSnippetViewSetGroup) \ No newline at end of file +register_snippet(MarkupSnippetViewSetGroup)