picata 0.0.11__py3-none-any.whl → 0.0.12__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,5 @@
1
1
  """Generic helper-functions."""
2
+
2
3
  # NB: Django's meta-class shenanigans over-complicate type hinting when QuerySets get involved.
3
4
  # pyright: reportAttributeAccessIssue=false
4
5
 
picata/helpers/wagtail.py CHANGED
@@ -1,24 +1,25 @@
1
1
  """Generic helper-functions."""
2
+
2
3
  # NB: Django's meta-class shenanigans over-complicate type hinting when QuerySets get involved.
3
4
  # pyright: reportAttributeAccessIssue=false
4
5
 
5
- from typing import cast
6
+ from typing import Any, cast
6
7
 
7
- from django.http import HttpRequest
8
8
  from wagtail.models import Page
9
9
  from wagtail.query import PageQuerySet
10
10
 
11
11
  from picata.models import TaggedPage
12
+ from picata.typing import UserOrNot
12
13
 
13
14
  from . import get_models_of_type
14
15
 
15
16
  TAGGED_PAGE_TYPES = get_models_of_type(TaggedPage)
16
17
 
17
18
 
18
- def visible_pages_qs(request: HttpRequest) -> PageQuerySet:
19
+ def visible_pages_qs(user: UserOrNot = None, page_qs: PageQuerySet | None = None) -> PageQuerySet:
19
20
  """Return a QuerySet of all pages derived from `Page` visible to the user."""
20
- pages = cast(PageQuerySet, Page.objects.all())
21
- if not request.user.is_authenticated:
21
+ pages = page_qs if page_qs else cast(PageQuerySet, Page.objects.all())
22
+ if not user or not user.is_authenticated:
22
23
  pages = pages.live()
23
24
  return pages
24
25
 
@@ -53,9 +54,9 @@ def filter_pages_by_type(pages: list[Page], page_type_slugs: set[str]) -> list[P
53
54
  return filtered_pages
54
55
 
55
56
 
56
- def page_preview_data(page: Page, request: HttpRequest | None) -> dict[str, str]:
57
+ def page_preview_data(page: Page, user: UserOrNot) -> dict[str, Any]:
57
58
  """Return a dictionary of available publication and preview data for a page."""
58
- page_data = getattr(page, "preview_data", {}).copy()
59
+ page_data = page.get_preview_fields(user) if hasattr(page, "get_preview_fields") else {}
59
60
  if hasattr(page, "get_publication_data"):
60
- page_data.update(page.get_publication_data(request))
61
+ page_data.update(page.get_publication_data())
61
62
  return page_data
@@ -0,0 +1,27 @@
1
+ # Generated by Django 5.1.5 on 2025-02-05 01:16
2
+
3
+ import django.db.models.deletion
4
+ import wagtail.fields
5
+ from django.db import migrations, models
6
+
7
+
8
+ class Migration(migrations.Migration):
9
+
10
+ dependencies = [
11
+ ('picata', '0001_initial'),
12
+ ('wagtailcore', '0094_alter_page_locale'),
13
+ ]
14
+
15
+ operations = [
16
+ migrations.CreateModel(
17
+ name='PostSeries',
18
+ fields=[
19
+ ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
20
+ ('introduction', wagtail.fields.StreamField([('rich_text', 0), ('image', 1)], blank=True, block_lookup={0: ('wagtail.blocks.RichTextBlock', (), {}), 1: ('picata.blocks.WrappedImageChooserBlock', (), {})})),
21
+ ],
22
+ options={
23
+ 'abstract': False,
24
+ },
25
+ bases=('wagtailcore.page',),
26
+ ),
27
+ ]
@@ -0,0 +1,24 @@
1
+ # Generated by Django 5.1.5 on 2025-02-11 02:39
2
+
3
+ import wagtail.fields
4
+ from django.db import migrations
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('picata', '0002_postseries'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AddField(
15
+ model_name='postseries',
16
+ name='summary',
17
+ field=wagtail.fields.RichTextField(blank=True, help_text='A summary to be displayed in previews.'),
18
+ ),
19
+ migrations.AlterField(
20
+ model_name='postseries',
21
+ name='introduction',
22
+ field=wagtail.fields.StreamField([('rich_text', 0), ('code', 3), ('image', 4)], blank=True, block_lookup={0: ('wagtail.blocks.RichTextBlock', (), {}), 1: ('wagtail.blocks.TextBlock', (), {'help_text': None, 'required': True}), 2: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('plaintext', 'Plain Text'), ('bash', 'Bash'), ('css', 'CSS'), ('javascript', 'JavaScript'), ('html', 'HTML'), ('python', 'Python'), ('toml', 'TOML'), ('yaml', 'YAML')], 'required': False}), 3: ('wagtail.blocks.StructBlock', [[('code', 1), ('language', 2)]], {}), 4: ('picata.blocks.WrappedImageChooserBlock', (), {})}, help_text='Content to introduce the series of articles.'),
23
+ ),
24
+ ]
picata/models.py CHANGED
@@ -4,10 +4,11 @@
4
4
  # pyright: reportAttributeAccessIssue=false
