Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"wagtail.images",
"wagtail.search",
"wagtail.admin",
"wagtail.contrib.routable_page",
"wagtail",
"wagtailmarkdown",
"modelcluster",
Expand All @@ -123,6 +124,7 @@
"slack",
"testimonials",
"patches",
"pages",
"asciidoctor_sandbox",
]

Expand Down
8 changes: 4 additions & 4 deletions config/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,10 @@
),
]
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
+ [
path("outreach/", include(wagtail_urls)),
path("pages/", include(wagtail_urls)),
]
+ [
# Libraries docs, some HTML parts are re-written
re_path(
Expand Down Expand Up @@ -494,10 +498,6 @@
),
]
+ djdt_urls
+ [
# Wagtail catch-all (must be last!)
path("", include(wagtail_urls)),
]
)

handler404 = "ak.views.custom_404_view"
5 changes: 4 additions & 1 deletion marketing/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,10 @@ class DetailPage(EmailCapturePage):
class OutreachHomePage(Page):
"""A dummy homepage to just return a 404 at the `/outreach/` url"""

parent_page_types = ["wagtailcore.Page"]
parent_page_types = [
"wagtailcore.Page",
"pages.RoutableHomePage",
]
subpage_types = ["marketing.ProgramPageIndex", "marketing.TopicPage"]
max_count = 1 # one container

Expand Down
Empty file added pages/__init__.py
Empty file.
1 change: 1 addition & 0 deletions pages/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Register your models here.
5 changes: 5 additions & 0 deletions pages/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.apps import AppConfig


class PagesConfig(AppConfig):
name = "pages"
29 changes: 29 additions & 0 deletions pages/blocks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from wagtail.blocks import CharBlock
from wagtail.blocks import RichTextBlock
from wagtail.blocks import StructBlock
from wagtail.blocks import StreamBlock
from wagtail.blocks import URLBlock
from wagtail.embeds.blocks import EmbedBlock
from wagtail.images.blocks import ImageChooserBlock
from wagtailmarkdown.blocks import MarkdownBlock


class CustomVideoBlock(StructBlock):
video = EmbedBlock()
thumbnail = ImageChooserBlock()

class Meta:
template = "blocks/custom_video_block.html"


class PollBlock(StreamBlock):
poll_choice = CharBlock(max_length=200)


POST_BLOCKS = [
("rich_text", RichTextBlock()),
("markdown", MarkdownBlock()),
("url", URLBlock()),
("video", CustomVideoBlock(label="Video")),
("poll", PollBlock()),
]
110 changes: 110 additions & 0 deletions pages/management/commands/convert_news_entries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import djclick as click
from wagtail.models import Page
from wagtail.images.models import Image

from pages.models import PostPage
from pages.models import PostIndexPage

from news.models import Video
from news.models import News
from news.models import BlogPost
from news.models import Link
from news.models import Entry

from django.template.defaultfilters import urlize
from django.template.defaultfilters import linebreaks_filter


def get_or_create_page(entry: Entry, index_page: PostIndexPage) -> PostPage:
try:
page = index_page.get_children().get(title=entry.title).specific
except Page.DoesNotExist:
page = PostPage(
title=entry.title,
first_published_at=entry.publish_at,
owner=entry.author,
)
index_page.add_child(instance=page)
return page


def convert_text_content(content: str):
r_content = content
r_content = urlize(r_content)
r_content = linebreaks_filter(r_content)
return r_content


def convert_image(entry: Entry, post_page: PostPage):
image = entry.image
wagtail_image, _ = Image.objects.get_or_create(
title=image.name,
defaults={"width": image.width, "height": image.height, "file": image},
)
post_page.image = wagtail_image
post_page.save()


def basic_conversion(entry: Entry, index_page: PostIndexPage):
print(f"Creating or updating PostPage {entry.title}")
page = get_or_create_page(entry, index_page)
if entry.image:
convert_image(entry, page)
if entry.summary:
page.summary = entry.summary
return page


@click.command()
def command():
post_index_page = PostIndexPage.objects.first()
if not post_index_page:
raise Exception(
"No Post Index Page found. Create one before running this command."
)

blogs_posts = BlogPost.objects.all()
print(f"Creating or updating {blogs_posts.count()} Blog Posts")
for bp in blogs_posts:
page = basic_conversion(bp, post_index_page)
page.content = [
{
"type": "markdown",
"value": convert_text_content(bp.content),
}
]
page.save()
news_posts = News.objects.all()
print(f"Creating or updating {news_posts.count()} News Posts")
for np in news_posts:
page = basic_conversion(np, post_index_page)
page.content = [
{
"type": "markdown",
"value": convert_text_content(np.content),
}
]
page.save()
videos = Video.objects.all()
print(f"Creating or updating {news_posts.count()} Videos")
for video in videos:
page = basic_conversion(video, post_index_page)
page.content = [
{
"type": "video",
"value": {"video": video.external_url},
}
]
page.save()

links = Link.objects.all()
print(f"Creating or updating {links.count()} Links")
for link in links:
page = basic_conversion(link, post_index_page)
page.content = [
{
"type": "url",
"value": link.external_url,
}
]
page.save()
108 changes: 108 additions & 0 deletions pages/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Generated by Django 6.0.2 on 2026-02-19 22:22

import django.db.models.deletion
import modelcluster.fields
import pages.mixins
import wagtail.contrib.routable_page.models
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
("wagtailcore", "0096_referenceindex_referenceindex_source_object_and_more"),
]

operations = [
migrations.CreateModel(
name="ContentTag",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"name",
models.CharField(max_length=100, unique=True, verbose_name="name"),
),
(
"slug",
models.SlugField(
allow_unicode=True,
max_length=100,
unique=True,
verbose_name="slug",
),
),
],
options={
"verbose_name": "content tag",
"verbose_name_plural": "content tags",
},
),
migrations.CreateModel(
name="RoutableHomePage",
fields=[
(
"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",
),
),
],
options={
"abstract": False,
},
bases=(
wagtail.contrib.routable_page.models.RoutablePageMixin,
pages.mixins.FlaggedMixin,
pages.mixins.TaggableMixin,
"wagtailcore.page",
),
),
migrations.CreateModel(
name="TaggedContent",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"content_object",
modelcluster.fields.ParentalKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="tagged_items",
to="wagtailcore.page",
),
),
(
"tag",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="tagged_content",
to="pages.contenttag",
),
),
],
options={
"abstract": False,
},
),
]
25 changes: 25 additions & 0 deletions pages/migrations/0002_routablehomepage_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Generated by Django 6.0.2 on 2026-02-20 14:56

import modelcluster.contrib.taggit
from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("pages", "0001_initial"),
]

operations = [
migrations.AddField(
model_name="routablehomepage",
name="tags",
field=modelcluster.contrib.taggit.ClusterTaggableManager(
blank=True,
help_text="A comma-separated list of tags.",
through="pages.TaggedContent",
to="pages.ContentTag",
verbose_name="Tags",
),
),
]
Loading