diff --git a/README.md b/README.md index bc2c3c77b9802d97e8f3b7bc66b89eb60cc244a2..76ed94b3c4bf49b800deb2fa3bc323f83b4d2d86 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,7 @@ Přes CRON je třeba na pozadí spouštět Django `manage.py` commandy: * `clearsessions` - maže expirované sessions (denně až týdně) * `publish_scheduled_pages` - publikuje naplánované stránky (každou hodinu) * `update_callendars` - stáhne a aktualizuje kalendáře (několikrát denně) +* `update_main_timeline_articles` - aktualizuje články na `pirati.cz` z `https://piratipracuji.cz/api/` * `update_redmine_issues` - aktualizuje programované body MS a KS stránek napojených na Redmine (několikrát denně) * `update_tweets` - aktualizuje tweety podle nastavení na Homepage pirati.cz - vyžaduje mít v .env TWITTER_BEARER_TOKEN, parametr --days určuje stáří tweetů (default 1) diff --git a/article_import_utils/services.py b/article_import_utils/services.py deleted file mode 100644 index b1f6e9c44bb4fc7f2178479f5e1e2f9015bf476e..0000000000000000000000000000000000000000 --- a/article_import_utils/services.py +++ /dev/null @@ -1,53 +0,0 @@ -import json -import logging -from typing import TYPE_CHECKING - -import requests - -from article_import_utils.utils import create_image_from_url -from main.models import MainArticlePage, MainArticlesPage, ARTICLE_TYPES - -if TYPE_CHECKING: - pass - -logger = logging.getLogger() - - -class ArticleDownloadService: - api_url = 'https://piratipracuji.cz/api/' - - @staticmethod - def get_existing_articles_slugs() -> list[str]: - return MainArticlePage.objects.filter(article_type=ARTICLE_TYPES.WORK_TIMELINE).values_list('slug', flat=True) - - def get_articles_response(self): - response = requests.get(self.api_url) - data = json.loads(response.text) - - return data - - def perform_update(self): - existing_articles_slug_list = self.get_existing_articles_slugs() - - for article in self.get_articles_response(): - if article['slug'] not in existing_articles_slug_list: - if 'thumbnail' in article: - img_filename = 'article-' + str(article['id']) + '.jpg' - img_obj = create_image_from_url(url=article['thumbnail'], filename=img_filename) - else: - img_obj = None - - article_to_save = MainArticlePage(article_type=ARTICLE_TYPES.WORK_TIMELINE, - title=article['title'], - slug=article['slug'], - perex=article['description'].replace(" ", ""), - author='ČESKÁ PIRÁTSKÁ STRANA', - date=article['start_date'], - image=img_obj, - content=json.dumps([ - {'type': 'text', - 'value': article['content'].replace("</p>", "</p><br>")} - ]) - ) - parent = MainArticlesPage.objects.all().first() - parent.add_child(instance=article_to_save) diff --git a/article_import_utils/utils.py b/article_import_utils/utils.py deleted file mode 100644 index 1320c99e5ff5b66339242a33f0477eee0f9b86c8..0000000000000000000000000000000000000000 --- a/article_import_utils/utils.py +++ /dev/null @@ -1,14 +0,0 @@ -import urllib.request -from wagtail.images.models import Image -from django.core.files import File - - -def create_image_from_url(url, filename): - img_data = urllib.request.urlretrieve(url) - img_obj = Image(title=filename) - img_obj.file.save( - filename, - File(open(img_data[0], 'rb')) - ) - img_obj.save() - return img_obj diff --git a/article_import_utils/management/__init__.py b/main/management/__init__.py similarity index 100% rename from article_import_utils/management/__init__.py rename to main/management/__init__.py diff --git a/article_import_utils/management/commands/__init__.py b/main/management/commands/__init__.py similarity index 100% rename from article_import_utils/management/commands/__init__.py rename to main/management/commands/__init__.py diff --git a/article_import_utils/management/commands/update_articles.py b/main/management/commands/update_main_timeline_articles.py similarity index 67% rename from article_import_utils/management/commands/update_articles.py rename to main/management/commands/update_main_timeline_articles.py index f4916750c8d07497aff4705064c58e72654a7e13..7a688ecb1a4d7033a87d27ec8d37e1c57b527c5c 100644 --- a/article_import_utils/management/commands/update_articles.py +++ b/main/management/commands/update_main_timeline_articles.py @@ -1,11 +1,11 @@ from django.core.management.base import BaseCommand -from article_import_utils.services import ArticleDownloadService +from main.services import TimelineArticleDownloadService -class Command(BaseCommand): +class Command(BaseCommand): def handle(self, *args, **options): - ads = ArticleDownloadService() + ads = TimelineArticleDownloadService() ads.perform_update() self.stdout.write("\nUpdate of articles finished!") diff --git a/main/services.py b/main/services.py new file mode 100644 index 0000000000000000000000000000000000000000..b1ea15e00d6fe156f9d754b97d4de44361bfa838 --- /dev/null +++ b/main/services.py @@ -0,0 +1,66 @@ +import json +import logging +from typing import TYPE_CHECKING + +import requests + +from main.models import ARTICLE_TYPES, MainArticlePage, MainArticlesPage +from shared.utils import create_image_from_url + +if TYPE_CHECKING: + pass + +logger = logging.getLogger() + + +class TimelineArticleDownloadService: + api_url = "https://piratipracuji.cz/api/" + + @staticmethod + def get_existing_articles_slugs() -> list[str]: + return MainArticlePage.objects.filter( + article_type=ARTICLE_TYPES.WORK_TIMELINE + ).values_list("slug", flat=True) + + def get_articles_response(self): + response = requests.get(self.api_url) + data = json.loads(response.text) + + return data + + def perform_update(self): + existing_articles_slug_list = self.get_existing_articles_slugs() + parent = MainArticlesPage.objects.all().first() + + if not parent: + RuntimeError("No MainArticlesPage to import to") + + for article in self.get_articles_response(): + if article["slug"] not in existing_articles_slug_list: + if "thumbnail" in article: + img_filename = "article-" + str(article["id"]) + ".jpg" + img_obj = create_image_from_url( + url=article["thumbnail"], filename=img_filename + ) + else: + img_obj = None + + article_to_save = MainArticlePage( + article_type=ARTICLE_TYPES.WORK_TIMELINE, + title=article["title"], + slug=article["slug"], + perex=article["description"].replace(" ", ""), + author="ČESKÁ PIRÁTSKÁ STRANA", + date=article["start_date"], + image=img_obj, + content=json.dumps( + [ + { + "type": "text", + "value": article["content"].replace("</p>", "</p><br>"), + } + ] + ), + ) + + parent.add_child(instance=article_to_save) diff --git a/main/static/main/css/pattern-scaffolding.css b/main/static/main/css/pattern-scaffolding.css deleted file mode 100644 index d56b035d01635d79ac4e4e26502b87d5d34f6902..0000000000000000000000000000000000000000 --- a/main/static/main/css/pattern-scaffolding.css +++ /dev/null @@ -1,70 +0,0 @@ -/** - * This stylesheet is for styles you want to include only when displaying demo - * styles for grids, animations, color swatches, etc. - * These styles will not be your production CSS. - */ -#sg-patterns { - -webkit-box-sizing: border-box !important; - box-sizing: border-box !important; - max-width: 100%; - padding: 0 0.5em; -} - -.demo-animate { - background: #ddd; - padding: 1em; - margin-bottom: 1em; - text-align: center; - border-radius: 8px; - cursor: pointer; -} - -.sg-colors { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - list-style: none !important; - padding: 0 !important; - margin: 0 !important; -} -.sg-colors li { - -webkit-box-flex: 1; - -ms-flex: auto; - flex: auto; - padding: 0.3em; - margin: 0 0.5em 0.5em 0; - min-width: 5em; - max-width: 14em; - border: 1px solid #ddd; - border-radius: 0; -} - -.sg-swatch { - display: block; - height: 8rem; - margin-bottom: 0.5rem; - border-radius: 0; -} - -.sg-label { - font-size: 1rem; -} - -.sg-pattern-example { - font-family: "Roboto", "Helvetica", "Arial", sans-serif !important; -} - -.sg-pattern-head .sg-pattern-title a { - font-family: "Roboto", "Helvetica", "Arial", sans-serif !important; - font-weight: bold !important; - font-size: 1.2rem !important; - color: #202020 !important; -} - -.sg-pattern-category-title a { - font-family: "Bebas Neue", "Helvetica", "Arial", sans-serif !important; - font-weight: 400 !important; - font-size: 3.5rem !important; -} diff --git a/main/static/main/css/styles.css b/main/static/main/css/styles.css index b544028edda6c1a622cb64806c39d57a32667c31..7d96ea029a5799e3b5fe9f95aa11b866c30dfaa7 100644 --- a/main/static/main/css/styles.css +++ b/main/static/main/css/styles.css @@ -2551,7 +2551,7 @@ p{ } .btn-carousel{ - @aplly h-11; + height: 2.75rem; top: 28%; } diff --git a/main/styleguide/source/css/molecules/carousels.pcss b/main/styleguide/source/css/molecules/carousels.pcss index f708ae7694503d241d54fa27debfd0641ad5f556..31cde331d38ecc88387a9949d2b1a0239943decf 100644 --- a/main/styleguide/source/css/molecules/carousels.pcss +++ b/main/styleguide/source/css/molecules/carousels.pcss @@ -169,8 +169,9 @@ } } } + .btn-carousel{ - @aplly h-11; + @apply h-11; top: 28%; } diff --git a/main/utils.py b/main/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/shared/utils.py b/shared/utils.py index 698ed7ed8e68c5860bab00cc52975fcf5e7e4a3e..072d2c5eb2326ebd92e7e1aac2bdb5f458b28cbd 100644 --- a/shared/utils.py +++ b/shared/utils.py @@ -1,9 +1,11 @@ import json import logging +import urllib.request import bleach import requests from django.conf import settings +from django.core.files import File from django.utils.translation import gettext_lazy from wagtail.admin.edit_handlers import ( CommentPanel, @@ -13,12 +15,21 @@ from wagtail.admin.edit_handlers import ( ) from wagtail.core.models import Page from wagtail.images.edit_handlers import FieldPanel +from wagtail.images.models import Image from tuning import admin_help logger = logging.getLogger() +def create_image_from_url(url, filename): + img_data = urllib.request.urlretrieve(url) + img_obj = Image(title=filename) + img_obj.file.save(filename, File(open(img_data[0], "rb"))) + img_obj.save() + return img_obj + + def get_subpage_url(page, dest_page_type): try: return page.get_descendants().type(dest_page_type).live().first().get_url()