5
5
 
6
6
  from collections import OrderedDict
7
- from datetime import timedelta
8
- from typing import Any, ClassVar, cast
7
+ from datetime import datetime, timedelta
8
+ from typing import Any, ClassVar, TypedDict, cast
9
9
 
10
- from django.contrib.auth.models import AnonymousUser, User
10
+ from django.apps import apps
11
+ from django.contrib.auth.models import AbstractUser
11
12
  from django.db.models import (
12
13
  CASCADE,
13
14
  SET_NULL,
@@ -17,15 +18,15 @@ from django.db.models import (
17
18
  SlugField,
18
19
  TextField,
19
20
  )
20
- from django.db.models.functions import Coalesce, ExtractYear
21
+ from django.db.models.functions import Coalesce
21
22
  from django.http import HttpRequest
22
23
  from django.urls import reverse
24
+ from django.utils.timezone import now
23
25
  from modelcluster.contrib.taggit import ClusterTaggableManager
24
26
  from modelcluster.fields import ParentalKey
25
27
  from taggit.models import TagBase, TaggedItemBase
26
28
  from wagtail.admin.panels import FieldPanel, Panel
27
29
  from wagtail.blocks import RichTextBlock
28
- from wagtail.contrib.routable_page.models import RoutablePageMixin
29
30
  from wagtail.contrib.settings.models import BaseSiteSetting, register_setting
30
31
  from wagtail.fields import RichTextField, StreamField
31
32
  from wagtail.images.blocks import ImageChooserBlock
@@ -35,7 +36,7 @@ from wagtail.query import PageQuerySet
35
36
  from wagtail.search import index
36
37
  from wagtail_modeladmin.options import ModelAdmin
37
38
 
38
- from picata.typing import Args, Kwargs
39
+ from picata.typing import Args, Kwargs, UserOrNot
39
40
  from picata.typing.wagtail import PageContext
40
41
 
41
42
  from .blocks import (
@@ -45,6 +46,53 @@ from .blocks import (
45
46
  )
46
47
 
47
48
 
49
+ class ChronoPageQuerySet(PageQuerySet):
50
+ """QuerySet for pages that can be ordered based on dates."""
51
+
52
+ def with_effective_date(self) -> "ChronoPageQuerySet":
53
+ """Annotate pages with 'effective_date' to allow date-based ordering."""
54
+ return self.annotate(
55
+ effective_date=Coalesce("last_published_at", "latest_revision_created_at", now())
56
+ )
57
+
58
+ def by_date(self) -> "ChronoPageQuerySet":
59
+ """Return all pages ordered by descending 'effective_date'."""
60
+ return self.with_effective_date().order_by("-effective_date")
61
+
62
+ def live_for_user(self, user: UserOrNot = None) -> "ChronoPageQuerySet":
63
+ """Filter out non-live pages for non-authenticated users."""
64
+ return self if user and user.is_authenticated else self.live()
65
+
66
+ def descendants_of_page(self, page: Page) -> "ChronoPageQuerySet":
67
+ """Return all Article and PostSeries pages under a given page."""
68
+ from picata.models import Article, PostSeries # Avoid circular imports
69
+
70
+ qs = Page.objects.descendant_of(page).type(Article, PostSeries) # ✅ Correct approach!
71
+ return qs.specific() # Ensures the QuerySet remains correctly typed.
72
+
73
+
74
+ class ChronoPageManager(PageManager.from_queryset(ChronoPageQuerySet)): # type: ignore[misc]
75
+ """Custom manager to ensure QuerySet methods are always available."""
76
+
77
+
78
+ class CorePublicationData(TypedDict):
79
+ """Guaranteed keys for publication data on a page derived from `BasePage`."""
80
+
81
+ live: bool
82
+ url: str | None
83
+ published: str | None
84
+ updated: str | None
85
+ year: int
86
+ list_date: datetime
87
+
88
+
89
+ class BasePublicationData(CorePublicationData, total=False):
90
+ """Publication data that may be included on pages derived from `BasePage`."""
91
+
92
+ latest_draft: str
93
+ draft_url: str
94
+
95
+
48
96
  class BasePageContext(PageContext, total=False):
49
97
  """Return-type for an `Article`'s context dictionary."""
50
98
 
@@ -57,10 +105,11 @@ class BasePageContext(PageContext, total=False):
57
105
 
58
106
 
59
107
  class BasePage(Page):
60
- """Mixin for `Page`-types offering previews of themselves on other `Page`s."""
108
+ """Base for all Picata pages, offering publication and preview data methods."""
61
109
 
62
- @property
63
- def preview_data(self) -> dict[str, Any]:
110
+ objects = ChronoPageManager()
111
+
112
+ def get_preview_fields(self, user: UserOrNot = None) -> dict[str, Any]:
64
113
  """Return a dictionary of data used in previewing this page type."""
65
114
  return {
66
115
  "title": self.seo_title or self.title,
@@ -73,14 +122,12 @@ class BasePage(Page):
73
122
  last_edited = (
74
123
  self.latest_revision.created_at if self.latest_revision else self.last_published_at
75
124
  )
125
+ published, updated = self.first_published_at, self.last_published_at
76
126
  year = (
77
127
  self.first_published_at.year
78
128
  if self.first_published_at
79
- else last_edited.year
80
- if last_edited
81
- else None
129
+ else (last_edited.year if last_edited else now().year)
82
130
  )
83
- published, updated = self.first_published_at, self.last_published_at
84
131
 
85
132
  # Convert datetime objects to strings like "3 Jan, '25", or False, and
86
133
  # give a grace-period of one week for edits before marking the post as "updated"
@@ -97,6 +144,7 @@ class BasePage(Page):
97
144
  "published": published_str,
98
145
  "updated": updated_str,
99
146
  "year": year,
147
+ "list_date": published if published else last_edited if last_edited else now(),
100
148
  }
101
149
 
102
150
  # Add last draft date & preview URL if there's an unpublished draft, for logged-in users
@@ -120,7 +168,7 @@ class BasePage(Page):
120
168
  from picata.helpers.wagtail import page_preview_data
121
169
 
122
170
  context = super().get_context(request, *args, **kwargs)
123
- context.update(page_preview_data(self, request))
171
+ context.update(page_preview_data(self, request.user))
124
172
  return cast(BasePageContext, {**context})
125
173
 
126
174
  class Meta:
@@ -162,9 +210,9 @@ class TaggedPage(BasePage):
162
210
  help_text="Tags for the article.",
163
211
  )
164
212
 
165
- content_panels: ClassVar[list[Panel]] = [
166
- *BasePage.content_panels,
213
+ promote_panels: ClassVar[list[Panel]] = [
167
214
  FieldPanel("tags"),
215
+ *BasePage.promote_panels,
168
216
  ]
169
217
 
170
218
  class Meta:
@@ -273,35 +321,37 @@ class ArticleTypeAdmin(ModelAdmin):
273
321
  search_fields = ("name", "slug") # Fields to include in the search bar
274
322
 
275
323
 
276
- class ArticleContext(BasePageContext):
277
- """Return-type for an `Article`'s context dictionary."""
324
+ class SeriesPostMixinContext(TypedDict, total=False):
325
+ """Potential context data for page including `SeriesPostMixin`."""
278
326
 
279
- content: str
327
+ series: dict[str, Any]
280
328
 
281
329
 
282
- class ArticleQuerySet(PageQuerySet):
283
- """Default `QuerySet` for all `Article`-type pages."""
330
+ class SeriesPostMixin:
331
+ """Mixin for articles that belong to a PostSeries."""
284
332
 
285
- def with_effective_date(self) -> PageQuerySet:
286
- """Annotate with 'effective_date' to allow date-ordering to consider recent drafts."""
287
- return self.annotate(
288
- effective_date=Coalesce("first_published_at", "latest_revision_created_at")
289
- )
333
+ def get_context(
334
+ self, request: HttpRequest, *args: Args, **kwargs: Kwargs
335
+ ) -> SeriesPostMixinContext:
336
+ """Return context about the series this page belongs to (if any)."""
337
+ context = cast(Page, super()).get_context(request, *args, **kwargs)
338
+ parent = context["page"].get_parent()
339
+ PostSeries = apps.get_model("picata", "PostSeries")
340
+ if isinstance(parent, PostSeries):
341
+ context["series"] = parent.get_preview_fields(request.user, relative_to=self)
342
+ return cast(SeriesPostMixinContext, context)
290
343
 
291
- def by_date(self) -> PageQuerySet:
292
- """Return all `Article` pages, ordered by decending "effective" date."""
293
- return self.with_effective_date().order_by("-effective_date")
294
344
 
295
- def live_for_user(self, user: AnonymousUser | User) -> PageQuerySet:
296
- """Filter out non-live pages for non-authenticated users."""
297
- return self if user.is_authenticated else self.live()
345
+ class ArticleContext(SeriesPostMixinContext, BasePageContext):
346
+ """Return-type for an `Article`'s context dictionary."""
347
+
348
+ content: str
298
349
 
299
350
 
300
- class Article(TaggedPage):
351
+ class Article(SeriesPostMixin, TaggedPage):
301
352
  """Class for article-like pages."""
302
353
 
303
354
  template = "picata/article.html"
304
- objects = PageManager.from_queryset(ArticleQuerySet)()
305
355
 
306
356
  tagline: CharField = CharField(
307
357
  blank=True, help_text="A short tagline for the article.", max_length=255
@@ -327,12 +377,16 @@ class Article(TaggedPage):
327
377
  help_text="Select the type of article.",
328
378
  )
329
379
 
380
+ promote_panels: ClassVar[list[Panel]] = [
381
+ FieldPanel("summary"),
382
+ FieldPanel("page_type"),
383
+ *TaggedPage.promote_panels,
384
+ ]
385
+
330
386
  content_panels: ClassVar[list[Panel]] = [
331
387
  *TaggedPage.content_panels,
332
388
  FieldPanel("tagline"),
333
- FieldPanel("summary"),
334
389
  FieldPanel("content"),
335
- FieldPanel("page_type"),
336
390
  ]
337
391
 
338
392
  search_fields: ClassVar[list[index.SearchField]] = [
@@ -344,11 +398,10 @@ class Article(TaggedPage):
344
398
  index.SearchField("page_type"),
345
399
  ]
346
400
 
347
- @property
348
- def preview_data(self) -> dict[str, Any]:
401
+ def get_preview_fields(self, user: UserOrNot = None) -> dict[str, Any]:
349
402
  """Return data required to render a preview of this article."""
350
403
  return {
351
- **super().preview_data,
404
+ **super().get_preview_fields(user),
352
405
  "tagline": self.tagline,
353
406
  "summary": self.summary,
354
407
  "page_type": self.page_type,
@@ -362,17 +415,17 @@ class Article(TaggedPage):
362
415
  return cast(ArticleContext, context)
363
416
 
364
417
 
365
- class PostGroupePageContext(PageContext):
418
+ class PostGroupPageContext(BasePageContext):
366
419
  """Return-type for a `PostGroupPage`'s context dictionary."""
367
420
 
368
- posts: OrderedDict[int, list[dict[str, str]]]
421
+ posts_by_year: OrderedDict[int, list[dict[str, str]]]
369
422
 
370
423
 
371
- class PostGroupPage(RoutablePageMixin, Page):
424
+ class PostGroupPage(BasePage):
372
425
  """A top-level page for grouping various types of posts or articles."""
373
426
 
374
427
  template = "picata/post_listing.html"
375
- subpage_types: ClassVar[list[str]] = ["picata.Article"]
428
+ subpage_types: ClassVar[list[str]] = ["picata.Article", "picata.PostSeries"]
376
429
 
377
430
  intro = RichTextField(blank=True, help_text="An optional introduction to this group.")
378
431
 
@@ -380,30 +433,30 @@ class PostGroupPage(RoutablePageMixin, Page):
380
433
 
381
434
  def get_context(
382
435
  self, request: HttpRequest, *args: Args, **kwargs: Kwargs
383
- ) -> PostGroupePageContext:
436
+ ) -> PostGroupPageContext:
384
437
  """Add a dictionary of posts grouped by year to the context dict."""
385
- children = self.get_children()
386
- if not request.user.is_authenticated:
387
- children = children.live()
388
- children = children.specific()
389
- children = children.annotate(
390
- effective_date=Coalesce("first_published_at", "latest_revision_created_at"),
391
- year_published=ExtractYear("first_published_at"),
438
+ from picata.helpers.wagtail import page_preview_data, visible_pages_qs
439
+
440
+ children = visible_pages_qs(
441
+ cast(AbstractUser, request.user), cast(PageQuerySet, self.get_children())
442
+ ).specific()
443
+
444
+ child_data = sorted(
445
+ [page_preview_data(child, request.user) for child in children],
446
+ key=lambda p: p["list_date"],
447
+ reverse=True,
392
448
  )
393
449
 
394
450
  # Create an OrderedDict grouping posts by year in reverse chronological order
395
451
  posts_by_year: OrderedDict = OrderedDict()
396
- for child in children.order_by("-effective_date"):
397
- post_data = getattr(child, "preview_data", {}).copy()
398
- post_data.update(**child.get_publication_data(request))
399
-
452
+ for child in child_data:
400
453
  # Group posts by year, defaulting to last-draft year if unpublished
401
- if post_data["year"] not in posts_by_year:
402
- posts_by_year[post_data["year"]] = []
403
- posts_by_year[post_data["year"]].append(post_data)
454
+ if child["year"] not in posts_by_year:
455
+ posts_by_year[child["year"]] = []
456
+ posts_by_year[child["year"]].append(child)
404
457
 
405
458
  return cast(
406
- PostGroupePageContext,
459
+ PostGroupPageContext,
407
460
  {**super().get_context(request, *args, **kwargs), "posts_by_year": posts_by_year},
408
461
  )
409
462
 
@@ -484,7 +537,7 @@ class HomePage(BasePage):
484
537
  from picata.helpers.wagtail import page_preview_data
485
538
 
486
539
  recent_posts = Article.objects.live_for_user(request.user).by_date()
487
- recent_posts = [page_preview_data(post, request) for post in recent_posts]
540
+ recent_posts = [page_preview_data(post, request.user) for post in recent_posts]
488
541
 
489
542
  return cast(
490
543
  HomePageContext,
@@ -500,3 +553,86 @@ class HomePage(BasePage):
500
553
  """Declare explicit human-readable names for the page type."""
501
554
 
502
555
  verbose_name = "home page"
556
+
557
+
558
+ class PostSeriesContext(BasePageContext):
559
+ """Return-type for a `PostSeries`'s context dictionary."""
560
+
561
+ introduction: str
562
+
563
+
564
+ class PostSeries(BasePage):
565
+ """A container for a series of related articles."""
566
+
567
+ summary = RichTextField(blank=True, help_text="A summary to be displayed in previews.")
568
+ introduction = StreamField(
569
+ [
570
+ ("rich_text", RichTextBlock()),
571
+ ("code", CodeBlock()),
572
+ ("image", WrappedImageChooserBlock()),
573
+ ],
574
+ blank=True,
575
+ use_json_field=True,
576
+ help_text="Content to introduce the series of articles.",
577
+ )
578
+
579
+ promote_panels: ClassVar[list[Panel]] = [
580
+ FieldPanel("summary"),
581
+ *BasePage.promote_panels,
582
+ ]
583
+
584
+ content_panels: ClassVar[list[FieldPanel]] = [
585
+ *BasePage.content_panels,
586
+ FieldPanel("introduction"),
587
+ ]
588
+
589
+ parent_page_types: ClassVar[list[str]] = ["PostGroupPage"]
590
+ subpage_types: ClassVar[list[str]] = ["Article"]
591
+
592
+ def get_publication_data(self, request: HttpRequest | None = None) -> dict[str, Any]:
593
+ """Return publication data, using the most recent child article's data for sorting."""
594
+ data = super().get_publication_data(request)
595
+ children = (
596
+ Article.objects.child_of(self)
597
+ .by_date()
598
+ .live_for_user(request.user if request else None)
599
+ )
600
+ child_publication_data = [child.get_publication_data(request) for child in children]
601
+
602
+ if child_publication_data:
603
+ latest_child = max(child_publication_data, key=lambda p: p["list_date"])
604
+ data["published"] = latest_child["published"]
605
+ data["updated"] = latest_child["updated"]
606
+ data["list_date"] = latest_child["list_date"]
607
+
608
+ return data
609
+
610
+ def get_preview_fields(
611
+ self, user: UserOrNot = None, relative_to: Page | None = None
612
+ ) -> dict[str, Any]:
613
+ """Return preview data, including a sorted list of child articles as 'parts'."""
614
+ from picata.helpers.wagtail import page_preview_data
615
+
616
+ site = self.get_site()
617
+ data = {
618
+ **super().get_preview_fields(user),
619
+ "summary": self.summary,
620
+ }
621
+ children = list(Article.objects.child_of(self).by_date().live_for_user(user))
622
+ part_previews = [page_preview_data(child, user) for child in children]
623
+ data["url"] = self.relative_url(site)
624
+ data["parts"] = part_previews
625
+ if relative_to and relative_to in children:
626
+ data["this_part"] = children.index(relative_to) + 1
627
+ return data
628
+
629
+ def get_context(self, request: HttpRequest, *args: Args, **kwargs: Kwargs) -> PostSeriesContext:
630
+ """Add content streams and a recent posts list to the context."""
631
+ return cast(
632
+ PostSeriesContext,
633
+ {
634
+ **super().get_context(request, *args, **kwargs),
635
+ **self.get_preview_fields(request.user),
636
+ "introduction": self.introduction,
637
+ },
638
+ )
picata/transformers.py CHANGED
@@ -13,7 +13,8 @@ def add_heading_ids(tree: etree._Element) -> None:
13
13
  return
14
14
 
15
15
  for heading in main[0].xpath(".//h1|//h2|//h3|//h4|//h5|//h6"):
16
- if heading.get("id"):
16
+ # Exclude headings in <nav> tags and those already having an id.
17
+ if heading.xpath("ancestor::nav") or heading.get("id"):
17
18
  continue
18
19
  heading_text = get_full_text(heading)
19
20
  slug = heading_text.lower().replace(" ", "-")
picata/typing/__init__.py CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  from typing import Any, TypedDict
4
4
 
5
+ from django.contrib.auth.models import AbstractBaseUser, AnonymousUser
5
6
  from django.http import HttpRequest
6
7
 
7
8
  # Generic arguments and keyword arguments
@@ -9,6 +10,9 @@ Args = tuple[Any, ...]
9
10
  Kwargs = dict[str, Any]
10
11
 
11
12
 
13
+ UserOrNot = AbstractBaseUser | AnonymousUser | None
14
+
15
+
12
16
  class Context(TypedDict):
13
17
  """Base class for context dicts passed all around the system."""
14
18
 
picata/views.py CHANGED
@@ -88,7 +88,7 @@ def search(request: HttpRequest) -> HttpResponse:
88
88
  results: dict[str, str | list[str] | set[str]] = {}
89
89
 
90
90
  # Base QuerySet for all pages
91
- pages: PageQuerySet = visible_pages_qs(request)
91
+ pages: PageQuerySet = visible_pages_qs(request.user)
92
92
 
93
93
  # Perform search by query
94
94
  query_string = request.GET.get("query")
@@ -119,6 +119,6 @@ def search(request: HttpRequest) -> HttpResponse:
119
119
  specific_pages = []
120
120
 
121
121
  # Enhance pages with preview and publication data
122
- page_previews = [page_preview_data(page, request) for page in specific_pages]
122
+ page_previews = [page_preview_data(page, request.user) for page in specific_pages]
123
123
 
124
124
  return render(request, "picata/search_results.html", {**results, "pages": page_previews})
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: picata
3
- Version: 0.0.11
3
+ Version: 0.0.12
4
4
  Summary: Ada's Wagtail-based CMS & blog
5
5
  Project-URL: Documentation, https://github.com/hipikat/picata#readme
6
6
  Project-URL: Issues, https://github.com/hipikat/picata/issues