diff --git a/district/forms.py b/district/forms.py index d4e7108c72d82cabe6f99761962e686b32b6d690..16147c8fe4c1109a72b20775505f079425582dfb 100644 --- a/district/forms.py +++ b/district/forms.py @@ -1,5 +1,4 @@ from django import forms -from django.contrib.messages import ERROR, WARNING from wagtail.admin.forms import WagtailAdminPageForm from wagtail.core.models.collections import Collection @@ -70,12 +69,6 @@ class JekyllImportForm(WagtailAdminPageForm): if len(self.errors): return cleaned_data - # if cleaned_data.get("dry_run"): - # import_message_list = self.handle_import() - # for message in import_message_list: - # if message["level"] in (WARNING, ERROR): - # self.add_error("jekyll_repo_url", message["text"]) - return cleaned_data def handle_import(self): diff --git a/district/tasks.py b/district/tasks.py index e0d9c6cd61bb29b8ecb6f027fd739d596c6c7598..0bb2aa59c97005d902a0192601d3e953609930e6 100644 --- a/district/tasks.py +++ b/district/tasks.py @@ -1,8 +1,7 @@ import logging from majak.celery import app - -from .jekyll_import import JekyllArticleImporter +from shared.jekyll_import import JekyllArticleImporter logger = logging.getLogger(__name__) diff --git a/region/forms.py b/region/forms.py new file mode 100644 index 0000000000000000000000000000000000000000..16147c8fe4c1109a72b20775505f079425582dfb --- /dev/null +++ b/region/forms.py @@ -0,0 +1,87 @@ +from django import forms +from wagtail.admin.forms import WagtailAdminPageForm +from wagtail.core.models.collections import Collection + +from .tasks import import_jekyll_articles + + +class JekyllImportForm(WagtailAdminPageForm): + do_import = forms.BooleanField( + initial=False, required=False, label="Provést import z Jekyllu" + ) + collection = forms.ModelChoiceField( + queryset=Collection.objects.all(), required=False, label="Kolekce obrázků" + ) + dry_run = forms.BooleanField( + initial=True, + required=False, + label="Jenom na zkoušku", + help_text="Žádné články se neuloží, vypíše případné problémy či " + "již existující články - 'ostrému' importu existující " + "články nevadí, přeskočí je", + ) + use_git = forms.BooleanField( + initial=False, + required=False, + label="Použít Git", + help_text="Umožňuje jednodušší zpracování, ale vyžaduje nainstalovaný Git.", + ) + jekyll_repo_url = forms.URLField( + max_length=512, + required=False, + help_text="V GitHubu tlačítko Code -> a odkaz z Download zip" + "např. 'https://github.com/pirati-web/cb.pirati.cz/archive/refs/heads/gh-pages.zip'," + "pokud máte nainstalovaný Git, zvolte Použít Git a vložte" + "jednoduše URL repozitáře " + "např. 'https://github.com/pirati-web/cb.pirati.cz'", + ) + readonly_log = forms.CharField( + disabled=True, + label="Log z posledního importu", + required=False, + widget=forms.Textarea, + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields["readonly_log"].initial = self.instance.last_import_log + + def clean(self): + cleaned_data = super().clean() + + if not cleaned_data.get("do_import"): + return cleaned_data + else: + if not cleaned_data.get("collection"): + self.add_error("collection", "Pro import je toto pole povinné") + if not cleaned_data.get("jekyll_repo_url"): + self.add_error("jekyll_repo_url", "Pro import je toto pole povinné") + + if cleaned_data.get("use_git"): + if cleaned_data.get("jekyll_repo_url", "").endswith(".zip"): + self.add_error( + "jekyll_repo_url", "Vložte odkaz pouze na repozitář, ne na zip" + ) + else: + if not cleaned_data.get("jekyll_repo_url", "").endswith(".zip"): + self.add_error("jekyll_repo_url", "Odkaz nesměřuje na soubor '.zip'") + + if len(self.errors): + return cleaned_data + + return cleaned_data + + def handle_import(self): + import_jekyll_articles.delay( + article_parent_page_id=self.instance.id, + collection_id=self.cleaned_data["collection"].id, + url=self.cleaned_data["jekyll_repo_url"], + dry_run=self.cleaned_data["dry_run"], + use_git=self.cleaned_data["use_git"], + ) + + def save(self, commit=True): + if self.cleaned_data.get("do_import") and not self.cleaned_data["dry_run"]: + self.handle_import() + + return super().save(commit=commit) diff --git a/region/models.py b/region/models.py index b23ccd0ada5604f5bda07de84874c74900fb2bf8..d75865e039084e501a4953a7910a810b9d2166da 100644 --- a/region/models.py +++ b/region/models.py @@ -11,6 +11,7 @@ from taggit.models import Tag, TaggedItemBase from wagtail.admin.edit_handlers import ( CommentPanel, FieldPanel, + HelpPanel, MultiFieldPanel, ObjectList, PageChooserPanel, @@ -30,6 +31,7 @@ from shared.models import ArticleMixin, MenuMixin, SubpageMixin from uniweb.constants import RICH_TEXT_FEATURES from . import blocks +from .forms import JekyllImportForm class RegionHomePage(MenuMixin, MetadataPageMixin, CalendarMixin, Page): @@ -365,6 +367,9 @@ class RegionArticlePage(ArticleMixin, SubpageMixin, MetadataPageMixin, Page): class RegionArticlesPage(SubpageMixin, MetadataPageMixin, Page): ### FIELDS + last_import_log = models.TextField( + "Výstup z posledního importu", null=True, blank=True + ) max_items = models.IntegerField("Počet článků na stránce", default=12) ### PANELS @@ -375,6 +380,38 @@ class RegionArticlesPage(SubpageMixin, MetadataPageMixin, Page): settings_panels = [CommentPanel()] + import_panels = [ + MultiFieldPanel( + [ + FieldPanel("do_import"), + FieldPanel("collection"), + FieldPanel("dry_run"), + FieldPanel("use_git"), + FieldPanel("jekyll_repo_url"), + FieldPanel("readonly_log"), + HelpPanel( + "Import provádějte vždy až po vytvoření stránky aktualit. " + 'Pro uložení logu je nutné volit možnost "Publikovat", nikoliv' + 'pouze "Uložit koncept". ' + "Import proběhne na pozadí a může trvat až několik minut. " + "Dejte si po spuštění importu kávu a potom obnovte stránku pro " + "zobrazení výsledku importu." + ), + ], + "import z Jekyll repozitáře", + ), + ] + + ### EDIT HANDLERS + + edit_handler = TabbedInterface( + [ + ObjectList(content_panels, heading="Obsah"), + ObjectList(settings_panels, heading="Nastavení"), + ObjectList(import_panels, heading="Import"), + ] + ) + ### RELATIONS parent_page_types = ["region.RegionHomePage"] @@ -382,6 +419,8 @@ class RegionArticlesPage(SubpageMixin, MetadataPageMixin, Page): ### OTHERS + base_form_class = JekyllImportForm + class Meta: verbose_name = "Aktuality" diff --git a/region/tasks.py b/region/tasks.py new file mode 100644 index 0000000000000000000000000000000000000000..8eb9c6d1de7b5f6892c2c0a058d22862cca16a2d --- /dev/null +++ b/region/tasks.py @@ -0,0 +1,27 @@ +import logging + +from majak.celery import app +from shared.jekyll_import import JekyllArticleImporter + +logger = logging.getLogger(__name__) + + +@app.task +def import_jekyll_articles( + article_parent_page_id: int, + collection_id: int, + url: str, + dry_run: bool, + use_git: bool, +): + from .models import RegionArticlePage, RegionArticlesPage + + return JekyllArticleImporter( + article_parent_page_id=article_parent_page_id, + collection_id=collection_id, + url=url, + dry_run=dry_run, + use_git=use_git, + parent_page_model=RegionArticlesPage, + page_model=RegionArticlePage, + ).perform_import() diff --git a/district/jekyll_import.py b/shared/jekyll_import.py similarity index 97% rename from district/jekyll_import.py rename to shared/jekyll_import.py index 1f083b296a581f4c5739f562a8fd74feaac1876b..2871f3783ae4968dc5b068bbefbe8f0729afc34d 100644 --- a/district/jekyll_import.py +++ b/shared/jekyll_import.py @@ -27,7 +27,7 @@ from wagtail.images.models import Image from yaml.scanner import ScannerError logger = logging.getLogger(__name__) -# from django.utils.dateparse import parse_date TODO enable date check again... +# from django.utils.dateparse import parse_date # pro hledani krome title i podle data image_params = {} # filled on JekyllArticleImporter init and used globally @@ -170,7 +170,12 @@ def get_or_create_image( file = ImageFile(open(img_path, "rb"), name=img_path) image = Image(title=file_path, file=file, collection=collection) - image.save() + try: + image.save() + except Exception as e: + msg = "Nelze uložit obrázek" + logger.warning(msg, extra={"exc": e}) + return None, msg return image, "" @@ -310,7 +315,7 @@ class JekyllArticleImporter: d = match.group(3) slug = match.group(4) - if article and self.article_path: # asi jenom Ceske Budejovice + if self.article_path: # asi jenom Ceske Budejovice Redirect.objects.get_or_create( site=self.site, old_path="/%s/%s/%s/%s/%s" @@ -318,7 +323,7 @@ class JekyllArticleImporter: defaults={"is_permanent": True, "redirect_page": article}, ) - elif article and self.permalink: + elif self.permalink: Redirect.objects.get_or_create( site=self.site, old_path=self.permalink.replace(":title", slug), @@ -433,7 +438,6 @@ class JekyllArticleImporter: except (Page.DoesNotExist, Page.MultipleObjectsReturned): article = self.page_model() - # article.text = html article.content = [("text", RichText(html))] article.perex = self.get_perex(md) or "..." @@ -517,7 +521,7 @@ class JekyllArticleImporter: if ext == "md": article = self.import_post(file_path) - if self.dry_run: + if self.dry_run or not article: return article.save() # ujistím se, že mám "redirect_page" pro Redirect uloženou