Skip to content
Snippets Groups Projects
Commit 46ece396 authored by Tomáš Valenta's avatar Tomáš Valenta
Browse files

move further models to mixins

parent f331981c
Branches
No related tags found
2 merge requests!876Fix shared articles & release elections web,!863Add elections web
Pipeline #16082 passed
...@@ -9,7 +9,6 @@ from wagtail.blocks import ( ...@@ -9,7 +9,6 @@ from wagtail.blocks import (
TextBlock, TextBlock,
URLBlock, URLBlock,
) )
from wagtail.documents.blocks import DocumentChooserBlock
from wagtail.images.blocks import ImageChooserBlock from wagtail.images.blocks import ImageChooserBlock
from shared.blocks import CardLinkBlockMixin, CardLinkWithHeadlineBlockMixin, CTAMixin from shared.blocks import CardLinkBlockMixin, CardLinkWithHeadlineBlockMixin, CTAMixin
...@@ -250,16 +249,6 @@ class PersonContactBoxBlock(StructBlock): ...@@ -250,16 +249,6 @@ class PersonContactBoxBlock(StructBlock):
# ARTICLE BLOCKS # ARTICLE BLOCKS
class ArticleQuoteBlock(StructBlock):
quote = CharBlock(label="Citace")
autor_name = CharBlock(label="Jméno autora")
class Meta:
icon = "user"
label = "Blok citace"
template = "main/includes/legacy/article_quote_block.html"
class ArticleImageMixin(StructBlock): class ArticleImageMixin(StructBlock):
image = ImageChooserBlock(label="Obrázek") image = ImageChooserBlock(label="Obrázek")
image_source = CharBlock( image_source = CharBlock(
...@@ -285,15 +274,6 @@ class ArticleRightImageBlock(ArticleImageMixin): ...@@ -285,15 +274,6 @@ class ArticleRightImageBlock(ArticleImageMixin):
template = "main/includes/molecules/articles/article_richtext_content_with_right_image.html" template = "main/includes/molecules/articles/article_richtext_content_with_right_image.html"
class ArticleDownloadBlock(StructBlock):
file = DocumentChooserBlock(label="Stáhnutelný soubor")
class Meta:
icon = "user"
label = "Blok stáhnutelného dokumentu"
template = "main/includes/molecules/blocks/article_download_block.html"
class TwoTextColumnBlock(StructBlock): class TwoTextColumnBlock(StructBlock):
text_column_1 = RichTextBlock(label="První sloupec textu") text_column_1 = RichTextBlock(label="První sloupec textu")
text_column_2 = RichTextBlock(label="Druhý sloupec textu") text_column_2 = RichTextBlock(label="Druhý sloupec textu")
...@@ -352,5 +332,6 @@ class TeamBlock(StructBlock): ...@@ -352,5 +332,6 @@ class TeamBlock(StructBlock):
# --- TODO: Remove legacy blocks used in migrations only # --- TODO: Remove legacy blocks used in migrations only
class LinkBlock(StructBlock): class LinkBlock(StructBlock):
pass pass
# Generated by Django 4.1.10 on 2024-01-03 19:04 # Generated by Django 4.1.10 on 2024-01-03 19:04
from django.db import migrations
import shared.blocks.main
import wagtail.blocks import wagtail.blocks
import wagtail.fields import wagtail.fields
from django.db import migrations
import shared.blocks.main
class Migration(migrations.Migration): class Migration(migrations.Migration):
......
...@@ -29,6 +29,7 @@ from wagtail.search import index ...@@ -29,6 +29,7 @@ from wagtail.search import index
from wagtailmetadata.models import MetadataPageMixin from wagtailmetadata.models import MetadataPageMixin
from calendar_utils.models import CalendarMixin from calendar_utils.models import CalendarMixin
from shared import blocks as shared_blocks
from shared.forms import SubscribeForm from shared.forms import SubscribeForm
from shared.models import ( # MenuMixin, from shared.models import ( # MenuMixin,
ArticleMixin, ArticleMixin,
...@@ -36,22 +37,20 @@ from shared.models import ( # MenuMixin, ...@@ -36,22 +37,20 @@ from shared.models import ( # MenuMixin,
ArticlesPageMixin, ArticlesPageMixin,
ExtendedMetadataHomePageMixin, ExtendedMetadataHomePageMixin,
ExtendedMetadataPageMixin, ExtendedMetadataPageMixin,
MainArticlePageMixin,
MainArticlesPageMixin,
MainHomePageMixin,
SharedTaggedMainArticle, SharedTaggedMainArticle,
SubpageMixin, SubpageMixin,
) )
from shared.utils import make_promote_panels, subscribe_to_newsletter from shared.utils import make_promote_panels, subscribe_to_newsletter
from shared import blocks as shared_blocks
from tuning import admin_help from tuning import admin_help
from . import blocks from . import blocks
from .constants import MONTH_NAMES
from .forms import JekyllImportForm from .forms import JekyllImportForm
from .menu import MenuMixin, PageInMenuMixin from .menu import MenuMixin, PageInMenuMixin
from shared.models import MainHomePageMixin
class MainHomePage(MainHomePageMixin): class MainHomePage(MainHomePageMixin):
# content # content
content = StreamField( content = StreamField(
...@@ -128,251 +127,10 @@ class MainHomePage(MainHomePageMixin): ...@@ -128,251 +127,10 @@ class MainHomePage(MainHomePageMixin):
return self.setup_article_page_context(request) return self.setup_article_page_context(request)
class MainArticlesPage( class MainArticlesPage(MainArticlesPageMixin):
RoutablePageMixin,
ExtendedMetadataPageMixin,
SubpageMixin,
MetadataPageMixin,
ArticlesPageMixin,
PageInMenuMixin,
Page,
):
last_import_log = models.TextField(
"Výstup z posledního importu", null=True, blank=True
)
perex = models.TextField()
import_panels = [
MultiFieldPanel(
[
FieldPanel("do_import"),
FieldPanel("collection"),
FieldPanel("dry_run"),
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",
),
]
### RELATIONS
parent_page_types = ["main.MainHomePage"] parent_page_types = ["main.MainHomePage"]
subpage_types = ["main.MainArticlePage"] subpage_types = ["main.MainArticlePage"]
### PANELS
content_panels = Page.content_panels + [
FieldPanel("perex"),
FieldPanel("shared_tags"),
]
promote_panels = make_promote_panels()
### EDIT HANDLERS
edit_handler = TabbedInterface(
[
ObjectList(content_panels, heading="Obsah"),
ObjectList(promote_panels, heading="Propagovat"),
ObjectList(import_panels, heading="Import"),
]
)
### OTHERS
base_form_class = JekyllImportForm
class Meta:
verbose_name = "Rozcestník článků"
def get_base_shared_articles_query(self, filter: models.Q):
return self.materialize_shared_articles_query(
self.append_all_shared_articles_query(
MainArticlePage.objects.filter(filter)
)
.live()
.order_by("-union_date")
)
def get_article_data_list(
self,
months_back: int = 1,
search_filter: models.Q | None = None,
):
if search_filter is None:
search_filter = models.Q()
target_date_list = (
self.append_all_shared_articles_query(
MainArticlePage.objects.filter(search_filter)
)
.order_by("-union_date")
.live()
.values_list("union_date", flat=True)
)
if not target_date_list:
return []
target_date = target_date_list[0] - relativedelta(months=months_back)
first_day_of_target_month = target_date.replace(day=1)
filter = models.Q(date__gte=first_day_of_target_month) & search_filter
sorted_article_qs = self.get_base_shared_articles_query(filter)
article_data_list = []
current_month_data = self.get_empty_month_data(timezone.now().date())
for article in sorted_article_qs:
if article.date.month != current_month_data["month_number"]:
if len(current_month_data["articles"]) != 0:
# append completed month if it contains any articles
article_data_list.append(current_month_data)
current_month_data = self.get_empty_month_data(article.date)
current_month_data["articles"].append(article)
article_data_list.append(current_month_data) # last iteration
return article_data_list
def get_search_filters(self, request):
filter = models.Q()
if "tag_id" in request.GET:
tag = self.get_filtered_tag(request)
if tag is not None:
filter = filter & models.Q(tags__id=tag.id)
if "q" in request.GET:
filter = filter & models.Q(title__icontains=self.get_search_query(request))
return filter
def get_filtered_tag(self, request) -> Tag | None:
if "tag_id" in request.GET:
try:
return Tag.objects.filter(id=int(request.GET["tag_id"])).first()
except Exception:
pass
return None
def get_search_query(self, request) -> str | None:
if "q" in request.GET:
return request.GET["q"]
def get_context(self, request, get_articles: bool = True, *args, **kwargs):
ctx = super().get_context(request, args, kwargs)
if get_articles:
filtered_tag = self.get_filtered_tag(request)
if filtered_tag is not None:
ctx["filtered_tag"] = filtered_tag
search_query = self.get_search_query(request)
if search_query is not None:
ctx["search_query"] = search_query
search_filter = self.get_search_filters(request)
article_timeline_list = self.get_article_data_list(1, search_filter)
ctx["article_timeline_list"] = article_timeline_list
ctx["show_next_timeline_articles"] = len(
self.get_base_shared_articles_query(search_filter)
) != 0 and (
self.materialize_shared_articles_query(
self.append_all_shared_articles_query(
MainArticlePage.objects.filter(search_filter)
)
.live()
.order_by("union_date")[:2] # LIMIT 2
)[0]
not in article_timeline_list[-1]["articles"]
)
tags = []
for article in MainArticlePage.objects.all()[:50]:
for tag in article.tags.all():
if tag in tags:
continue
tags.append(tag)
ctx["tags"] = tags
# meow
return ctx
def get_timeline_articles_response(self, request):
try:
months = int(request.GET.get("months", None))
except ValueError:
months = 1
search_filter = self.get_search_filters(request)
article_timeline_list = self.get_article_data_list(months, search_filter)
context = {"article_timeline_list": article_timeline_list}
data = {
"html": render(
request,
"main/includes/organisms/articles/articles_timeline_list.html",
context,
).content.decode("utf-8"),
"has_next": (
len(self.get_base_shared_articles_query(search_filter)) != 0
and (
self.materialize_shared_articles_query(
self.append_all_shared_articles_query(
MainArticlePage.objects.filter(search_filter)
)
.live()
.order_by("union_date")[:2] # LIMIT 2
)[0]
not in article_timeline_list[-1]["articles"]
)
),
}
return JsonResponse(data=data, safe=False)
@route(r"^sdilene/$", name="shared")
def shared(self, request):
return self.setup_article_page_context(request)
def serve(self, request, *args, **kwargs):
if request.META.get("HTTP_X_REQUESTED_WITH") == "XMLHttpRequest":
if "months" in request.GET:
return self.get_timeline_articles_response(request)
return super().serve(request, *args, **kwargs)
@staticmethod
def get_empty_month_data(date_obj):
return {
"month_number": date_obj.month,
"month_text": MONTH_NAMES[date_obj.month - 1],
"articles": [],
}
class MainArticleTag(TaggedItemBase): class MainArticleTag(TaggedItemBase):
content_object = ParentalKey( content_object = ParentalKey(
...@@ -382,29 +140,7 @@ class MainArticleTag(TaggedItemBase): ...@@ -382,29 +140,7 @@ class MainArticleTag(TaggedItemBase):
) )
class MainArticlePage( class MainArticlePage(MainArticlePageMixin):
ArticleMixin,
ExtendedMetadataPageMixin,
SubpageMixin,
MetadataPageMixin,
PageInMenuMixin,
Page,
):
### FIELDS
content = StreamField(
[
(
"text",
RichTextBlock(template="main/includes/atoms/text/prose_richtext.html"),
),
("quote", blocks.ArticleQuoteBlock()),
("download", blocks.ArticleDownloadBlock()),
],
verbose_name="Článek",
blank=True,
use_json_field=True,
)
author_page = models.ForeignKey( author_page = models.ForeignKey(
"main.MainPersonPage", "main.MainPersonPage",
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
...@@ -415,50 +151,10 @@ class MainArticlePage( ...@@ -415,50 +151,10 @@ class MainArticlePage(
tags = ClusterTaggableManager( tags = ClusterTaggableManager(
through=MainArticleTag, related_name="tagged_articles", blank=True through=MainArticleTag, related_name="tagged_articles", blank=True
) )
shared_tags = ClusterTaggableManager(
verbose_name="Tagy pro sdílení mezi weby",
through=SharedTaggedMainArticle,
blank=True,
)
search_fields = ArticleMixin.search_fields + [
index.SearchField("author_page"),
index.FilterField("slug"),
]
### PANELS
content_panels = ArticleMixin.content_panels + [
FieldPanel("author_page"),
FieldPanel("tags"),
FieldPanel("shared_tags"),
]
promote_panels = make_promote_panels(
admin_help.build(admin_help.NO_SEO_TITLE, admin_help.NO_DESCRIPTION_USE_PEREX),
search_image=False,
)
### RELATIONS
parent_page_types = ["main.MainArticlesPage"] parent_page_types = ["main.MainArticlesPage"]
subpage_types = [] subpage_types = []
### OTHERS
class Meta:
verbose_name = "Aktualita"
# def get_context(self, request): chceme/nechceme?
# context = super().get_context(request)
# context["related_articles"] = (
# self.get_siblings(inclusive=False)
# .live()
# .specific()
# .order_by("-mainarticlepage__date")[:3]
# )
# return context
class MainProgramPage( class MainProgramPage(
ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, PageInMenuMixin, Page ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, PageInMenuMixin, Page
......
from wagtail import blocks from wagtail import blocks
from wagtail.blocks import ( from wagtail.blocks import (
CharBlock, CharBlock,
ListBlock, ListBlock,
...@@ -8,12 +7,13 @@ from wagtail.blocks import ( ...@@ -8,12 +7,13 @@ from wagtail.blocks import (
StructBlock, StructBlock,
URLBlock, URLBlock,
) )
from wagtail.documents.blocks import DocumentChooserBlock
from .base import MenuItemBlock as MenuItemBlockBase from .base import MenuItemBlock as MenuItemBlockBase
# Mixins (or used as such) # Mixins (or used as such)
class CTAMixin(StructBlock): class CTAMixin(StructBlock):
button_link = URLBlock(label="Odkaz tlačítka") button_link = URLBlock(label="Odkaz tlačítka")
button_text = CharBlock(label="Text tlačítka") button_text = CharBlock(label="Text tlačítka")
...@@ -34,6 +34,7 @@ class LinkBlock(StructBlock): ...@@ -34,6 +34,7 @@ class LinkBlock(StructBlock):
# Navbar # Navbar
class MainMenuItemBlock(MenuItemBlockBase): class MainMenuItemBlock(MenuItemBlockBase):
title = blocks.CharBlock( title = blocks.CharBlock(
label="Titulek", label="Titulek",
...@@ -63,8 +64,31 @@ class SocialLinkBlock(LinkBlock): ...@@ -63,8 +64,31 @@ class SocialLinkBlock(LinkBlock):
label = "Odkaz" label = "Odkaz"
# Articles
class ArticleQuoteBlock(StructBlock):
quote = CharBlock(label="Citace")
autor_name = CharBlock(label="Jméno autora")
class Meta:
icon = "user"
label = "Blok citace"
template = "main/includes/legacy/article_quote_block.html"
class ArticleDownloadBlock(StructBlock):
file = DocumentChooserBlock(label="Stáhnutelný soubor")
class Meta:
icon = "user"
label = "Blok stáhnutelného dokumentu"
template = "main/includes/molecules/blocks/article_download_block.html"
# People # People
class PersonContactBlock(StructBlock): class PersonContactBlock(StructBlock):
position = CharBlock(label="Název pozice", required=False) position = CharBlock(label="Název pozice", required=False)
# email, phone? # email, phone?
...@@ -80,6 +104,7 @@ class PersonContactBlock(StructBlock): ...@@ -80,6 +104,7 @@ class PersonContactBlock(StructBlock):
# Footer # Footer
class OtherLinksBlock(StructBlock): class OtherLinksBlock(StructBlock):
title = CharBlock(label="Titulek") title = CharBlock(label="Titulek")
list = ListBlock(LinkBlock, label="Seznam odkazů s titulkem") list = ListBlock(LinkBlock, label="Seznam odkazů s titulkem")
......
...@@ -17,3 +17,18 @@ RICH_TEXT_DEFAULT_FEATURES = [ ...@@ -17,3 +17,18 @@ RICH_TEXT_DEFAULT_FEATURES = [
"blockquote", "blockquote",
"embed", "embed",
] ]
MONTH_NAMES = [
"Leden",
"Únor",
"Březen",
"Duben",
"Květen",
"Červen",
"Červenec",
"Srpen",
"Září",
"Říjen",
"Listopad",
"Prosinec",
]
from django import forms from django import forms
from wagtail.admin.forms import WagtailAdminPageForm
from wagtail.models.collections import Collection
from shared.jekyll_import import JekyllArticleImporter
class SubscribeForm(forms.Form): class SubscribeForm(forms.Form):
email = forms.EmailField() email = forms.EmailField()
confirmed = forms.BooleanField() confirmed = forms.BooleanField()
return_page_id = forms.IntegerField() return_page_id = forms.IntegerField()
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",
)
jekyll_repo_url = forms.URLField(
max_length=512,
required=False,
help_text="např. https://github.com/pirati-web/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
if cleaned_data.get("do_import") and not self.instance.id:
self.add_error(
"do_import", "Import proveďte prosím až po vytvoření stránky"
)
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("jekyll_repo_url", "").endswith(".zip"):
self.add_error(
"jekyll_repo_url", "Vložte odkaz pouze na repozitář, ne na zip"
)
return cleaned_data
def handle_import(self, model):
# TODO: Portable function
from .models import MainArticlePage
JekyllArticleImporter(
article_parent_page=self.instance,
collection_id=self.cleaned_data["collection"].id,
url=self.cleaned_data["jekyll_repo_url"],
dry_run=self.cleaned_data["dry_run"],
use_git=True,
page_model=MainArticlePage,
).perform_import()
def save(self, commit=True):
if self.cleaned_data.get("do_import"):
self.handle_import()
return super().save(commit=commit)
...@@ -29,28 +29,29 @@ from wagtail.search import index ...@@ -29,28 +29,29 @@ from wagtail.search import index
from wagtailmetadata.models import MetadataPageMixin from wagtailmetadata.models import MetadataPageMixin
from calendar_utils.models import CalendarMixin from calendar_utils.models import CalendarMixin
from shared.forms import SubscribeForm from shared.blocks import (
ArticleDownloadBlock,
ArticleQuoteBlock,
MainMenuItemBlock,
NavbarMenuItemBlock,
OtherLinksBlock,
PersonContactBlock,
SocialLinkBlock,
)
from shared.const import MONTH_NAMES
from shared.forms import JekyllImportForm, SubscribeForm
from shared.utils import make_promote_panels, subscribe_to_newsletter
from tuning import admin_help
from .base import ( # MenuMixin, from .base import ( # MenuMixin,
ArticleMixin, ArticleMixin,
ArticlesMixin, ArticlesMixin,
ArticlesPageMixin, ArticlesPageMixin,
ExtendedMetadataHomePageMixin, ExtendedMetadataHomePageMixin,
ExtendedMetadataPageMixin, ExtendedMetadataPageMixin,
SharedTaggedMainArticle,
SubpageMixin,
) )
from shared.utils import make_promote_panels, subscribe_to_newsletter
from tuning import admin_help
from wagtail.models import Page
from django.db import models
from wagtail.admin.panels import FieldPanel, MultiFieldPanel
from wagtail.fields import StreamField
from wagtail.models import Page
from .base import MenuMixin as MenuMixinBase from .base import MenuMixin as MenuMixinBase
from shared.blocks import MainMenuItemBlock, NavbarMenuItemBlock, OtherLinksBlock, PersonContactBlock, SocialLinkBlock from .base import SharedTaggedMainArticle, SubpageMixin # MenuMixin,
class MainMenuMixin(MenuMixinBase): class MainMenuMixin(MenuMixinBase):
...@@ -261,7 +262,9 @@ class MainHomePageMixin( ...@@ -261,7 +262,9 @@ class MainHomePageMixin(
context = super().get_context(request, args, kwargs) context = super().get_context(request, args, kwargs)
context["article_data_list"] = self.materialize_shared_articles_query( context["article_data_list"] = self.materialize_shared_articles_query(
self.append_all_shared_articles_query(self.article_page_model.objects.live().all()) self.append_all_shared_articles_query(
self.article_page_model.objects.live().all()
)
.live() .live()
.order_by("-union_date")[:3] .order_by("-union_date")[:3]
) )
...@@ -373,3 +376,316 @@ class MainHomePageMixin( ...@@ -373,3 +376,316 @@ class MainHomePageMixin(
@route(r"^sdilene/$", name="shared") @route(r"^sdilene/$", name="shared")
def shared(self, request): def shared(self, request):
return self.setup_article_page_context(request) return self.setup_article_page_context(request)
class MainArticlesPageMixin(
RoutablePageMixin,
ExtendedMetadataPageMixin,
SubpageMixin,
MetadataPageMixin,
ArticlesPageMixin,
PageInMenuMixin,
Page,
):
last_import_log = models.TextField(
"Výstup z posledního importu", null=True, blank=True
)
perex = models.TextField()
import_panels = [
MultiFieldPanel(
[
FieldPanel("do_import"),
FieldPanel("collection"),
FieldPanel("dry_run"),
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",
),
]
### RELATIONS
parent_page_types = [] # NOTE: Must be implemented
subpage_types = [] # NOTE: Must be implemented
### PANELS
content_panels = Page.content_panels + [
FieldPanel("perex"),
FieldPanel("shared_tags"),
]
promote_panels = make_promote_panels()
### EDIT HANDLERS
edit_handler = TabbedInterface(
[
ObjectList(content_panels, heading="Obsah"),
ObjectList(promote_panels, heading="Propagovat"),
ObjectList(import_panels, heading="Import"),
]
)
### OTHERS
base_form_class = JekyllImportForm
class Meta:
verbose_name = "Rozcestník článků"
abstract = True
def get_base_shared_articles_query(self, filter: models.Q):
return self.materialize_shared_articles_query(
self.append_all_shared_articles_query(
self.root_page.article_page_model.objects.filter(filter)
)
.live()
.order_by("-union_date")
)
def get_article_data_list(
self,
months_back: int = 1,
search_filter: models.Q | None = None,
):
if search_filter is None:
search_filter = models.Q()
target_date_list = (
self.append_all_shared_articles_query(
self.root_page.article_page_model.objects.filter(search_filter)
)
.order_by("-union_date")
.live()
.values_list("union_date", flat=True)
)
if not target_date_list:
return []
target_date = target_date_list[0] - relativedelta(months=months_back)
first_day_of_target_month = target_date.replace(day=1)
filter = models.Q(date__gte=first_day_of_target_month) & search_filter
sorted_article_qs = self.get_base_shared_articles_query(filter)
article_data_list = []
current_month_data = self.get_empty_month_data(timezone.now().date())
for article in sorted_article_qs:
if article.date.month != current_month_data["month_number"]:
if len(current_month_data["articles"]) != 0:
# append completed month if it contains any articles
article_data_list.append(current_month_data)
current_month_data = self.get_empty_month_data(article.date)
current_month_data["articles"].append(article)
article_data_list.append(current_month_data) # last iteration
return article_data_list
def get_search_filters(self, request):
filter = models.Q()
if "tag_id" in request.GET:
tag = self.get_filtered_tag(request)
if tag is not None:
filter = filter & models.Q(tags__id=tag.id)
if "q" in request.GET:
filter = filter & models.Q(title__icontains=self.get_search_query(request))
return filter
def get_filtered_tag(self, request) -> Tag | None:
if "tag_id" in request.GET:
try:
return Tag.objects.filter(id=int(request.GET["tag_id"])).first()
except Exception:
pass
return None
def get_search_query(self, request) -> str | None:
if "q" in request.GET:
return request.GET["q"]
def get_context(self, request, get_articles: bool = True, *args, **kwargs):
ctx = super().get_context(request, args, kwargs)
if get_articles:
filtered_tag = self.get_filtered_tag(request)
if filtered_tag is not None:
ctx["filtered_tag"] = filtered_tag
search_query = self.get_search_query(request)
if search_query is not None:
ctx["search_query"] = search_query
search_filter = self.get_search_filters(request)
article_timeline_list = self.get_article_data_list(1, search_filter)
ctx["article_timeline_list"] = article_timeline_list
ctx["show_next_timeline_articles"] = len(
self.get_base_shared_articles_query(search_filter)
) != 0 and (
self.materialize_shared_articles_query(
self.append_all_shared_articles_query(
self.root_page.article_page_model.objects.filter(search_filter)
)
.live()
.order_by("union_date")[:2] # LIMIT 2
)[0]
not in article_timeline_list[-1]["articles"]
)
tags = []
for article in self.root_page.article_page_model.objects.all()[:50]:
for tag in article.tags.all():
if tag in tags:
continue
tags.append(tag)
ctx["tags"] = tags
# meow
return ctx
def get_timeline_articles_response(self, request):
try:
months = int(request.GET.get("months", None))
except ValueError:
months = 1
search_filter = self.get_search_filters(request)
article_timeline_list = self.get_article_data_list(months, search_filter)
context = {"article_timeline_list": article_timeline_list}
data = {
"html": render(
request,
"main/includes/organisms/articles/articles_timeline_list.html",
context,
).content.decode("utf-8"),
"has_next": (
len(self.get_base_shared_articles_query(search_filter)) != 0
and (
self.materialize_shared_articles_query(
self.append_all_shared_articles_query(
self.root_page.article_page_model.objects.filter(
search_filter
)
)
.live()
.order_by("union_date")[:2] # LIMIT 2
)[0]
not in article_timeline_list[-1]["articles"]
)
),
}
return JsonResponse(data=data, safe=False)
@route(r"^sdilene/$", name="shared")
def shared(self, request):
return self.setup_article_page_context(request)
def serve(self, request, *args, **kwargs):
if request.META.get("HTTP_X_REQUESTED_WITH") == "XMLHttpRequest":
if "months" in request.GET:
return self.get_timeline_articles_response(request)
return super().serve(request, *args, **kwargs)
@staticmethod
def get_empty_month_data(date_obj):
return {
"month_number": date_obj.month,
"month_text": MONTH_NAMES[date_obj.month - 1],
"articles": [],
}
class MainArticlePageMixin(
ArticleMixin,
ExtendedMetadataPageMixin,
SubpageMixin,
MetadataPageMixin,
PageInMenuMixin,
Page,
):
### FIELDS
content = StreamField(
[
(
"text",
RichTextBlock(template="main/includes/atoms/text/prose_richtext.html"),
),
("quote", ArticleQuoteBlock()),
("download", ArticleDownloadBlock()),
],
verbose_name="Článek",
blank=True,
use_json_field=True,
)
@property
def tags(self):
# NOTE: Must be implemented
raise NotImplementedError
shared_tags = ClusterTaggableManager(
verbose_name="Tagy pro sdílení mezi weby",
through=SharedTaggedMainArticle,
blank=True,
)
search_fields = ArticleMixin.search_fields + [
index.SearchField("author_page"),
index.FilterField("slug"),
]
### PANELS
content_panels = ArticleMixin.content_panels + [
FieldPanel("author_page"),
FieldPanel("tags"),
FieldPanel("shared_tags"),
]
promote_panels = make_promote_panels(
admin_help.build(admin_help.NO_SEO_TITLE, admin_help.NO_DESCRIPTION_USE_PEREX),
search_image=False,
)
### RELATIONS
parent_page_types = [] # NOTE: Must be implemented
subpage_types = [] # NOTE: Must be implemented
### OTHERS
class Meta:
verbose_name = "Aktualita"
abstract = True
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment