diff --git a/constraints.txt b/constraints.txt
index 20e9a025..dac63db4 100644
--- a/constraints.txt
+++ b/constraints.txt
@@ -16,9 +16,9 @@ django-appconf==1.0.5
django-compressor==4.0
django-filter==21.1
django-libsass==0.9
-django-modelcluster==5.3
+django-modelcluster==6.0
django-storages==1.12.3
-django-taggit==1.5.1
+django-taggit==2.1.0
django-treebeard==4.5.1
djangorestframework==3.13.1
docutils==0.15.2
@@ -58,9 +58,9 @@ tqdm==4.64.0
typed-environment-configuration==0.1.4
typepy==0.2.5
urllib3==1.26.9
-wagtail==2.15.5
+wagtail==3.0.1
wagtail-markdown==0.8.0
-wagtail-orderable==1.0.3
+wagtail-orderable==1.0.4
webencodings==0.5.1
Willow==1.4.1
xlrd==2.0.1
diff --git a/ietf/bibliography/management/commands/fix_BMI_page_links.py b/ietf/bibliography/management/commands/fix_BMI_page_links.py
index 3815bb80..30841957 100644
--- a/ietf/bibliography/management/commands/fix_BMI_page_links.py
+++ b/ietf/bibliography/management/commands/fix_BMI_page_links.py
@@ -1,72 +1,71 @@
-from django.core.management.base import BaseCommand, CommandError
-
import re
-from tqdm import tqdm
-
from bs4 import BeautifulSoup
+from django.core.management.base import BaseCommand, CommandError
+from tqdm import tqdm
+from wagtail.models import Page
-from wagtail.core.models import Page
-
-from ietf.standard.models import StandardPage
from ietf.blog.models import BlogPage
from ietf.iesg_statement.models import IESGStatementPage
-
from ietf.snippets.models import RFC, Charter, WorkingGroup
+from ietf.standard.models import StandardPage
+
def change_links(page):
- unfound_rfcs=set()
+ unfound_rfcs = set()
- rfc_pattern = re.compile('^ *\\[? *RFC *(\\d{4}) *\\]? *$')
+ rfc_pattern = re.compile("^ *\\[? *RFC *(\\d{4}) *\\]? *$")
- group_pattern1 = re.compile('\((\w+)\)\\xa0[Ww]orking [Gg]roup$')
- group_pattern2 = re.compile(' *(\w+) +[Ww]orking [Gg]roup$')
+ group_pattern1 = re.compile("\((\w+)\)\\xa0[Ww]orking [Gg]roup$")
+ group_pattern2 = re.compile(" *(\w+) +[Ww]orking [Gg]roup$")
for fieldname in page.CONTENT_FIELD_MAP.keys():
- field = getattr(page,fieldname)
+ field = getattr(page, fieldname)
for item in field.stream_data:
- if not item['type'] in ('paragraph','raw_html'):
+ if not item["type"] in ("paragraph", "raw_html"):
continue
- soup = BeautifulSoup(item['value'], 'html.parser')
- for tag in soup.find_all('a',string=rfc_pattern):
- if 'href' in tag.attrs:
+ soup = BeautifulSoup(item["value"], "html.parser")
+ for tag in soup.find_all("a", string=rfc_pattern):
+ if "href" in tag.attrs:
continue
rfc_number = rfc_pattern.match(tag.string)[1]
rfc = RFC.objects.filter(rfc=rfc_number).first()
if not rfc:
unfound_rfcs.add(rfc_number)
continue
- tag['data-app'] = 'snippets'
- tag['data-linktype'] = 'rfc'
- tag['data-id'] = str(rfc.pk)
+ tag["data-app"] = "snippets"
+ tag["data-linktype"] = "rfc"
+ tag["data-id"] = str(rfc.pk)
for pattern in (group_pattern1, group_pattern2):
- for tag in soup.find_all('a',string=pattern):
- if 'href' in tag.attrs:
+ for tag in soup.find_all("a", string=pattern):
+ if "href" in tag.attrs:
continue
- if 'linktype' in tag.attrs and tag['linktype']!='charter':
+ if "linktype" in tag.attrs and tag["linktype"] != "charter":
continue
if not pattern.search(tag.string):
- print ("Search failure", tag.string, pattern)
- print (page.url_path)
+ print("Search failure", tag.string, pattern)
+ print(page.url_path)
continue
acronym = pattern.search(tag.string)[1].lower()
- charter = Charter.objects.filter(working_group__acronym=acronym).first()
+ charter = Charter.objects.filter(
+ working_group__acronym=acronym
+ ).first()
if charter:
- tag['data-app'] = 'snippets'
- tag['data-linktype'] = 'charter'
- tag['data-id'] = str(charter.pk)
+ tag["data-app"] = "snippets"
+ tag["data-linktype"] = "charter"
+ tag["data-id"] = str(charter.pk)
else:
group = WorkingGroup.objects.filter(acronym=acronym).first()
if group:
- tag['data-app'] = 'snippets'
- tag['data-linktype'] = 'workinggroup'
- tag['data-id'] = str(group.pk)
+ tag["data-app"] = "snippets"
+ tag["data-linktype"] = "workinggroup"
+ tag["data-id"] = str(group.pk)
else:
- print("Nothing found in ",str(tag))
+ print("Nothing found in ", str(tag))
print("Acronym was", acronym)
continue
- item['value'] = str(soup)
+ item["value"] = str(soup)
all_the_fields = list(page.CONTENT_FIELD_MAP.keys())
all_the_fields.extend(list(page.CONTENT_FIELD_MAP.values()))
@@ -74,31 +73,32 @@ def change_links(page):
return unfound_rfcs
+
class Command(BaseCommand):
- help = 'Replace tag parameters on pages using BibliographyMixin'
+ help = "Replace tag parameters on pages using BibliographyMixin"
def add_arguments(self, parser):
- parser.add_argument('url_paths', nargs='*', type=str)
+ parser.add_argument("url_paths", nargs="*", type=str)
def handle(self, *args, **options):
- unfound_rfcs=set()
+ unfound_rfcs = set()
- if options['url_paths']:
- for url_path in options['url_paths']:
+ if options["url_paths"]:
+ for url_path in options["url_paths"]:
page = Page.objects.filter(url_path=url_path).first()
if not page:
- CommandError('Page with path '+url_path+' not found')
+ CommandError("Page with path " + url_path + " not found")
unfound_rfcs.update(change_links(page.specific))
else:
- print ('Standard Pages:')
+ print("Standard Pages:")
for page in tqdm(StandardPage.objects.all()):
unfound_rfcs.update(change_links(page))
- print ('Blog Pages:')
+ print("Blog Pages:")
for page in tqdm(BlogPage.objects.all()):
unfound_rfcs.update(change_links(page))
- print ('IESGStatement Pages:')
+ print("IESGStatement Pages:")
for page in tqdm(IESGStatementPage.objects.all()):
unfound_rfcs.update(change_links(page))
if unfound_rfcs:
- print ("Unfound RFCs", unfound_rfcs)
+ print("Unfound RFCs", unfound_rfcs)
diff --git a/ietf/bibliography/models.py b/ietf/bibliography/models.py
index 4343b32a..c456fe1f 100644
--- a/ietf/bibliography/models.py
+++ b/ietf/bibliography/models.py
@@ -1,14 +1,12 @@
from bs4 import BeautifulSoup, NavigableString
-
-from django.template import TemplateDoesNotExist
-from django.template.loader import get_template
+from django.apps import apps
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
-from django.db import models
-from django.apps import apps
from django.core.exceptions import ObjectDoesNotExist
-
-from wagtail.core.models import Page
+from django.db import models
+from django.template import TemplateDoesNotExist
+from django.template.loader import get_template
+from wagtail.models import Page
from ietf.utils import OrderedSet
@@ -26,7 +24,7 @@ class BibliographyItem(models.Model):
)
page = models.ForeignKey(
Page,
- related_name='bibliography_items',
+ related_name="bibliography_items",
help_text="The page that this item links to.",
on_delete=models.CASCADE,
)
@@ -41,23 +39,22 @@ class BibliographyItem(models.Model):
max_length=127,
help_text='The "value" with which this item was created, eg. "3514" in [[rfc:3514]].',
)
- content_long_title = models.CharField(
- max_length=127,
- blank=True
- )
+ content_long_title = models.CharField(max_length=127, blank=True)
content_title = models.CharField(
max_length=127,
help_text='The link title for this item, eg. "RFC 7168" for [[rfc:7168]].',
)
content_type = models.ForeignKey(
ContentType,
- blank=True, null=True,
+ blank=True,
+ null=True,
on_delete=models.CASCADE,
)
object_id = models.PositiveIntegerField(
- blank=True, null=True,
+ blank=True,
+ null=True,
)
- content_object = GenericForeignKey('content_type', 'object_id')
+ content_object = GenericForeignKey("content_type", "object_id")
def render_title(self):
if not self.content_object:
@@ -73,10 +70,10 @@ def render_uri(self):
@property
def link(self):
- soup = BeautifulSoup("", 'html5lib')
- link = soup.new_tag('a', href="#bibliography" + str(self.ordering))
- link['class'] = "bibliography-reference"
- link['data-ordering'] = str(self.ordering)
+ soup = BeautifulSoup("", "html5lib")
+ link = soup.new_tag("a", href="#bibliography" + str(self.ordering))
+ link["class"] = "bibliography-reference"
+ link["data-ordering"] = str(self.ordering)
link.insert(0, NavigableString(self.content_title))
return link
@@ -91,24 +88,21 @@ def render(self, request=None):
else:
try:
template = get_template(
- 'bibliography/item_{}.html'.format(self.content_key)
+ "bibliography/item_{}.html".format(self.content_key)
)
except TemplateDoesNotExist:
template = None
BibliographyItem.TEMPLATE_CACHE[self.content_key] = template
if template:
- return template.render({
- 'object': self.content_object,
- 'item': self
- }, request=request)
+ return template.render(
+ {"object": self.content_object, "item": self}, request=request
+ )
else:
return str(object)
def __str__(self):
- return "Bibliography Item #{}: {}".format(
- self.ordering, self.content_object
- )
+ return "Bibliography Item #{}: {}".format(self.ordering, self.content_object)
class BibliographyMixin(models.Model):
@@ -125,59 +119,70 @@ def save(self, *args, **kwargs):
# Don't update prepared content fields if none of the source fields are being updated (e.g. when saving a draft)
# NB - We have to update all prepared and source fields or none, as there's no way of determining which field a
# given BibliographyItem appears in.
- update_fields = kwargs.get('update_fields')
+ update_fields = kwargs.get("update_fields")
recreate_bibliography_items = True
if update_fields is not None:
- source_fields_being_updated = [source_field in update_fields for source_field in self.CONTENT_FIELD_MAP.values()]
- prepared_fields_being_updated = [prepared_field in update_fields for prepared_field in self.CONTENT_FIELD_MAP.keys()]
+ source_fields_being_updated = [
+ source_field in update_fields
+ for source_field in self.CONTENT_FIELD_MAP.values()
+ ]
+ prepared_fields_being_updated = [
+ prepared_field in update_fields
+ for prepared_field in self.CONTENT_FIELD_MAP.keys()
+ ]
if any(source_fields_being_updated) or any(prepared_fields_being_updated):
- if not all(source_fields_being_updated) or not all(prepared_fields_being_updated):
- raise ValueError('Either all prepared content fields must be updated or none')
+ if not all(source_fields_being_updated) or not all(
+ prepared_fields_being_updated
+ ):
+ raise ValueError(
+ "Either all prepared content fields must be updated or none"
+ )
else:
recreate_bibliography_items = False
if recreate_bibliography_items:
self.bibliography_items.all().delete()
- all_content = "".join([
- str(getattr(self, content_field)) or '' for content_field
- in self.CONTENT_FIELD_MAP.keys()
- ])
- all_soup = BeautifulSoup(all_content, 'html.parser')
+ all_content = "".join(
+ [
+ str(getattr(self, content_field)) or ""
+ for content_field in self.CONTENT_FIELD_MAP.keys()
+ ]
+ )
+ all_soup = BeautifulSoup(all_content, "html.parser")
subsoups = {
prepared_content_field: BeautifulSoup(
- str(getattr(self, content_field)) or '', 'html.parser'
- ) for content_field, prepared_content_field in
- self.CONTENT_FIELD_MAP.items()
+ str(getattr(self, content_field)) or "", "html.parser"
+ )
+ for content_field, prepared_content_field in self.CONTENT_FIELD_MAP.items()
}
- tags = OrderedSet(all_soup.find_all('a', attrs={'data-app': True}))
+ tags = OrderedSet(all_soup.find_all("a", attrs={"data-app": True}))
for tag in tags:
- app = tag['data-app']
- model = tag['data-linktype']
- obj_id = tag['data-id']
+ app = tag["data-app"]
+ model = tag["data-linktype"]
+ obj_id = tag["data-id"]
try:
- obj = apps.get_model(
- app_label=app,
- model_name=model
- ).objects.get(pk=obj_id)
+ obj = apps.get_model(app_label=app, model_name=model).objects.get(
+ pk=obj_id
+ )
try:
long_title = obj.long_title
except AttributeError:
long_title = ""
object_details = {
- 'content_object': obj,
- 'content_long_title': long_title,
- 'content_title': obj.__str__()
+ "content_object": obj,
+ "content_long_title": long_title,
+ "content_title": obj.__str__(),
}
except ObjectDoesNotExist:
object_details = {
- 'content_object': None,
- 'content_long_title': "",
- 'content_title': '(removed)'
+ "content_object": None,
+ "content_long_title": "",
+ "content_title": "(removed)",
}
item = BibliographyItem.objects.create(
page=self,
@@ -187,11 +192,14 @@ def save(self, *args, **kwargs):
**object_details
)
for soup in subsoups.values():
- for t in soup.find_all('a', attrs={
- 'data-app': app,
- 'data-linktype': model,
- 'data-id': obj_id
- }):
+ for t in soup.find_all(
+ "a",
+ attrs={
+ "data-app": app,
+ "data-linktype": model,
+ "data-id": obj_id,
+ },
+ ):
t.replaceWith(item.link)
for prepared_content_field, prepared_soup in subsoups.items():
diff --git a/ietf/bibliography/views.py b/ietf/bibliography/views.py
index 1f897190..181584e4 100644
--- a/ietf/bibliography/views.py
+++ b/ietf/bibliography/views.py
@@ -1,52 +1,65 @@
-from django.shortcuts import render
from django.contrib.contenttypes.models import ContentType
from django.db.models import Count
-
-from wagtail.core.models import Page
+from django.shortcuts import render
+from wagtail.models import Page
from .models import BibliographyItem
def referenced_types(request):
- content_types = BibliographyItem.objects.exclude(
- content_type=None
- ).order_by().values_list(
- 'content_type'
- ).distinct().annotate(num=Count('content_type')).order_by('-num')
- return render(request, 'bibliography/referenced_types.html', {
- 'types': [
- (ContentType.objects.get(pk=type_id), count)
- for type_id, count in content_types
- ]
- })
+ content_types = (
+ BibliographyItem.objects.exclude(content_type=None)
+ .order_by()
+ .values_list("content_type")
+ .distinct()
+ .annotate(num=Count("content_type"))
+ .order_by("-num")
+ )
+ return render(
+ request,
+ "bibliography/referenced_types.html",
+ {
+ "types": [
+ (ContentType.objects.get(pk=type_id), count)
+ for type_id, count in content_types
+ ]
+ },
+ )
def referenced_objects(request, content_type_id):
content_type = ContentType.objects.get(pk=content_type_id)
- object_ids = BibliographyItem.objects.filter(
- content_type=content_type_id
- ).order_by().values_list('object_id').distinct().annotate(
- num=Count('object_id')
- ).order_by('-num')
- return render(request, 'bibliography/referenced_objects.html', {
- 'title': content_type._meta.verbose_name,
- 'content_type_id': content_type_id,
- 'objects': [
- (content_type.get_object_for_this_type(id=object_id), count)
- for object_id, count in object_ids
- ]
- })
+ object_ids = (
+ BibliographyItem.objects.filter(content_type=content_type_id)
+ .order_by()
+ .values_list("object_id")
+ .distinct()
+ .annotate(num=Count("object_id"))
+ .order_by("-num")
+ )
+ return render(
+ request,
+ "bibliography/referenced_objects.html",
+ {
+ "title": content_type._meta.verbose_name,
+ "content_type_id": content_type_id,
+ "objects": [
+ (content_type.get_object_for_this_type(id=object_id), count)
+ for object_id, count in object_ids
+ ],
+ },
+ )
def referencing_pages(request, content_type_id, object_id):
content_type = ContentType.objects.get(pk=content_type_id)
obj = content_type.get_object_for_this_type(id=object_id)
page_ids = BibliographyItem.objects.filter(
- content_type=content_type_id,
- object_id=object_id
- ).values_list('page', flat=True)
+ content_type=content_type_id, object_id=object_id
+ ).values_list("page", flat=True)
pages = Page.objects.filter(pk__in=page_ids)
- return render(request, 'bibliography/referencing_pages.html', {
- 'title': obj.__str__(),
- 'pages': pages
- })
+ return render(
+ request,
+ "bibliography/referencing_pages.html",
+ {"title": obj.__str__(), "pages": pages},
+ )
diff --git a/ietf/bibliography/wagtail_hooks.py b/ietf/bibliography/wagtail_hooks.py
index 2e32274f..4007ce38 100644
--- a/ietf/bibliography/wagtail_hooks.py
+++ b/ietf/bibliography/wagtail_hooks.py
@@ -1,12 +1,13 @@
from django.urls import reverse
-
-from wagtail.core import hooks
+from wagtail import hooks
from wagtail.admin.menu import MenuItem
-@hooks.register('register_admin_menu_item')
+@hooks.register("register_admin_menu_item")
def register_references_menu_item():
- return MenuItem('References',
- reverse('referenced_types'),
- classnames='icon icon-folder-inverse',
- order=10000)
+ return MenuItem(
+ "References",
+ reverse("referenced_types"),
+ classnames="icon icon-folder-inverse",
+ order=10000,
+ )
diff --git a/ietf/blog/feeds.py b/ietf/blog/feeds.py
index 4a55e787..438259bc 100644
--- a/ietf/blog/feeds.py
+++ b/ietf/blog/feeds.py
@@ -1,6 +1,7 @@
from django.contrib.syndication.views import Feed
from django.db.models.functions import Coalesce
-from wagtail.core.models import Site
+from wagtail.models import Site
+
from ..blog.models import BlogPage
from ..utils.models import FeedSettings
@@ -15,8 +16,11 @@ def __call__(self, request, *args, **kwargs):
return super().__call__(request, *args, **kwargs)
def items(self):
- return BlogPage.objects.live().annotate(
- d=Coalesce('date_published', 'first_published_at')).order_by('-d')
+ return (
+ BlogPage.objects.live()
+ .annotate(d=Coalesce("date_published", "first_published_at"))
+ .order_by("-d")
+ )
def item_title(self, item):
return item.title
diff --git a/ietf/blog/migrations/0001_initial.py b/ietf/blog/migrations/0001_initial.py
index 72ebdf08..9033b944 100644
--- a/ietf/blog/migrations/0001_initial.py
+++ b/ietf/blog/migrations/0001_initial.py
@@ -2,15 +2,15 @@
# Generated by Django 1.11.29 on 2020-04-10 18:46
from __future__ import unicode_literals
-from django.db import migrations, models
import django.db.models.deletion
import modelcluster.fields
+import wagtail.blocks
import wagtail.contrib.routable_page.models
import wagtail.contrib.table_block.blocks
-import wagtail.core.blocks
-import wagtail.core.fields
import wagtail.embeds.blocks
+import wagtail.fields
import wagtail.images.blocks
+from django.db import migrations, models
class Migration(migrations.Migration):
@@ -18,55 +18,214 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
- ('wagtailcore', '0040_page_draft_title'),
- ('snippets', '0001_initial'),
- ('images', '0001_initial'),
+ ("wagtailcore", "0040_page_draft_title"),
+ ("snippets", "0001_initial"),
+ ("images", "0001_initial"),
]
operations = [
migrations.CreateModel(
- name='BlogIndexPage',
+ name="BlogIndexPage",
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')),
+ (
+ "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={
- 'verbose_name': 'Blog Index Page',
+ "verbose_name": "Blog Index Page",
},
- bases=(wagtail.contrib.routable_page.models.RoutablePageMixin, 'wagtailcore.page'),
+ bases=(
+ wagtail.contrib.routable_page.models.RoutablePageMixin,
+ "wagtailcore.page",
+ ),
),
migrations.CreateModel(
- name='BlogPage',
+ name="BlogPage",
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')),
- ('social_text', models.CharField(blank=True, help_text='Description of this page as it should appear when shared on social networks, or in Google results', max_length=255)),
- ('date_published', models.DateTimeField(blank=True, help_text='Use this field to override the date that the blog post appears to have been published.', null=True)),
- ('introduction', models.CharField(help_text='The page introduction text.', max_length=511)),
- ('body', wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}))])),
- ('prepared_body', models.TextField(blank=True, help_text='The prepared body content after bibliography styling has been applied. Auto-generated on each save.', null=True)),
- ('author_group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='snippets.Group')),
- ('feed_image', models.ForeignKey(blank=True, help_text='This image will be used in listings and indexes across the site, if no feed image is added, the social image will be used.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')),
- ('social_image', models.ForeignKey(blank=True, help_text="Image to appear alongside 'social text', particularly for sharing on social networks", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')),
+ (
+ "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",
+ ),
+ ),
+ (
+ "social_text",
+ models.CharField(
+ blank=True,
+ help_text="Description of this page as it should appear when shared on social networks, or in Google results",
+ max_length=255,
+ ),
+ ),
+ (
+ "date_published",
+ models.DateTimeField(
+ blank=True,
+ help_text="Use this field to override the date that the blog post appears to have been published.",
+ null=True,
+ ),
+ ),
+ (
+ "introduction",
+ models.CharField(
+ help_text="The page introduction text.", max_length=511
+ ),
+ ),
+ (
+ "body",
+ wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ (
+ "raw_html",
+ wagtail.blocks.RawHTMLBlock(icon="placeholder"),
+ ),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"}
+ ),
+ ),
+ ]
+ ),
+ ),
+ (
+ "prepared_body",
+ models.TextField(
+ blank=True,
+ help_text="The prepared body content after bibliography styling has been applied. Auto-generated on each save.",
+ null=True,
+ ),
+ ),
+ (
+ "author_group",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="snippets.Group",
+ ),
+ ),
+ (
+ "feed_image",
+ models.ForeignKey(
+ blank=True,
+ help_text="This image will be used in listings and indexes across the site, if no feed image is added, the social image will be used.",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
+ (
+ "social_image",
+ models.ForeignKey(
+ blank=True,
+ help_text="Image to appear alongside 'social text', particularly for sharing on social networks",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
],
options={
- 'verbose_name': 'Blog Page',
+ "verbose_name": "Blog Page",
},
- bases=('wagtailcore.page', models.Model),
+ bases=("wagtailcore.page", models.Model),
),
migrations.CreateModel(
- name='BlogPageAuthor',
+ name="BlogPageAuthor",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='snippets.Person')),
- ('page', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='authors', to='blog.BlogPage')),
- ('role', models.ForeignKey(blank=True, help_text="Override the person's current role for this blog post.", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='snippets.Role')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "author",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="snippets.Person",
+ ),
+ ),
+ (
+ "page",
+ modelcluster.fields.ParentalKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="authors",
+ to="blog.BlogPage",
+ ),
+ ),
+ (
+ "role",
+ models.ForeignKey(
+ blank=True,
+ help_text="Override the person's current role for this blog post.",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="snippets.Role",
+ ),
+ ),
],
),
migrations.CreateModel(
- name='BlogPageTopic',
+ name="BlogPageTopic",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('page', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='topics', to='blog.BlogPage')),
- ('topic', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='snippets.Topic')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "page",
+ modelcluster.fields.ParentalKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="topics",
+ to="blog.BlogPage",
+ ),
+ ),
+ (
+ "topic",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="snippets.Topic",
+ ),
+ ),
],
),
]
diff --git a/ietf/blog/migrations/0002_auto_20210325_0442.py b/ietf/blog/migrations/0002_auto_20210325_0442.py
index 1b758bba..ee561a33 100644
--- a/ietf/blog/migrations/0002_auto_20210325_0442.py
+++ b/ietf/blog/migrations/0002_auto_20210325_0442.py
@@ -1,23 +1,43 @@
# Generated by Django 2.2.16 on 2021-03-25 04:42
-from django.db import migrations
+import wagtail.blocks
import wagtail.contrib.table_block.blocks
-import wagtail.core.blocks
-import wagtail.core.fields
import wagtail.embeds.blocks
+import wagtail.fields
import wagtail.images.blocks
+from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
- ('blog', '0001_initial'),
+ ("blog", "0001_initial"),
]
operations = [
migrations.AlterField(
- model_name='blogpage',
- name='body',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))]),
+ model_name="blogpage",
+ name="body",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ]
+ ),
),
]
diff --git a/ietf/blog/migrations/0003_auto_20211101_0113.py b/ietf/blog/migrations/0003_auto_20211101_0113.py
index bf92f984..a006494b 100644
--- a/ietf/blog/migrations/0003_auto_20211101_0113.py
+++ b/ietf/blog/migrations/0003_auto_20211101_0113.py
@@ -1,24 +1,45 @@
# Generated by Django 2.2.19 on 2021-11-01 01:13
-from django.db import migrations
+import wagtail.blocks
import wagtail.contrib.table_block.blocks
-import wagtail.core.blocks
-import wagtail.core.fields
import wagtail.embeds.blocks
+import wagtail.fields
import wagtail.images.blocks
import wagtailmarkdown.blocks
+from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
- ('blog', '0002_auto_20210325_0442'),
+ ("blog", "0002_auto_20210325_0442"),
]
operations = [
migrations.AlterField(
- model_name='blogpage',
- name='body',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('markdown', wagtailmarkdown.blocks.MarkdownBlock(icon='code')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))]),
+ model_name="blogpage",
+ name="body",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("markdown", wagtailmarkdown.blocks.MarkdownBlock(icon="code")),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ]
+ ),
),
]
diff --git a/ietf/blog/migrations/0004_alter_blogpage_body.py b/ietf/blog/migrations/0004_alter_blogpage_body.py
new file mode 100644
index 00000000..dc2a0134
--- /dev/null
+++ b/ietf/blog/migrations/0004_alter_blogpage_body.py
@@ -0,0 +1,24 @@
+# Generated by Django 3.2.13 on 2022-09-02 04:24
+
+from django.db import migrations
+import wagtail.blocks
+import wagtail.contrib.table_block.blocks
+import wagtail.embeds.blocks
+import wagtail.fields
+import wagtail.images.blocks
+import wagtailmarkdown.blocks
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('blog', '0003_auto_20211101_0113'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='blogpage',
+ name='body',
+ field=wagtail.fields.StreamField([('heading', wagtail.blocks.CharBlock(icon='title')), ('paragraph', wagtail.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('markdown', wagtailmarkdown.blocks.MarkdownBlock(icon='code')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], use_json_field=True),
+ ),
+ ]
diff --git a/ietf/blog/models.py b/ietf/blog/models.py
index 17018179..622ba11f 100644
--- a/ietf/blog/models.py
+++ b/ietf/blog/models.py
@@ -1,40 +1,33 @@
from datetime import datetime
from functools import partial
+from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.db.models.functions import Coalesce
from django.http import Http404
-from django.shortcuts import redirect, get_object_or_404
-from django.core.exceptions import ObjectDoesNotExist
+from django.shortcuts import get_object_or_404, redirect
from django.utils import functional
from django.utils.safestring import mark_safe
-
from modelcluster.fields import ParentalKey
-
-from wagtail.core.models import Page, Site
-from wagtail.core.fields import StreamField
-from wagtail.snippets.edit_handlers import (
- SnippetChooserPanel
-)
-from wagtail.search import index
-from wagtail.admin.edit_handlers import (
- StreamFieldPanel, FieldPanel, InlinePanel
-)
+from wagtail.admin.panels import FieldPanel, InlinePanel
from wagtail.contrib.routable_page.models import RoutablePageMixin, route
+from wagtail.fields import StreamField
+from wagtail.models import Page, Site
+from wagtail.search import index
from ..bibliography.models import BibliographyMixin
-from ..utils.models import FeedSettings, PromoteMixin
+from ..snippets.models import Topic
from ..utils.blocks import StandardBlock
-from ..snippets.models import Topic
+from ..utils.models import FeedSettings, PromoteMixin
def ordered_live_annotated_blogs(sibling=None):
- blogs = BlogPage.objects.live().prefetch_related('authors')
+ blogs = BlogPage.objects.live().prefetch_related("authors")
if sibling:
blogs = blogs.sibling_of(sibling)
- blogs = blogs.annotate(
- d=Coalesce('date_published', 'first_published_at')
- ).order_by('-d')
+ blogs = blogs.annotate(d=Coalesce("date_published", "first_published_at")).order_by(
+ "-d"
+ )
return blogs
@@ -53,36 +46,34 @@ def parse_date_search_input(date):
def build_filter_text(**kwargs):
if any(kwargs):
text_fragments = []
- if kwargs.get('topic'):
+ if kwargs.get("topic"):
+ text_fragments.append("{}".format(kwargs.get("topic")))
+ if kwargs.get("secondary_topic"): # for legacy URI support
text_fragments.append(
- '{}'.format(kwargs.get('topic'))
- )
- if kwargs.get('secondary_topic'): # for legacy URI support
+ "{}".format(kwargs.get("secondary_topic"))
+ )
+ if kwargs.get("date_from") and kwargs.get("date_to"):
text_fragments.append(
- '{}'.format(kwargs.get('secondary_topic'))
+ "dates between {} & {}".format(
+ kwargs["date_from"], kwargs["date_to"]
)
- if kwargs.get('date_from') and kwargs.get('date_to'):
+ )
+ elif kwargs.get("date_from"):
text_fragments.append(
- 'dates between {} & {}'.format(
- kwargs['date_from'], kwargs['date_to']
- )
+ "dates after {}".format(kwargs["date_from"])
+ )
+ elif kwargs.get("date_to"):
+ text_fragments.append(
+ "dates before {}".format(kwargs["date_to"])
)
- elif kwargs.get('date_from'):
- text_fragments.append('dates after {}'.format(
- kwargs['date_from']
- ))
- elif kwargs.get('date_to'):
- text_fragments.append('dates before {}'.format(
- kwargs['date_to']
- ))
- return ', '.join(text_fragments)
+ return ", ".join(text_fragments)
else:
return ""
parameter_functions_map = {
- 'date_from': [parse_date_search_input, filter_pages_by_date_from],
- 'date_to': [parse_date_search_input, filter_pages_by_date_to]
+ "date_from": [parse_date_search_input, filter_pages_by_date_from],
+ "date_to": [parse_date_search_input, filter_pages_by_date_to],
}
@@ -91,19 +82,15 @@ class BlogPageTopic(models.Model):
A through model from :model:`blog.BlogPage`
to :model:`snippets.Topic`
"""
- page = ParentalKey(
- 'blog.BlogPage',
- related_name='topics'
- )
+
+ page = ParentalKey("blog.BlogPage", related_name="topics")
topic = models.ForeignKey(
- 'snippets.Topic',
- related_name='+',
+ "snippets.Topic",
+ related_name="+",
on_delete=models.CASCADE,
)
- panels = [
- SnippetChooserPanel('topic')
- ]
+ panels = [FieldPanel("topic")]
class BlogPageAuthor(models.Model):
@@ -111,27 +98,27 @@ class BlogPageAuthor(models.Model):
A through model from :model:`blog.BlogPage`
to :model:`snippets.Person`
"""
- page = ParentalKey(
- 'blog.BlogPage',
- related_name='authors'
- )
+
+ page = ParentalKey("blog.BlogPage", related_name="authors")
author = models.ForeignKey(
- 'snippets.Person',
+ "snippets.Person",
on_delete=models.CASCADE,
- related_name='+',
- null=True, blank=True,
+ related_name="+",
+ null=True,
+ blank=True,
)
role = models.ForeignKey(
- 'snippets.Role',
- null=True, blank=True,
+ "snippets.Role",
+ null=True,
+ blank=True,
on_delete=models.SET_NULL,
- related_name='+',
- help_text="Override the person's current role for this blog post."
+ related_name="+",
+ help_text="Override the person's current role for this blog post.",
)
panels = [
- SnippetChooserPanel('author'),
- SnippetChooserPanel('role'),
+ FieldPanel("author"),
+ FieldPanel("role"),
]
@@ -139,34 +126,37 @@ class BlogPage(Page, BibliographyMixin, PromoteMixin):
"""
A page for the IETF's news and commentary.
"""
+
author_group = models.ForeignKey(
- 'snippets.Group',
- null=True, blank=True,
+ "snippets.Group",
+ null=True,
+ blank=True,
on_delete=models.SET_NULL,
- related_name='+',
+ related_name="+",
)
date_published = models.DateTimeField(
- null=True, blank=True,
+ null=True,
+ blank=True,
help_text="Use this field to override the date that the "
- "blog post appears to have been published."
+ "blog post appears to have been published.",
)
introduction = models.CharField(
- max_length=511,
- help_text="The page introduction text."
+ max_length=511, help_text="The page introduction text."
)
- body = StreamField(StandardBlock())
+ body = StreamField(StandardBlock(), use_json_field=True)
search_fields = Page.search_fields + [
- index.SearchField('introduction'),
- index.SearchField('body'),
+ index.SearchField("introduction"),
+ index.SearchField("body"),
]
# for bibliography
prepared_body = models.TextField(
- blank=True, null=True,
+ blank=True,
+ null=True,
help_text="The prepared body content after bibliography styling has been applied. Auto-generated on each save.",
)
- CONTENT_FIELD_MAP = {'body': 'prepared_body'}
+ CONTENT_FIELD_MAP = {"body": "prepared_body"}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -187,14 +177,20 @@ def date(self):
def next(self):
if not self.date:
return None
- after = sorted([p for p in self.siblings if p.date > self.date], key=lambda o:o.date)
+ after = sorted(
+ [p for p in self.siblings if p.date > self.date], key=lambda o: o.date
+ )
return after and after[0] or None
@property
def previous(self):
if not self.date:
return None
- before = sorted([p for p in self.siblings if p.date < self.date], key=lambda o:o.date, reverse=True)
+ before = sorted(
+ [p for p in self.siblings if p.date < self.date],
+ key=lambda o: o.date,
+ reverse=True,
+ )
return before and before[0] or None
def coalesced_published_date(self):
@@ -207,9 +203,13 @@ def feed_text(self):
@functional.cached_property
def siblings(self):
"""Published siblings that match filter_topic, most recent first"""
- qs = self.__class__.objects.live().sibling_of(self).exclude(pk=self.pk).annotate(
- d=Coalesce('date_published', 'first_published_at')
- ).order_by('-d')
+ qs = (
+ self.__class__.objects.live()
+ .sibling_of(self)
+ .exclude(pk=self.pk)
+ .annotate(d=Coalesce("date_published", "first_published_at"))
+ .order_by("-d")
+ )
if self.filter_topic:
qs = qs.filter(topics__topic=self.filter_topic)
return qs
@@ -230,8 +230,9 @@ def get_context(self, request, *args, **kwargs):
related_object = functions[0](search_query)
siblings = functions[1](siblings, related_object)
query_string += "%s=%s&" % (parameter, search_query)
- filter_text_builder = partial(filter_text_builder,
- **{parameter: related_object.__str__()})
+ filter_text_builder = partial(
+ filter_text_builder, **{parameter: related_object.__str__()}
+ )
except (ValueError, ObjectDoesNotExist):
pass
@@ -239,7 +240,7 @@ def get_context(self, request, *args, **kwargs):
if self.filter_topic:
if filter_text:
- filter_text = ','.join([self.filter_topic.title, filter_text])
+ filter_text = ",".join([self.filter_topic.title, filter_text])
else:
filter_text = self.filter_topic.title
@@ -247,65 +248,69 @@ def get_context(self, request, *args, **kwargs):
if siblings:
filter_text = mark_safe("You have filtered by " + filter_text)
else:
- filter_text = mark_safe("No results for " + filter_text + ", showing latest")
+ filter_text = mark_safe(
+ "No results for " + filter_text + ", showing latest"
+ )
context.update(
parent_url=self.get_parent().url,
- filter_text = filter_text,
- filter_topic = self.filter_topic,
+ filter_text=filter_text,
+ filter_topic=self.filter_topic,
siblings=siblings[:max_siblings_to_show],
- topics=BlogPageTopic.objects.all().values_list(
- 'topic__pk', 'topic__title'
- ).distinct(),
+ topics=BlogPageTopic.objects.all()
+ .values_list("topic__pk", "topic__title")
+ .distinct(),
query_string=query_string,
- blog_feed_title=feed_settings.blog_feed_title
+ blog_feed_title=feed_settings.blog_feed_title,
)
return context
def serve(self, request, *args, **kwargs):
- topic_id = request.GET.get('topic')
+ topic_id = request.GET.get("topic")
if not topic_id:
- topic_id = request.GET.get('secondary_topic') # For legacy URI support
+ topic_id = request.GET.get("secondary_topic") # For legacy URI support
if topic_id:
try:
topic_id = int(topic_id)
except ValueError:
raise Http404
- filter_topic = get_object_or_404(Topic,id=topic_id)
- query_string_segments=[]
+ filter_topic = get_object_or_404(Topic, id=topic_id)
+ query_string_segments = []
for parameter, function in parameter_functions_map.items():
search_query = request.GET.get(parameter)
if search_query:
- query_string_segments.append('%s=%s' % (parameter, search_query))
- query_string = '&'.join(query_string_segments)
- target_url = self.get_parent().specific.reverse_subpage('redirect_first',args=(filter_topic.slug,))
+ query_string_segments.append("%s=%s" % (parameter, search_query))
+ query_string = "&".join(query_string_segments)
+ target_url = self.get_parent().specific.reverse_subpage(
+ "redirect_first", args=(filter_topic.slug,)
+ )
if query_string:
- target_url = target_url + '?' + query_string
+ target_url = target_url + "?" + query_string
return redirect(target_url)
else:
return super().serve(request, *args, **kwargs)
def serve_preview(self, request, mode_name):
- """ This is another hack to overcome the MRO issue we were seeing """
+ """This is another hack to overcome the MRO issue we were seeing"""
return BibliographyMixin.serve_preview(self, request, mode_name)
class Meta:
verbose_name = "Blog Page"
+
BlogPage.content_panels = Page.content_panels + [
- InlinePanel('authors', label="Authors"),
- SnippetChooserPanel('author_group'),
- FieldPanel('date_published'),
- FieldPanel('introduction'),
- StreamFieldPanel('body'),
- InlinePanel('topics', label="Topics"),
+ InlinePanel("authors", label="Authors"),
+ FieldPanel("author_group"),
+ FieldPanel("date_published"),
+ FieldPanel("introduction"),
+ FieldPanel("body"),
+ InlinePanel("topics", label="Topics"),
]
BlogPage.promote_panels = Page.promote_panels + PromoteMixin.panels
class BlogIndexPage(RoutablePageMixin, Page):
-
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.filter_topic = None
@@ -316,49 +321,53 @@ def get_context(self, request):
if self.filter_topic:
entry_qs = entry_qs.filter(topics__topic=self.filter_topic)
entry_qs = entry_qs.annotate(
- coalesced_published_date=Coalesce('date_published', 'first_published_at')
- ).order_by('-coalesced_published_date')
- context['entries'] = entry_qs
- context['topics'] = sorted(set([p.topic for p in BlogPageTopic.objects.all()]),key=lambda x:x.title)
+ coalesced_published_date=Coalesce("date_published", "first_published_at")
+ ).order_by("-coalesced_published_date")
+ context["entries"] = entry_qs
+ context["topics"] = sorted(
+ set([p.topic for p in BlogPageTopic.objects.all()]), key=lambda x: x.title
+ )
return context
- @route(r'^all/$')
+ @route(r"^all/$")
def all_entries(self, request, *args, **kwargs):
return super().serve(request, *args, **kwargs)
- @route(r'^([-\w]+)/all/$')
+ @route(r"^([-\w]+)/all/$")
def filtered_entries(self, request, slug, *args, **kwargs):
- self.filter_topic = get_object_or_404(Topic,slug=slug)
+ self.filter_topic = get_object_or_404(Topic, slug=slug)
return super().serve(request, *args, **kwargs)
- @route(r'^([-\w]+)/$')
- @route(r'^$')
+ @route(r"^([-\w]+)/$")
+ @route(r"^$")
def redirect_first(self, request, slug=None, *args, **kwargs):
# IESG statements were moved under the IESG about/groups page. Queries to the
# base /blog/ page that used a query string to filter for IESG statements can't
# be redirected through ordinary redirection, so we're doing it here.
- if request.GET.get('primary_topic')=='7':
- query_string = ''
- topic = request.GET.get('secondary_topic')
+ if request.GET.get("primary_topic") == "7":
+ query_string = ""
+ topic = request.GET.get("secondary_topic")
if topic:
- query_string = query_string + 'topic=' + topic
- date_from = request.GET.get('date_from')
+ query_string = query_string + "topic=" + topic
+ date_from = request.GET.get("date_from")
if date_from:
- separator = '&' if query_string else ''
- query_string = query_string + separator + 'date_from=' + date_from
- date_to = request.GET.get('date_to')
+ separator = "&" if query_string else ""
+ query_string = query_string + separator + "date_from=" + date_from
+ date_to = request.GET.get("date_to")
if date_to:
- separator = '&' if query_string else ''
- query_string = query_string + separator + 'date_to' + date_to
- target_url = '/about/groups/iesg/statements'
+ separator = "&" if query_string else ""
+ query_string = query_string + separator + "date_to" + date_to
+ target_url = "/about/groups/iesg/statements"
if query_string:
- target_url = target_url + '?' + query_string
+ target_url = target_url + "?" + query_string
return redirect(target_url)
else:
if slug:
self.filter_topic = Topic.objects.filter(slug=slug).first()
if not self.filter_topic:
- blog_page = get_object_or_404(BlogPage.objects.prefetch_related('authors'), slug=slug)
+ blog_page = get_object_or_404(
+ BlogPage.objects.prefetch_related("authors"), slug=slug
+ )
return blog_page.serve(request, *args, **kwargs)
blogs = ordered_live_annotated_blogs()
@@ -379,7 +388,7 @@ def redirect_first(self, request, slug=None, *args, **kwargs):
query_string += "%s=%s&" % (parameter, search_query)
except (ValueError, ObjectDoesNotExist):
pass
-
+
if blogs:
first_blog = blogs.first()
@@ -388,10 +397,9 @@ def redirect_first(self, request, slug=None, *args, **kwargs):
return first_blog.serve(request, *args, **kwargs)
+ search_fields = Page.search_fields + []
- search_fields = []
-
- subpage_types = ['blog.BlogPage']
+ subpage_types = ["blog.BlogPage"]
class Meta:
verbose_name = "Blog Index Page"
diff --git a/ietf/blog/tests.py b/ietf/blog/tests.py
index f01437f4..a447e5ad 100644
--- a/ietf/blog/tests.py
+++ b/ietf/blog/tests.py
@@ -1,10 +1,10 @@
-from django.test import TestCase
from datetime import datetime, timedelta
-from .models import BlogPage, BlogIndexPage
-from ..home.models import HomePage
+from django.test import TestCase
+from wagtail.models import Page, Site
-from wagtail.core.models import Page, Site
+from ..home.models import HomePage
+from .models import BlogIndexPage, BlogPage
class BlogTests(TestCase):
@@ -12,12 +12,12 @@ def setUp(self):
root = Page.get_first_root_node()
home = HomePage(
- slug = 'homepageslug',
- title = 'home page title',
- heading = 'home page heading',
- introduction = 'home page introduction',
- request_for_comments_section_body = 'rfc section body',
- working_groups_section_body = 'wg section body',
+ slug="homepageslug",
+ title="home page title",
+ heading="home page heading",
+ introduction="home page introduction",
+ request_for_comments_section_body="rfc section body",
+ working_groups_section_body="wg section body",
)
root.add_child(instance=home)
@@ -25,59 +25,58 @@ def setUp(self):
Site.objects.all().delete()
Site.objects.create(
- hostname='localhost',
- root_page = home,
+ hostname="localhost",
+ root_page=home,
is_default_site=True,
- site_name='testingsitename',
+ site_name="testingsitename",
)
self.blog_index = BlogIndexPage(
- slug = 'blog',
- title = 'blog index title',
+ slug="blog",
+ title="blog index title",
)
- home.add_child(instance = self.blog_index)
+ home.add_child(instance=self.blog_index)
now = datetime.utcnow()
self.otherblog = BlogPage(
- slug = 'otherpost',
- title = 'other title',
- introduction = 'other introduction',
- body = 'other body',
- date_published = (now - timedelta(minutes = 10))
+ slug="otherpost",
+ title="other title",
+ introduction="other introduction",
+ body="other body",
+ date_published=(now - timedelta(minutes=10)),
)
- self.blog_index.add_child(instance = self.otherblog)
+ self.blog_index.add_child(instance=self.otherblog)
self.otherblog.save
self.prevblog = BlogPage(
- slug = 'prevpost',
- title = 'prev title',
- introduction = 'prev introduction',
- body = 'prev body',
- date_published = (now - timedelta(minutes = 5))
+ slug="prevpost",
+ title="prev title",
+ introduction="prev introduction",
+ body="prev body",
+ date_published=(now - timedelta(minutes=5)),
)
- self.blog_index.add_child(instance = self.prevblog)
+ self.blog_index.add_child(instance=self.prevblog)
self.prevblog.save()
-
self.blog = BlogPage(
- slug = 'blogpost',
- title = 'blog title',
- introduction = 'blog introduction',
- body = 'blog body',
- first_published_at = (now + timedelta(minutes=1))
+ slug="blogpost",
+ title="blog title",
+ introduction="blog introduction",
+ body="blog body",
+ first_published_at=(now + timedelta(minutes=1)),
)
- self.blog_index.add_child(instance = self.blog)
+ self.blog_index.add_child(instance=self.blog)
self.blog.save()
self.nextblog = BlogPage(
- slug = 'nextpost',
- title = 'next title',
- introduction = 'next introduction',
- body = 'next body',
- first_published_at = (now + timedelta(minutes=5))
+ slug="nextpost",
+ title="next title",
+ introduction="next introduction",
+ body="next body",
+ first_published_at=(now + timedelta(minutes=5)),
)
- self.blog_index.add_child(instance = self.nextblog)
+ self.blog_index.add_child(instance=self.nextblog)
self.nextblog.save()
def test_blog(self):
diff --git a/ietf/context_processors.py b/ietf/context_processors.py
index f0a77b80..e2f1e900 100644
--- a/ietf/context_processors.py
+++ b/ietf/context_processors.py
@@ -37,7 +37,7 @@ def global_pages(request):
"BLOG_INDEX": BlogIndexPage.objects.first(),
"MENU": menu(),
"SECONDARY_MENU": secondary_menu(),
- "BASE_URL": getattr(settings, "BASE_URL", ""),
+ "BASE_URL": getattr(settings, "WAGTAILADMIN_BASE_URL", ""),
"DEBUG": getattr(settings, "DEBUG", ""),
"FB_APP_ID": getattr(settings, "FB_APP_ID", ""),
}
diff --git a/ietf/events/migrations/0001_initial.py b/ietf/events/migrations/0001_initial.py
index da60b6c6..d22eddf6 100644
--- a/ietf/events/migrations/0001_initial.py
+++ b/ietf/events/migrations/0001_initial.py
@@ -2,17 +2,18 @@
# Generated by Django 1.11.29 on 2020-04-10 18:46
from __future__ import unicode_literals
-from django.db import migrations, models
import django.db.models.deletion
-import ietf.snippets.models
import modelcluster.fields
+import wagtail.blocks
import wagtail.contrib.table_block.blocks
-import wagtail.core.blocks
-import wagtail.core.fields
import wagtail.documents.blocks
import wagtail.embeds.blocks
+import wagtail.fields
import wagtail.images.blocks
import wagtail.snippets.blocks
+from django.db import migrations, models
+
+import ietf.snippets.models
class Migration(migrations.Migration):
@@ -20,73 +21,384 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
- ('wagtailcore', '0040_page_draft_title'),
- ('images', '0001_initial'),
- ('snippets', '0001_initial'),
+ ("wagtailcore", "0040_page_draft_title"),
+ ("images", "0001_initial"),
+ ("snippets", "0001_initial"),
]
operations = [
migrations.CreateModel(
- name='EventListingPage',
+ name="EventListingPage",
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')),
- ('social_text', models.CharField(blank=True, help_text='Description of this page as it should appear when shared on social networks, or in Google results', max_length=255)),
- ('introduction', models.CharField(blank=True, max_length=511)),
- ('feed_image', models.ForeignKey(blank=True, help_text='This image will be used in listings and indexes across the site, if no feed image is added, the social image will be used.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')),
- ('social_image', models.ForeignKey(blank=True, help_text="Image to appear alongside 'social text', particularly for sharing on social networks", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')),
+ (
+ "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",
+ ),
+ ),
+ (
+ "social_text",
+ models.CharField(
+ blank=True,
+ help_text="Description of this page as it should appear when shared on social networks, or in Google results",
+ max_length=255,
+ ),
+ ),
+ ("introduction", models.CharField(blank=True, max_length=511)),
+ (
+ "feed_image",
+ models.ForeignKey(
+ blank=True,
+ help_text="This image will be used in listings and indexes across the site, if no feed image is added, the social image will be used.",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
+ (
+ "social_image",
+ models.ForeignKey(
+ blank=True,
+ help_text="Image to appear alongside 'social text', particularly for sharing on social networks",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
],
options={
- 'abstract': False,
+ "abstract": False,
},
- bases=('wagtailcore.page', models.Model),
+ bases=("wagtailcore.page", models.Model),
),
migrations.CreateModel(
- name='EventListingPagePromotedEvent',
+ name="EventListingPagePromotedEvent",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('page', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='promoted_events', to='events.EventListingPage')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "page",
+ modelcluster.fields.ParentalKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="promoted_events",
+ to="events.EventListingPage",
+ ),
+ ),
],
),
migrations.CreateModel(
- name='EventPage',
+ name="EventPage",
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')),
- ('social_text', models.CharField(blank=True, help_text='Description of this page as it should appear when shared on social networks, or in Google results', max_length=255)),
- ('start_date', models.DateField(blank=True, help_text='The start date date of the event.', null=True)),
- ('end_date', models.DateField(blank=True, help_text='The end date of the event.', null=True)),
- ('introduction', models.CharField(help_text='The introduction for the event page. Limited to 511 characters.', max_length=200)),
- ('body', wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}))])),
- ('venue_section_title', models.CharField(blank=True, default='Meeting venue information', max_length=255)),
- ('venue', wagtail.core.fields.StreamField([('address_line', wagtail.core.blocks.CharBlock(classname='full title'))], blank=True)),
- ('extras', wagtail.core.fields.StreamField([('extra', wagtail.core.blocks.CharBlock(classname='full title'))], blank=True)),
- ('reservation_name', models.CharField(blank=True, max_length=255)),
- ('room_rates', wagtail.core.fields.StreamField([('room_rate', wagtail.core.blocks.CharBlock(classname='full title')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}))], blank=True)),
- ('reservations_open', models.DateField(blank=True, null=True)),
- ('contact_details', wagtail.core.fields.StreamField([('contact_detail', wagtail.core.blocks.CharBlock(classname='full title'))], blank=True)),
- ('key_details', wagtail.core.fields.StreamField([('item', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.CharBlock()), ('link_group', wagtail.core.blocks.StreamBlock([('link', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.CharBlock()), ('link_external', wagtail.core.blocks.URLBlock(required=False)), ('link_page', wagtail.core.blocks.PageChooserBlock(required=False)), ('link_document', wagtail.documents.blocks.DocumentChooserBlock(required=False))]))]))]))], blank=True)),
- ('key_details_expanded', models.BooleanField(default=False, help_text='Show the key details items expanded when the page first loads')),
- ('sponsors', wagtail.core.fields.StreamField([('sponsor_category', wagtail.core.blocks.StructBlock([('category_title', wagtail.core.blocks.CharBlock()), ('sponsor_group', wagtail.core.blocks.StreamBlock([('sponsor', wagtail.snippets.blocks.SnippetChooserBlock(ietf.snippets.models.Sponsor))]))]))], blank=True)),
- ('listing_location', models.CharField(blank=True, help_text='Add a short location name to appear on the event listing.', max_length=255)),
- ('feed_image', models.ForeignKey(blank=True, help_text='This image will be used in listings and indexes across the site, if no feed image is added, the social image will be used.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')),
- ('main_image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')),
- ('social_image', models.ForeignKey(blank=True, help_text="Image to appear alongside 'social text', particularly for sharing on social networks", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')),
+ (
+ "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",
+ ),
+ ),
+ (
+ "social_text",
+ models.CharField(
+ blank=True,
+ help_text="Description of this page as it should appear when shared on social networks, or in Google results",
+ max_length=255,
+ ),
+ ),
+ (
+ "start_date",
+ models.DateField(
+ blank=True,
+ help_text="The start date date of the event.",
+ null=True,
+ ),
+ ),
+ (
+ "end_date",
+ models.DateField(
+ blank=True, help_text="The end date of the event.", null=True
+ ),
+ ),
+ (
+ "introduction",
+ models.CharField(
+ help_text="The introduction for the event page. Limited to 511 characters.",
+ max_length=200,
+ ),
+ ),
+ (
+ "body",
+ wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ (
+ "raw_html",
+ wagtail.blocks.RawHTMLBlock(icon="placeholder"),
+ ),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"}
+ ),
+ ),
+ ]
+ ),
+ ),
+ (
+ "venue_section_title",
+ models.CharField(
+ blank=True, default="Meeting venue information", max_length=255
+ ),
+ ),
+ (
+ "venue",
+ wagtail.fields.StreamField(
+ [
+ (
+ "address_line",
+ wagtail.blocks.CharBlock(classname="full title"),
+ )
+ ],
+ blank=True,
+ ),
+ ),
+ (
+ "extras",
+ wagtail.fields.StreamField(
+ [("extra", wagtail.blocks.CharBlock(classname="full title"))],
+ blank=True,
+ ),
+ ),
+ ("reservation_name", models.CharField(blank=True, max_length=255)),
+ (
+ "room_rates",
+ wagtail.fields.StreamField(
+ [
+ (
+ "room_rate",
+ wagtail.blocks.CharBlock(classname="full title"),
+ ),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"}
+ ),
+ ),
+ ],
+ blank=True,
+ ),
+ ),
+ ("reservations_open", models.DateField(blank=True, null=True)),
+ (
+ "contact_details",
+ wagtail.fields.StreamField(
+ [
+ (
+ "contact_detail",
+ wagtail.blocks.CharBlock(classname="full title"),
+ )
+ ],
+ blank=True,
+ ),
+ ),
+ (
+ "key_details",
+ wagtail.fields.StreamField(
+ [
+ (
+ "item",
+ wagtail.blocks.StructBlock(
+ [
+ ("title", wagtail.blocks.CharBlock()),
+ (
+ "link_group",
+ wagtail.blocks.StreamBlock(
+ [
+ (
+ "link",
+ wagtail.blocks.StructBlock(
+ [
+ (
+ "title",
+ wagtail.blocks.CharBlock(),
+ ),
+ (
+ "link_external",
+ wagtail.blocks.URLBlock(
+ required=False
+ ),
+ ),
+ (
+ "link_page",
+ wagtail.blocks.PageChooserBlock(
+ required=False
+ ),
+ ),
+ (
+ "link_document",
+ wagtail.documents.blocks.DocumentChooserBlock(
+ required=False
+ ),
+ ),
+ ]
+ ),
+ )
+ ]
+ ),
+ ),
+ ]
+ ),
+ )
+ ],
+ blank=True,
+ ),
+ ),
+ (
+ "key_details_expanded",
+ models.BooleanField(
+ default=False,
+ help_text="Show the key details items expanded when the page first loads",
+ ),
+ ),
+ (
+ "sponsors",
+ wagtail.fields.StreamField(
+ [
+ (
+ "sponsor_category",
+ wagtail.blocks.StructBlock(
+ [
+ ("category_title", wagtail.blocks.CharBlock()),
+ (
+ "sponsor_group",
+ wagtail.blocks.StreamBlock(
+ [
+ (
+ "sponsor",
+ wagtail.snippets.blocks.SnippetChooserBlock(
+ ietf.snippets.models.Sponsor
+ ),
+ )
+ ]
+ ),
+ ),
+ ]
+ ),
+ )
+ ],
+ blank=True,
+ ),
+ ),
+ (
+ "listing_location",
+ models.CharField(
+ blank=True,
+ help_text="Add a short location name to appear on the event listing.",
+ max_length=255,
+ ),
+ ),
+ (
+ "feed_image",
+ models.ForeignKey(
+ blank=True,
+ help_text="This image will be used in listings and indexes across the site, if no feed image is added, the social image will be used.",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
+ (
+ "main_image",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
+ (
+ "social_image",
+ models.ForeignKey(
+ blank=True,
+ help_text="Image to appear alongside 'social text', particularly for sharing on social networks",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
],
options={
- 'abstract': False,
+ "abstract": False,
},
- bases=('wagtailcore.page', models.Model),
+ bases=("wagtailcore.page", models.Model),
),
migrations.CreateModel(
- name='EventPageHost',
+ name="EventPageHost",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('host', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='snippets.Sponsor')),
- ('page', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='hosts', to='events.EventPage')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "host",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="snippets.Sponsor",
+ ),
+ ),
+ (
+ "page",
+ modelcluster.fields.ParentalKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="hosts",
+ to="events.EventPage",
+ ),
+ ),
],
),
migrations.AddField(
- model_name='eventlistingpagepromotedevent',
- name='promoted_event',
- field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='events.EventPage'),
+ model_name="eventlistingpagepromotedevent",
+ name="promoted_event",
+ field=models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="events.EventPage",
+ ),
),
]
diff --git a/ietf/events/migrations/0002_auto_20210325_0442.py b/ietf/events/migrations/0002_auto_20210325_0442.py
index c593a35f..5a964237 100644
--- a/ietf/events/migrations/0002_auto_20210325_0442.py
+++ b/ietf/events/migrations/0002_auto_20210325_0442.py
@@ -1,23 +1,43 @@
# Generated by Django 2.2.16 on 2021-03-25 04:42
-from django.db import migrations
+import wagtail.blocks
import wagtail.contrib.table_block.blocks
-import wagtail.core.blocks
-import wagtail.core.fields
import wagtail.embeds.blocks
+import wagtail.fields
import wagtail.images.blocks
+from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
- ('events', '0001_initial'),
+ ("events", "0001_initial"),
]
operations = [
migrations.AlterField(
- model_name='eventpage',
- name='body',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))]),
+ model_name="eventpage",
+ name="body",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ]
+ ),
),
]
diff --git a/ietf/events/migrations/0004_auto_20211101_0113.py b/ietf/events/migrations/0004_auto_20211101_0113.py
index 4f4f8b2e..8952e0bb 100644
--- a/ietf/events/migrations/0004_auto_20211101_0113.py
+++ b/ietf/events/migrations/0004_auto_20211101_0113.py
@@ -1,24 +1,45 @@
# Generated by Django 2.2.19 on 2021-11-01 01:13
-from django.db import migrations
+import wagtail.blocks
import wagtail.contrib.table_block.blocks
-import wagtail.core.blocks
-import wagtail.core.fields
import wagtail.embeds.blocks
+import wagtail.fields
import wagtail.images.blocks
import wagtailmarkdown.blocks
+from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
- ('events', '0003_auto_20210704_2343'),
+ ("events", "0003_auto_20210704_2343"),
]
operations = [
migrations.AlterField(
- model_name='eventpage',
- name='body',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('markdown', wagtailmarkdown.blocks.MarkdownBlock(icon='code')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))]),
+ model_name="eventpage",
+ name="body",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("markdown", wagtailmarkdown.blocks.MarkdownBlock(icon="code")),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ]
+ ),
),
]
diff --git a/ietf/events/migrations/0005_auto_20220902_0524.py b/ietf/events/migrations/0005_auto_20220902_0524.py
new file mode 100644
index 00000000..bb51e7c6
--- /dev/null
+++ b/ietf/events/migrations/0005_auto_20220902_0524.py
@@ -0,0 +1,57 @@
+# Generated by Django 3.2.13 on 2022-09-02 04:24
+
+from django.db import migrations
+import ietf.snippets.models
+import wagtail.blocks
+import wagtail.contrib.table_block.blocks
+import wagtail.documents.blocks
+import wagtail.embeds.blocks
+import wagtail.fields
+import wagtail.images.blocks
+import wagtail.snippets.blocks
+import wagtailmarkdown.blocks
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('events', '0004_auto_20211101_0113'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='eventpage',
+ name='body',
+ field=wagtail.fields.StreamField([('heading', wagtail.blocks.CharBlock(icon='title')), ('paragraph', wagtail.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('markdown', wagtailmarkdown.blocks.MarkdownBlock(icon='code')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], use_json_field=True),
+ ),
+ migrations.AlterField(
+ model_name='eventpage',
+ name='contact_details',
+ field=wagtail.fields.StreamField([('contact_detail', wagtail.blocks.CharBlock(form_classname='full title'))], blank=True, use_json_field=True),
+ ),
+ migrations.AlterField(
+ model_name='eventpage',
+ name='extras',
+ field=wagtail.fields.StreamField([('extra', wagtail.blocks.CharBlock(form_classname='full title'))], blank=True, use_json_field=True),
+ ),
+ migrations.AlterField(
+ model_name='eventpage',
+ name='key_details',
+ field=wagtail.fields.StreamField([('item', wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock()), ('link_group', wagtail.blocks.StreamBlock([('link', wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock()), ('link_external', wagtail.blocks.URLBlock(required=False)), ('link_page', wagtail.blocks.PageChooserBlock(required=False)), ('link_document', wagtail.documents.blocks.DocumentChooserBlock(required=False))]))]))]))], blank=True, use_json_field=True),
+ ),
+ migrations.AlterField(
+ model_name='eventpage',
+ name='room_rates',
+ field=wagtail.fields.StreamField([('room_rate', wagtail.blocks.CharBlock(form_classname='full title')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}))], blank=True, use_json_field=True),
+ ),
+ migrations.AlterField(
+ model_name='eventpage',
+ name='sponsors',
+ field=wagtail.fields.StreamField([('sponsor_category', wagtail.blocks.StructBlock([('category_title', wagtail.blocks.CharBlock()), ('sponsor_group', wagtail.blocks.StreamBlock([('sponsor', wagtail.snippets.blocks.SnippetChooserBlock(ietf.snippets.models.Sponsor))]))]))], blank=True, use_json_field=True),
+ ),
+ migrations.AlterField(
+ model_name='eventpage',
+ name='venue',
+ field=wagtail.fields.StreamField([('address_line', wagtail.blocks.CharBlock(form_classname='full title'))], blank=True, use_json_field=True),
+ ),
+ ]
diff --git a/ietf/events/models.py b/ietf/events/models.py
index 9be4bd00..1e8f80a3 100644
--- a/ietf/events/models.py
+++ b/ietf/events/models.py
@@ -1,36 +1,32 @@
from datetime import datetime
from django.db import models
-
from modelcluster.fields import ParentalKey
-
-from wagtail.core.models import Page
-from wagtail.images.edit_handlers import ImageChooserPanel
-from wagtail.core.fields import StreamField
-from wagtail.core import blocks
-from wagtail.contrib.table_block.blocks import TableBlock
-from wagtail.admin.edit_handlers import (
- FieldPanel, StreamFieldPanel, PageChooserPanel, InlinePanel
+from wagtail import blocks
+from wagtail.admin.panels import (
+ FieldPanel,
+ InlinePanel,
)
-from wagtail.snippets.edit_handlers import (
- SnippetChooserPanel
+from wagtail.blocks import (
+ CharBlock,
+ PageChooserBlock,
+ StreamBlock,
+ StructBlock,
+ URLBlock,
)
+from wagtail.contrib.table_block.blocks import TableBlock
+from wagtail.documents.blocks import DocumentChooserBlock
+from wagtail.fields import StreamField
+from wagtail.models import Page
from wagtail.snippets.blocks import SnippetChooserBlock
-from wagtail.core.blocks import (
- CharBlock, URLBlock, PageChooserBlock,
- StructBlock, StreamBlock
-)
-from wagtail.documents.blocks import (
- DocumentChooserBlock
-)
from ..snippets.models import Sponsor
-from ..utils.models import PromoteMixin
from ..utils.blocks import StandardBlock
-
+from ..utils.models import PromoteMixin
# Links
+
class LinkBlock(StructBlock):
title = CharBlock()
link_external = URLBlock(required=False)
@@ -39,13 +35,13 @@ class LinkBlock(StructBlock):
def get_context(self, value, parent_context=None):
context = super(LinkBlock, self).get_context(value, parent_context)
- if value['link_page']:
- link = value['link_page'].url
- elif value['link_document']:
- link = value['link_document'].url
+ if value["link_page"]:
+ link = value["link_page"].url
+ elif value["link_document"]:
+ link = value["link_document"].url
else:
- link = value['link_external']
- context.update(link=link, title=value['title'])
+ link = value["link_external"]
+ context.update(link=link, title=value["title"])
return context
class Meta:
@@ -63,6 +59,7 @@ class NamedLinkGroupBlock(StructBlock):
# Sponsors
+
class SponsorGroupBlock(StreamBlock):
sponsor = SnippetChooserBlock(Sponsor)
@@ -74,25 +71,23 @@ class SponsorCategoryBlock(StructBlock):
# Hosts
+
class EventPageHost(models.Model):
- page = ParentalKey(
- 'events.EventPage',
- related_name='hosts'
- )
+ page = ParentalKey("events.EventPage", related_name="hosts")
host = models.ForeignKey(
- 'snippets.Sponsor',
- null=True, blank=True,
+ "snippets.Sponsor",
+ null=True,
+ blank=True,
on_delete=models.SET_NULL,
- related_name='+'
+ related_name="+",
)
- panels = [
- SnippetChooserPanel('host')
- ]
+ panels = [FieldPanel("host")]
# Pages
+
class EventPage(Page, PromoteMixin):
"""
A page that describes the IETF's events.
@@ -101,141 +96,136 @@ class EventPage(Page, PromoteMixin):
single block streamfields to allow items to be added and removed and to
allow arbitrary nesting of Panels.
"""
+
start_date = models.DateField(
- null=True, blank=True,
- help_text="The start date date of the event."
+ null=True, blank=True, help_text="The start date date of the event."
)
end_date = models.DateField(
- null=True, blank=True,
- help_text="The end date of the event."
+ null=True, blank=True, help_text="The end date of the event."
)
introduction = models.CharField(
max_length=511,
- help_text="The introduction for the event page. "
- "Limited to 511 characters."
+ help_text="The introduction for the event page. " "Limited to 511 characters.",
)
- body = StreamField(StandardBlock())
+ body = StreamField(StandardBlock(), use_json_field=True)
main_image = models.ForeignKey(
- 'images.IETFImage',
- null=True, blank=True,
+ "images.IETFImage",
+ null=True,
+ blank=True,
on_delete=models.SET_NULL,
- related_name='+',
+ related_name="+",
)
venue_section_title = models.CharField(
- max_length=255,
- default="Meeting venue information",
- blank=True
+ max_length=255, default="Meeting venue information", blank=True
+ )
+ venue = StreamField(
+ [("address_line", blocks.CharBlock(classname="full title"))], blank=True, use_json_field=True
+ )
+ extras = StreamField(
+ [("extra", blocks.CharBlock(classname="full title"))], blank=True, use_json_field=True
)
- venue = StreamField([
- ('address_line', blocks.CharBlock(classname="full title"))
- ], blank=True)
- extras = StreamField([
- ('extra', blocks.CharBlock(classname="full title"))
- ], blank=True)
reservation_name = models.CharField(max_length=255, blank=True)
- room_rates = StreamField([
- ('room_rate', blocks.CharBlock(classname="full title")),
- ('table', TableBlock(table_options={'renderer': 'html'}))
- ], blank=True)
- reservations_open = models.DateField(
- null=True, blank=True
+ room_rates = StreamField(
+ [
+ ("room_rate", blocks.CharBlock(classname="full title")),
+ ("table", TableBlock(table_options={"renderer": "html"})),
+ ],
+ blank=True,
+ use_json_field=True,
+ )
+ reservations_open = models.DateField(null=True, blank=True)
+ contact_details = StreamField(
+ [("contact_detail", blocks.CharBlock(classname="full title"))], blank=True, use_json_field=True
)
- contact_details = StreamField([
- ('contact_detail', blocks.CharBlock(classname="full title"))
- ], blank=True)
- key_details = StreamField([
- ('item', NamedLinkGroupBlock())
- ], blank=True)
+ key_details = StreamField([("item", NamedLinkGroupBlock())], blank=True, use_json_field=True)
key_details_expanded = models.BooleanField(
default=False,
help_text="Show the key details items expanded when the page first loads",
)
- sponsors = StreamField([
- ('sponsor_category', SponsorCategoryBlock())
- ], blank=True)
+ sponsors = StreamField([("sponsor_category", SponsorCategoryBlock())], blank=True, use_json_field=True)
listing_location = models.CharField(
max_length=255,
blank=True,
- help_text="Add a short location name to appear on the event listing."
+ help_text="Add a short location name to appear on the event listing.",
)
@property
def siblings(self):
- return self.get_siblings().live().public().filter(
- show_in_menus=True).specific()
+ return self.get_siblings().live().public().filter(show_in_menus=True).specific()
EventPage.content_panels = Page.content_panels + [
- FieldPanel('start_date'),
- FieldPanel('end_date'),
- FieldPanel('introduction'),
- StreamFieldPanel('body'),
- ImageChooserPanel('main_image'),
- FieldPanel('venue_section_title'),
- StreamFieldPanel('venue'),
- StreamFieldPanel('extras'),
- FieldPanel('reservation_name'),
- StreamFieldPanel('room_rates'),
- FieldPanel('reservations_open'),
- StreamFieldPanel('contact_details'),
-
- FieldPanel('key_details_expanded'),
- StreamFieldPanel('key_details'),
- InlinePanel('hosts', label="Hosts"),
- StreamFieldPanel('sponsors')
+ FieldPanel("start_date"),
+ FieldPanel("end_date"),
+ FieldPanel("introduction"),
+ FieldPanel("body"),
+ FieldPanel("main_image"),
+ FieldPanel("venue_section_title"),
+ FieldPanel("venue"),
+ FieldPanel("extras"),
+ FieldPanel("reservation_name"),
+ FieldPanel("room_rates"),
+ FieldPanel("reservations_open"),
+ FieldPanel("contact_details"),
+ FieldPanel("key_details_expanded"),
+ FieldPanel("key_details"),
+ InlinePanel("hosts", label="Hosts"),
+ FieldPanel("sponsors"),
]
-EventPage.promote_panels = Page.promote_panels + PromoteMixin.panels + [
- FieldPanel('listing_location')
-]
+EventPage.promote_panels = (
+ Page.promote_panels + PromoteMixin.panels + [FieldPanel("listing_location")]
+)
class EventListingPagePromotedEvent(models.Model):
- page = ParentalKey(
- 'events.EventListingPage',
- related_name='promoted_events'
- )
+ page = ParentalKey("events.EventListingPage", related_name="promoted_events")
promoted_event = models.ForeignKey(
- 'events.EventPage',
- related_name='+',
+ "events.EventPage",
+ related_name="+",
on_delete=models.CASCADE,
)
- panels = [
- PageChooserPanel('promoted_event')
- ]
+ panels = [FieldPanel("promoted_event")]
class EventListingPage(Page, PromoteMixin):
- introduction = models.CharField(
- blank=True,
- max_length=511
- )
+ introduction = models.CharField(blank=True, max_length=511)
+
@property
def upcoming_events(self):
- return EventPage.objects.filter(
- end_date__gte=datetime.today()
- ).descendant_of(self).live().exclude(
- pk__in=self.promoted_events.all().values_list(
- 'promoted_event__pk', flat=True
+ return (
+ EventPage.objects.filter(end_date__gte=datetime.today())
+ .descendant_of(self)
+ .live()
+ .exclude(
+ pk__in=self.promoted_events.all().values_list(
+ "promoted_event__pk", flat=True
+ )
)
- ).order_by('start_date')
+ .order_by("start_date")
+ )
@property
def past_events(self):
- return EventPage.objects.filter(
- end_date__lt=datetime.today()
- ).descendant_of(self).live().exclude(
- pk__in=self.promoted_events.all().values_list(
- 'promoted_event__pk', flat=True
+ return (
+ EventPage.objects.filter(end_date__lt=datetime.today())
+ .descendant_of(self)
+ .live()
+ .exclude(
+ pk__in=self.promoted_events.all().values_list(
+ "promoted_event__pk", flat=True
+ )
)
- ).order_by('-start_date')
+ .order_by("-start_date")
+ )
+
EventListingPage.content_panels = Page.content_panels + [
- FieldPanel('introduction'),
- InlinePanel('promoted_events', label="Promoted Events")
+ FieldPanel("introduction"),
+ InlinePanel("promoted_events", label="Promoted Events"),
]
EventListingPage.promote_panels = Page.promote_panels + PromoteMixin.panels
diff --git a/ietf/events/tests.py b/ietf/events/tests.py
index b7cd2194..92f779c9 100644
--- a/ietf/events/tests.py
+++ b/ietf/events/tests.py
@@ -1,23 +1,22 @@
from django.test import TestCase
+from wagtail.models import Page, Site
-from .models import EventListingPage, EventPage
from ..home.models import HomePage
+from .models import EventListingPage, EventPage
-from wagtail.core.models import Page, Site
class EventPageTests(TestCase):
-
def test_event_page(self):
root = Page.get_first_root_node()
home = HomePage(
- slug = 'homepageslug',
- title = 'home page title',
- heading = 'home page heading',
- introduction = 'home page introduction',
- request_for_comments_section_body = 'rfc section body',
- working_groups_section_body = 'wg section body',
+ slug="homepageslug",
+ title="home page title",
+ heading="home page heading",
+ introduction="home page introduction",
+ request_for_comments_section_body="rfc section body",
+ working_groups_section_body="wg section body",
)
root.add_child(instance=home)
@@ -25,25 +24,25 @@ def test_event_page(self):
Site.objects.all().delete()
Site.objects.create(
- hostname='localhost',
- root_page = home,
+ hostname="localhost",
+ root_page=home,
is_default_site=True,
- site_name='testingsitename',
+ site_name="testingsitename",
)
eventlisting = EventListingPage(
- slug = 'eventlisting',
- title = 'event listing page title',
- introduction = 'event listing page introduction'
+ slug="eventlisting",
+ title="event listing page title",
+ introduction="event listing page introduction",
)
- home.add_child(instance = eventlisting)
+ home.add_child(instance=eventlisting)
eventpage = EventPage(
- slug = 'event',
- title = 'event title',
- introduction = 'event introduction',
+ slug="event",
+ title="event title",
+ introduction="event introduction",
)
- eventlisting.add_child(instance = eventpage)
+ eventlisting.add_child(instance=eventpage)
rindex = self.client.get(path=eventlisting.url)
self.assertEqual(rindex.status_code, 200)
diff --git a/ietf/forms/migrations/0001_initial.py b/ietf/forms/migrations/0001_initial.py
index 3058b0de..c7b6f257 100644
--- a/ietf/forms/migrations/0001_initial.py
+++ b/ietf/forms/migrations/0001_initial.py
@@ -2,10 +2,10 @@
# Generated by Django 1.11.29 on 2020-04-10 18:46
from __future__ import unicode_literals
-from django.db import migrations, models
import django.db.models.deletion
import modelcluster.fields
-import wagtail.core.fields
+import wagtail.fields
+from django.db import migrations, models
class Migration(migrations.Migration):
@@ -13,45 +13,139 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
- ('wagtailcore', '0040_page_draft_title'),
+ ("wagtailcore", "0040_page_draft_title"),
]
operations = [
migrations.CreateModel(
- name='FormField',
+ name="FormField",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
- ('label', models.CharField(help_text='The label of the form field', max_length=255, verbose_name='label')),
- ('field_type', models.CharField(choices=[('singleline', 'Single line text'), ('multiline', 'Multi-line text'), ('email', 'Email'), ('number', 'Number'), ('url', 'URL'), ('checkbox', 'Checkbox'), ('checkboxes', 'Checkboxes'), ('dropdown', 'Drop down'), ('multiselect', 'Multiple select'), ('radio', 'Radio buttons'), ('date', 'Date'), ('datetime', 'Date/time'), ('hidden', 'Hidden field')], max_length=16, verbose_name='field type')),
- ('required', models.BooleanField(default=True, verbose_name='required')),
- ('choices', models.TextField(blank=True, help_text='Comma separated list of choices. Only applicable in checkboxes, radio and dropdown.', verbose_name='choices')),
- ('default_value', models.CharField(blank=True, help_text='Default value. Comma separated values supported for checkboxes.', max_length=255, verbose_name='default value')),
- ('help_text', models.CharField(blank=True, max_length=255, verbose_name='help text')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "sort_order",
+ models.IntegerField(blank=True, editable=False, null=True),
+ ),
+ (
+ "label",
+ models.CharField(
+ help_text="The label of the form field",
+ max_length=255,
+ verbose_name="label",
+ ),
+ ),
+ (
+ "field_type",
+ models.CharField(
+ choices=[
+ ("singleline", "Single line text"),
+ ("multiline", "Multi-line text"),
+ ("email", "Email"),
+ ("number", "Number"),
+ ("url", "URL"),
+ ("checkbox", "Checkbox"),
+ ("checkboxes", "Checkboxes"),
+ ("dropdown", "Drop down"),
+ ("multiselect", "Multiple select"),
+ ("radio", "Radio buttons"),
+ ("date", "Date"),
+ ("datetime", "Date/time"),
+ ("hidden", "Hidden field"),
+ ],
+ max_length=16,
+ verbose_name="field type",
+ ),
+ ),
+ (
+ "required",
+ models.BooleanField(default=True, verbose_name="required"),
+ ),
+ (
+ "choices",
+ models.TextField(
+ blank=True,
+ help_text="Comma separated list of choices. Only applicable in checkboxes, radio and dropdown.",
+ verbose_name="choices",
+ ),
+ ),
+ (
+ "default_value",
+ models.CharField(
+ blank=True,
+ help_text="Default value. Comma separated values supported for checkboxes.",
+ max_length=255,
+ verbose_name="default value",
+ ),
+ ),
+ (
+ "help_text",
+ models.CharField(
+ blank=True, max_length=255, verbose_name="help text"
+ ),
+ ),
],
options={
- 'ordering': ['sort_order'],
- 'abstract': False,
+ "ordering": ["sort_order"],
+ "abstract": False,
},
),
migrations.CreateModel(
- name='FormPage',
+ name="FormPage",
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')),
- ('to_address', models.CharField(blank=True, help_text='Optional - form submissions will be emailed to these addresses. Separate multiple addresses by comma.', max_length=255, verbose_name='to address')),
- ('from_address', models.CharField(blank=True, max_length=255, verbose_name='from address')),
- ('subject', models.CharField(blank=True, max_length=255, verbose_name='subject')),
- ('intro', wagtail.core.fields.RichTextField(blank=True)),
- ('thank_you_text', wagtail.core.fields.RichTextField(blank=True)),
+ (
+ "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",
+ ),
+ ),
+ (
+ "to_address",
+ models.CharField(
+ blank=True,
+ help_text="Optional - form submissions will be emailed to these addresses. Separate multiple addresses by comma.",
+ max_length=255,
+ verbose_name="to address",
+ ),
+ ),
+ (
+ "from_address",
+ models.CharField(
+ blank=True, max_length=255, verbose_name="from address"
+ ),
+ ),
+ (
+ "subject",
+ models.CharField(
+ blank=True, max_length=255, verbose_name="subject"
+ ),
+ ),
+ ("intro", wagtail.fields.RichTextField(blank=True)),
+ ("thank_you_text", wagtail.fields.RichTextField(blank=True)),
],
options={
- 'abstract': False,
+ "abstract": False,
},
- bases=('wagtailcore.page',),
+ bases=("wagtailcore.page",),
),
migrations.AddField(
- model_name='formfield',
- name='page',
- field=modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='form_fields', to='forms.FormPage'),
+ model_name="formfield",
+ name="page",
+ field=modelcluster.fields.ParentalKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="form_fields",
+ to="forms.FormPage",
+ ),
),
]
diff --git a/ietf/forms/migrations/0003_auto_20220722_0302.py b/ietf/forms/migrations/0003_auto_20220722_0302.py
new file mode 100644
index 00000000..abee178c
--- /dev/null
+++ b/ietf/forms/migrations/0003_auto_20220722_0302.py
@@ -0,0 +1,34 @@
+# Generated by Django 3.2.13 on 2022-07-22 02:02
+
+from django.db import migrations, models
+import wagtail.contrib.forms.models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('forms', '0002_formfield_clean_name'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='formfield',
+ name='choices',
+ field=models.TextField(blank=True, help_text='Comma or new line separated list of choices. Only applicable in checkboxes, radio and dropdown.', verbose_name='choices'),
+ ),
+ migrations.AlterField(
+ model_name='formfield',
+ name='default_value',
+ field=models.TextField(blank=True, help_text='Default value. Comma or new line separated values supported for checkboxes.', verbose_name='default value'),
+ ),
+ migrations.AlterField(
+ model_name='formpage',
+ name='from_address',
+ field=models.EmailField(blank=True, max_length=255, verbose_name='from address'),
+ ),
+ migrations.AlterField(
+ model_name='formpage',
+ name='to_address',
+ field=models.CharField(blank=True, help_text='Optional - form submissions will be emailed to these addresses. Separate multiple addresses by comma.', max_length=255, validators=[wagtail.contrib.forms.models.validate_to_address], verbose_name='to address'),
+ ),
+ ]
diff --git a/ietf/forms/migrations/0004_convert_unicode_to_text.py b/ietf/forms/migrations/0004_convert_unicode_to_text.py
new file mode 100644
index 00000000..1266ca54
--- /dev/null
+++ b/ietf/forms/migrations/0004_convert_unicode_to_text.py
@@ -0,0 +1,20 @@
+
+from django.db import migrations, models
+
+def convert_unicode_to_text(apps, schema_editor):
+ if apps.is_installed('wagtailforms'):
+ Submissions = apps.get_model('wagtailforms', 'formsubmission')
+ for submission in Submissions.objects.all():
+ submission.form_data = str(submission.form_data.replace('\\u0000',''))
+ submission.save()
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('forms', '0003_auto_20220722_0302'),
+ ]
+
+ operations = [
+ migrations.RunPython(convert_unicode_to_text)
+ ]
diff --git a/ietf/forms/models.py b/ietf/forms/models.py
index 508b6586..44c88e19 100644
--- a/ietf/forms/models.py
+++ b/ietf/forms/models.py
@@ -3,9 +3,9 @@
from django.contrib import messages
from django.views.defaults import server_error
from modelcluster.fields import ParentalKey
-from wagtail.admin.edit_handlers import FieldPanel, InlinePanel, MultiFieldPanel
+from wagtail.admin.panels import FieldPanel, InlinePanel, MultiFieldPanel
from wagtail.contrib.forms.models import AbstractEmailForm, AbstractFormField
-from wagtail.core.fields import RichTextField
+from wagtail.fields import RichTextField
from ietf.views import server_error
diff --git a/ietf/forms/templatetags/form_tags.py b/ietf/forms/templatetags/form_tags.py
index 5f6fcd28..cbcb027a 100644
--- a/ietf/forms/templatetags/form_tags.py
+++ b/ietf/forms/templatetags/form_tags.py
@@ -1,6 +1,5 @@
-from wagtail.core.utils import camelcase_to_underscore
-
from django import template
+from wagtail.coreutils import camelcase_to_underscore
register = template.Library()
@@ -14,16 +13,17 @@ def fieldtype(bound_field):
def widgettype(bound_field):
return camelcase_to_underscore(bound_field.field.widget.__class__.__name__)
-@register.filter(name='add_attr')
+
+@register.filter(name="add_attr")
def add_attr(bound_field, value):
attrs = {}
- definition = value.split(',')
+ definition = value.split(",")
for d in definition:
- if ':' not in d:
- attrs['class'] = d
+ if ":" not in d:
+ attrs["class"] = d
else:
- key, val = d.split(':')
+ key, val = d.split(":")
attrs[key] = val
return bound_field.as_widget(attrs=attrs)
diff --git a/ietf/forms/tests.py b/ietf/forms/tests.py
index 5f603a66..d114e113 100644
--- a/ietf/forms/tests.py
+++ b/ietf/forms/tests.py
@@ -1,5 +1,5 @@
from django.test import TestCase
-from wagtail.core.models import Page, Site
+from wagtail.models import Page, Site
from ..home.models import HomePage
from .models import FormPage
diff --git a/ietf/glossary/models.py b/ietf/glossary/models.py
index c717e991..6f3bdcfb 100644
--- a/ietf/glossary/models.py
+++ b/ietf/glossary/models.py
@@ -1,45 +1,40 @@
from django.db import models
-
-from wagtail.core.models import Page, Orderable
-from wagtail.search.backends import get_search_backend
-from wagtail.admin.edit_handlers import (
- FieldPanel, InlinePanel
-)
-from wagtail.snippets.edit_handlers import (
- SnippetChooserPanel
-)
-
from modelcluster.fields import ParentalKey
+from wagtail.admin.panels import FieldPanel, InlinePanel
+from wagtail.models import Orderable, Page
+from wagtail.search.backends import get_search_backend
from ..snippets.models import GlossaryItem
from ..utils.models import PromoteMixin, RelatedLink
class GlossaryPageRelatedLink(Orderable, RelatedLink):
- page = ParentalKey('glossary.GlossaryPage', related_name='related_links')
+ page = ParentalKey("glossary.GlossaryPage", related_name="related_links")
class GlossaryPage(Page, PromoteMixin):
"""
This page lists all :models:`snippets.GlossaryItem` snippets.
"""
+
introduction = models.CharField(
blank=True,
max_length=511,
- help_text="The page introduction text. You can only use 511 "
- "characters."
+ help_text="The page introduction text. You can only use 511 " "characters.",
)
call_to_action = models.ForeignKey(
- 'snippets.CallToAction',
- null=True, blank=True,
+ "snippets.CallToAction",
+ null=True,
+ blank=True,
on_delete=models.SET_NULL,
- related_name='+'
+ related_name="+",
)
mailing_list_signup = models.ForeignKey(
- 'snippets.MailingListSignup',
+ "snippets.MailingListSignup",
null=True,
- blank=True, on_delete=models.SET_NULL,
- related_name='+'
+ blank=True,
+ on_delete=models.SET_NULL,
+ related_name="+",
)
@property
@@ -50,28 +45,26 @@ def get_context(self, request, *args, **kwargs):
context = super(GlossaryPage, self).get_context(request, *args, **kwargs)
glossary_items = GlossaryItem.objects.all()
- if request.GET.get('query'):
+ if request.GET.get("query"):
s = get_search_backend()
- glossary_items = s.search(
- request.GET.get('query'), glossary_items
- )
+ glossary_items = s.search(request.GET.get("query"), glossary_items)
- context['glossary_items'] = {}
+ context["glossary_items"] = {}
for item in glossary_items:
- if item.title[0:1].upper() not in context['glossary_items'].keys():
- context['glossary_items'][item.title[0:1].upper()] = [item]
+ if item.title[0:1].upper() not in context["glossary_items"].keys():
+ context["glossary_items"][item.title[0:1].upper()] = [item]
else:
- context['glossary_items'][item.title[0:1].upper()].append(item)
- context['search_query'] = request.GET.get('query')
+ context["glossary_items"][item.title[0:1].upper()].append(item)
+ context["search_query"] = request.GET.get("query")
return context
GlossaryPage.content_panels = Page.content_panels + [
- FieldPanel('introduction'),
- InlinePanel('related_links', label="Related Links"),
- SnippetChooserPanel('call_to_action'),
- SnippetChooserPanel('mailing_list_signup'),
+ FieldPanel("introduction"),
+ InlinePanel("related_links", label="Related Links"),
+ FieldPanel("call_to_action"),
+ FieldPanel("mailing_list_signup"),
]
GlossaryPage.promote_panels = Page.promote_panels + PromoteMixin.panels
diff --git a/ietf/glossary/tests.py b/ietf/glossary/tests.py
index 28b623e3..9f2d9a6f 100644
--- a/ietf/glossary/tests.py
+++ b/ietf/glossary/tests.py
@@ -1,23 +1,22 @@
from django.test import TestCase
+from wagtail.models import Page, Site
-from .models import GlossaryPage
from ..home.models import HomePage
+from .models import GlossaryPage
-from wagtail.core.models import Page, Site
class GlossaryPageTests(TestCase):
-
def test_glossary_page(self):
root = Page.get_first_root_node()
home = HomePage(
- slug = 'homepageslug',
- title = 'home page title',
- heading = 'home page heading',
- introduction = 'home page introduction',
- request_for_comments_section_body = 'rfc section body',
- working_groups_section_body = 'wg section body',
+ slug="homepageslug",
+ title="home page title",
+ heading="home page heading",
+ introduction="home page introduction",
+ request_for_comments_section_body="rfc section body",
+ working_groups_section_body="wg section body",
)
root.add_child(instance=home)
@@ -25,18 +24,18 @@ def test_glossary_page(self):
Site.objects.all().delete()
Site.objects.create(
- hostname='localhost',
- root_page = home,
+ hostname="localhost",
+ root_page=home,
is_default_site=True,
- site_name='testingsitename',
+ site_name="testingsitename",
)
glossary = GlossaryPage(
- slug = 'glossary',
- title = 'glossary title',
- introduction = 'glossary introduction',
+ slug="glossary",
+ title="glossary title",
+ introduction="glossary introduction",
)
- home.add_child(instance = glossary)
+ home.add_child(instance=glossary)
r = self.client.get(path=glossary.url)
self.assertEqual(r.status_code, 200)
diff --git a/ietf/home/models.py b/ietf/home/models.py
index 3275d3cb..7e3fc4ea 100644
--- a/ietf/home/models.py
+++ b/ietf/home/models.py
@@ -1,82 +1,89 @@
from __future__ import unicode_literals
+
from datetime import datetime
from django.db import models
from django.db.models.expressions import RawSQL
-
from modelcluster.fields import ParentalKey
-
-from wagtail.core.models import Page
-from wagtail.images.edit_handlers import ImageChooserPanel
-from wagtail.search import index
-from wagtail.admin.edit_handlers import (
- FieldPanel, MultiFieldPanel, InlinePanel, PageChooserPanel
+from wagtail.admin.panels import (
+ FieldPanel,
+ InlinePanel,
+ MultiFieldPanel,
)
-from wagtail.snippets.edit_handlers import SnippetChooserPanel
+from wagtail.models import Page
+from wagtail.search import index
+
+from ietf.blog.models import BlogIndexPage, BlogPage
+from ..events.models import EventListingPage, EventPage
+from ..topics.models import PrimaryTopicPage, TopicIndexPage
from ..utils.models import RelatedLink
-from ..topics.models import TopicIndexPage, PrimaryTopicPage
-from ..events.models import EventPage, EventListingPage
-from ietf.blog.models import BlogPage, BlogIndexPage
class RequestForCommentsSectionLinks(RelatedLink):
- page = ParentalKey('home.HomePage',
- related_name='request_for_comments_section_links')
+ page = ParentalKey(
+ "home.HomePage", related_name="request_for_comments_section_links"
+ )
class WorkingGroupsSectionLinks(RelatedLink):
- page = ParentalKey('home.HomePage',
- related_name='working_groups_section_links')
+ page = ParentalKey("home.HomePage", related_name="working_groups_section_links")
class HomePage(Page):
heading = models.CharField(max_length=255)
introduction = models.CharField(max_length=255)
main_image = models.ForeignKey(
- 'images.IETFImage',
- null=True, blank=True,
+ "images.IETFImage",
+ null=True,
+ blank=True,
on_delete=models.SET_NULL,
- related_name='+',
+ related_name="+",
)
button_text = models.CharField(max_length=255, blank=True)
button_link = models.ForeignKey(
- 'wagtailcore.Page',
- null=True, blank=True,
+ "wagtailcore.Page",
+ null=True,
+ blank=True,
on_delete=models.SET_NULL,
- related_name='+'
+ related_name="+",
)
request_for_comments_section_body = models.CharField(max_length=500)
highlighted_request_for_comment = models.ForeignKey(
- 'snippets.RFC',
- null=True, blank=True,
+ "snippets.RFC",
+ null=True,
+ blank=True,
on_delete=models.SET_NULL,
- related_name='+'
+ related_name="+",
)
working_groups_section_body = models.CharField(max_length=500)
highlighted_working_group = models.ForeignKey(
- 'snippets.WorkingGroup',
- null=True, blank=True,
+ "snippets.WorkingGroup",
+ null=True,
+ blank=True,
on_delete=models.SET_NULL,
- related_name='+'
+ related_name="+",
)
call_to_action = models.ForeignKey(
- 'snippets.CallToAction',
- null=True, blank=True,
+ "snippets.CallToAction",
+ null=True,
+ blank=True,
on_delete=models.SET_NULL,
- related_name='+'
+ related_name="+",
)
search_fields = Page.search_fields + [
- index.SearchField('heading'),
- index.SearchField('request_for_comments_section_body'),
- index.SearchField('working_groups_section_body'),
+ index.SearchField("heading"),
+ index.SearchField("request_for_comments_section_body"),
+ index.SearchField("working_groups_section_body"),
]
- def topic_index(self,):
+ def topic_index(
+ self,
+ ):
return TopicIndexPage.objects.live().first()
def primary_topics(self):
@@ -86,9 +93,11 @@ def primary_topics(self):
return []
def upcoming_events(self):
- return EventPage.objects.filter(
- end_date__gte=datetime.today()
- ).live().order_by('start_date')[:2]
+ return (
+ EventPage.objects.filter(end_date__gte=datetime.today())
+ .live()
+ .order_by("start_date")[:2]
+ )
def event_index(self):
return EventListingPage.objects.live().first()
@@ -97,28 +106,43 @@ def blog_index(self):
return BlogIndexPage.objects.live().first()
def blogs(self):
- return BlogPage.objects.live() \
- .annotate(date_sql=RawSQL('CASE WHEN (date_published IS NOT NULL) THEN date_published ELSE first_published_at END', ()))\
- .order_by('-date_sql')\
- [:2]
+ return (
+ BlogPage.objects.live()
+ .annotate(
+ date_sql=RawSQL(
+ "CASE WHEN (date_published IS NOT NULL) THEN date_published ELSE first_published_at END",
+ (),
+ )
+ )
+ .order_by("-date_sql")[:2]
+ )
content_panels = Page.content_panels + [
- MultiFieldPanel([
- FieldPanel('heading'),
- FieldPanel('introduction'),
- FieldPanel('button_text'),
- ImageChooserPanel('main_image'),
- PageChooserPanel('button_link')
- ], "Header"),
- MultiFieldPanel([
- FieldPanel('request_for_comments_section_body'),
- SnippetChooserPanel('highlighted_request_for_comment'),
- InlinePanel('request_for_comments_section_links', label="Link"),
- ], "Request For Comments Section"),
- MultiFieldPanel([
- FieldPanel('working_groups_section_body'),
- SnippetChooserPanel('highlighted_working_group'),
- InlinePanel('working_groups_section_links', label="Link"),
- ], "Working Groups Section"),
- SnippetChooserPanel('call_to_action')
+ MultiFieldPanel(
+ [
+ FieldPanel("heading"),
+ FieldPanel("introduction"),
+ FieldPanel("button_text"),
+ FieldPanel("main_image"),
+ FieldPanel("button_link"),
+ ],
+ "Header",
+ ),
+ MultiFieldPanel(
+ [
+ FieldPanel("request_for_comments_section_body"),
+ FieldPanel("highlighted_request_for_comment"),
+ InlinePanel("request_for_comments_section_links", label="Link"),
+ ],
+ "Request For Comments Section",
+ ),
+ MultiFieldPanel(
+ [
+ FieldPanel("working_groups_section_body"),
+ FieldPanel("highlighted_working_group"),
+ InlinePanel("working_groups_section_links", label="Link"),
+ ],
+ "Working Groups Section",
+ ),
+ FieldPanel("call_to_action"),
]
diff --git a/ietf/home/tests.py b/ietf/home/tests.py
index 018b1978..a37be46a 100644
--- a/ietf/home/tests.py
+++ b/ietf/home/tests.py
@@ -1,24 +1,23 @@
from django.test import TestCase
+from wagtail.models import Page, Site
-from .models import HomePage, RequestForCommentsSectionLinks, WorkingGroupsSectionLinks
-from ..blog.models import BlogPage, BlogIndexPage
+from ..blog.models import BlogIndexPage, BlogPage
from ..snippets.models import RFC, WorkingGroup
+from .models import HomePage, RequestForCommentsSectionLinks, WorkingGroupsSectionLinks
-from wagtail.core.models import Page, Site
class HomeTests(TestCase):
-
def test_homepage(self):
root = Page.get_first_root_node()
home = HomePage(
- slug = 'homepageslug',
- title = 'home page title',
- heading = 'home page heading',
- introduction = 'home page introduction',
- request_for_comments_section_body = 'rfc section body',
- working_groups_section_body = 'wg section body',
+ slug="homepageslug",
+ title="home page title",
+ heading="home page heading",
+ introduction="home page introduction",
+ request_for_comments_section_body="rfc section body",
+ working_groups_section_body="wg section body",
)
root.add_child(instance=home)
@@ -28,27 +27,27 @@ def test_homepage(self):
Site.objects.all().delete()
Site.objects.create(
- hostname='localhost',
- root_page = home,
+ hostname="localhost",
+ root_page=home,
is_default_site=True,
- site_name='testingsitename',
+ site_name="testingsitename",
)
blogindex = BlogIndexPage(
- slug = 'blog',
- title = 'blog index title',
+ slug="blog",
+ title="blog index title",
)
- home.add_child(instance = blogindex)
+ home.add_child(instance=blogindex)
blog = BlogPage(
- slug = 'blogpost',
- title = 'blog title',
- introduction = 'blog introduction',
- body = 'blog body'
+ slug="blogpost",
+ title="blog title",
+ introduction="blog introduction",
+ body="blog body",
)
- blogindex.add_child(instance = blog)
+ blogindex.add_child(instance=blog)
- home.button_text = 'blog button text'
+ home.button_text = "blog button text"
home.button_link = blog
home.save()
@@ -60,7 +59,6 @@ def test_homepage(self):
self.assertIn(home.button_text.encode(), r.content)
self.assertIn(('href="%s"' % blog.url).encode(), r.content)
-
# other_page = BlogPage.objects.create(
# introduction = 'blog introduction',
# title='blog title',
@@ -77,6 +75,3 @@ def test_homepage(self):
# r = self.client.get(url=home.url_path)
# self.assertEqual(r.status_code, 200)
-
-
-
diff --git a/ietf/home/wagtail_hooks.py b/ietf/home/wagtail_hooks.py
index 72aada2d..76cabb98 100644
--- a/ietf/home/wagtail_hooks.py
+++ b/ietf/home/wagtail_hooks.py
@@ -1,14 +1,13 @@
from django.urls import reverse
-
-from wagtail.core import hooks
+from wagtail import hooks
from wagtail.admin.menu import MenuItem
-@hooks.register('register_admin_menu_item')
+@hooks.register("register_admin_menu_item")
def register_resource_menu_item():
- return MenuItem('Documentation',
- reverse('django-admindocs-docroot'),
- classnames='icon icon-folder-inverse',
- order=10000)
-
-
+ return MenuItem(
+ "Documentation",
+ reverse("django-admindocs-docroot"),
+ classnames="icon icon-folder-inverse",
+ order=10000,
+ )
diff --git a/ietf/iesg_statement/migrations/0001_initial.py b/ietf/iesg_statement/migrations/0001_initial.py
index 4964aec3..3bb27277 100644
--- a/ietf/iesg_statement/migrations/0001_initial.py
+++ b/ietf/iesg_statement/migrations/0001_initial.py
@@ -2,15 +2,15 @@
# Generated by Django 1.11.29 on 2020-04-10 18:46
from __future__ import unicode_literals
-from django.db import migrations, models
import django.db.models.deletion
import modelcluster.fields
+import wagtail.blocks
import wagtail.contrib.routable_page.models
import wagtail.contrib.table_block.blocks
-import wagtail.core.blocks
-import wagtail.core.fields
import wagtail.embeds.blocks
+import wagtail.fields
import wagtail.images.blocks
+from django.db import migrations, models
class Migration(migrations.Migration):
@@ -18,45 +18,161 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
- ('wagtailcore', '0040_page_draft_title'),
- ('images', '0001_initial'),
- ('snippets', '0001_initial'),
+ ("wagtailcore", "0040_page_draft_title"),
+ ("images", "0001_initial"),
+ ("snippets", "0001_initial"),
]
operations = [
migrations.CreateModel(
- name='IESGStatementIndexPage',
+ name="IESGStatementIndexPage",
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')),
+ (
+ "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={
- 'verbose_name': 'IESG Statements Index Page',
+ "verbose_name": "IESG Statements Index Page",
},
- bases=(wagtail.contrib.routable_page.models.RoutablePageMixin, 'wagtailcore.page'),
+ bases=(
+ wagtail.contrib.routable_page.models.RoutablePageMixin,
+ "wagtailcore.page",
+ ),
),
migrations.CreateModel(
- name='IESGStatementPage',
+ name="IESGStatementPage",
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')),
- ('social_text', models.CharField(blank=True, help_text='Description of this page as it should appear when shared on social networks, or in Google results', max_length=255)),
- ('date_published', models.DateTimeField(blank=True, help_text='Use this field to override the date that the blog post appears to have been published.', null=True)),
- ('introduction', models.CharField(help_text='The page introduction text.', max_length=511)),
- ('body', wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}))])),
- ('prepared_body', models.TextField(blank=True, help_text='The prepared body content after bibliography styling has been applied. Auto-generated on each save.', null=True)),
- ('feed_image', models.ForeignKey(blank=True, help_text='This image will be used in listings and indexes across the site, if no feed image is added, the social image will be used.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')),
- ('social_image', models.ForeignKey(blank=True, help_text="Image to appear alongside 'social text', particularly for sharing on social networks", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')),
+ (
+ "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",
+ ),
+ ),
+ (
+ "social_text",
+ models.CharField(
+ blank=True,
+ help_text="Description of this page as it should appear when shared on social networks, or in Google results",
+ max_length=255,
+ ),
+ ),
+ (
+ "date_published",
+ models.DateTimeField(
+ blank=True,
+ help_text="Use this field to override the date that the blog post appears to have been published.",
+ null=True,
+ ),
+ ),
+ (
+ "introduction",
+ models.CharField(
+ help_text="The page introduction text.", max_length=511
+ ),
+ ),
+ (
+ "body",
+ wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ (
+ "raw_html",
+ wagtail.blocks.RawHTMLBlock(icon="placeholder"),
+ ),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"}
+ ),
+ ),
+ ]
+ ),
+ ),
+ (
+ "prepared_body",
+ models.TextField(
+ blank=True,
+ help_text="The prepared body content after bibliography styling has been applied. Auto-generated on each save.",
+ null=True,
+ ),
+ ),
+ (
+ "feed_image",
+ models.ForeignKey(
+ blank=True,
+ help_text="This image will be used in listings and indexes across the site, if no feed image is added, the social image will be used.",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
+ (
+ "social_image",
+ models.ForeignKey(
+ blank=True,
+ help_text="Image to appear alongside 'social text', particularly for sharing on social networks",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
],
options={
- 'verbose_name': 'IESG Statement Page',
+ "verbose_name": "IESG Statement Page",
},
- bases=('wagtailcore.page', models.Model),
+ bases=("wagtailcore.page", models.Model),
),
migrations.CreateModel(
- name='IESGStatementTopic',
+ name="IESGStatementTopic",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('page', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='topics', to='iesg_statement.IESGStatementPage')),
- ('topic', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='snippets.Topic')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "page",
+ modelcluster.fields.ParentalKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="topics",
+ to="iesg_statement.IESGStatementPage",
+ ),
+ ),
+ (
+ "topic",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="snippets.Topic",
+ ),
+ ),
],
),
]
diff --git a/ietf/iesg_statement/migrations/0002_auto_20210325_0442.py b/ietf/iesg_statement/migrations/0002_auto_20210325_0442.py
index 7b137ed8..22d8b1a9 100644
--- a/ietf/iesg_statement/migrations/0002_auto_20210325_0442.py
+++ b/ietf/iesg_statement/migrations/0002_auto_20210325_0442.py
@@ -1,23 +1,43 @@
# Generated by Django 2.2.16 on 2021-03-25 04:42
-from django.db import migrations
+import wagtail.blocks
import wagtail.contrib.table_block.blocks
-import wagtail.core.blocks
-import wagtail.core.fields
import wagtail.embeds.blocks
+import wagtail.fields
import wagtail.images.blocks
+from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
- ('iesg_statement', '0001_initial'),
+ ("iesg_statement", "0001_initial"),
]
operations = [
migrations.AlterField(
- model_name='iesgstatementpage',
- name='body',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))]),
+ model_name="iesgstatementpage",
+ name="body",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ]
+ ),
),
]
diff --git a/ietf/iesg_statement/migrations/0003_auto_20211101_0113.py b/ietf/iesg_statement/migrations/0003_auto_20211101_0113.py
index c4ab6110..2c31adea 100644
--- a/ietf/iesg_statement/migrations/0003_auto_20211101_0113.py
+++ b/ietf/iesg_statement/migrations/0003_auto_20211101_0113.py
@@ -1,24 +1,45 @@
# Generated by Django 2.2.19 on 2021-11-01 01:13
-from django.db import migrations
+import wagtail.blocks
import wagtail.contrib.table_block.blocks
-import wagtail.core.blocks
-import wagtail.core.fields
import wagtail.embeds.blocks
+import wagtail.fields
import wagtail.images.blocks
import wagtailmarkdown.blocks
+from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
- ('iesg_statement', '0002_auto_20210325_0442'),
+ ("iesg_statement", "0002_auto_20210325_0442"),
]
operations = [
migrations.AlterField(
- model_name='iesgstatementpage',
- name='body',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('markdown', wagtailmarkdown.blocks.MarkdownBlock(icon='code')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))]),
+ model_name="iesgstatementpage",
+ name="body",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("markdown", wagtailmarkdown.blocks.MarkdownBlock(icon="code")),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ]
+ ),
),
]
diff --git a/ietf/iesg_statement/models.py b/ietf/iesg_statement/models.py
index 4eac5e89..a3ffd799 100644
--- a/ietf/iesg_statement/models.py
+++ b/ietf/iesg_statement/models.py
@@ -1,32 +1,26 @@
from datetime import datetime
from functools import partial
+from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.db.models.functions import Coalesce
from django.shortcuts import redirect
-
-from django.core.exceptions import ObjectDoesNotExist
from django.utils import functional
from django.utils.safestring import mark_safe
-
from modelcluster.fields import ParentalKey
-
-from wagtail.core.models import Page
-from wagtail.core.fields import StreamField
-from wagtail.snippets.edit_handlers import (
- SnippetChooserPanel
-)
-from wagtail.search import index
-from wagtail.admin.edit_handlers import (
- StreamFieldPanel, FieldPanel, InlinePanel
-)
+from wagtail.admin.panels import FieldPanel, InlinePanel
from wagtail.contrib.routable_page.models import RoutablePageMixin, route
+from wagtail.fields import StreamField
+from wagtail.models import Page
+from wagtail.search import index
from ..bibliography.models import BibliographyMixin
-#from ..utils.models import FeedSettings, PromoteMixin
-from ..utils.models import PromoteMixin
-from ..utils.blocks import StandardBlock
from ..snippets.models import Topic
+from ..utils.blocks import StandardBlock
+
+# from ..utils.models import FeedSettings, PromoteMixin
+from ..utils.models import PromoteMixin
+
def filter_pages_by_topic(pages, topic):
return pages.filter(topics__topic=topic)
@@ -51,81 +45,75 @@ def parse_date_search_input(date):
def build_filter_text(**kwargs):
if any(kwargs):
text_fragments = []
- if kwargs.get('topic'):
+ if kwargs.get("topic"):
+ text_fragments.append("{}".format(kwargs.get("topic")))
+ if kwargs.get("date_from") and kwargs.get("date_to"):
text_fragments.append(
- '{}'.format(kwargs.get('topic'))
+ "dates between {} & {}".format(
+ kwargs["date_from"], kwargs["date_to"]
)
- if kwargs.get('date_from') and kwargs.get('date_to'):
+ )
+ elif kwargs.get("date_from"):
text_fragments.append(
- 'dates between {} & {}'.format(
- kwargs['date_from'], kwargs['date_to']
- )
+ "dates after {}".format(kwargs["date_from"])
+ )
+ elif kwargs.get("date_to"):
+ text_fragments.append(
+ "dates before {}".format(kwargs["date_to"])
)
- elif kwargs.get('date_from'):
- text_fragments.append('dates after {}'.format(
- kwargs['date_from']
- ))
- elif kwargs.get('date_to'):
- text_fragments.append('dates before {}'.format(
- kwargs['date_to']
- ))
- return ', '.join(text_fragments)
+ return ", ".join(text_fragments)
else:
return ""
parameter_functions_map = {
- 'topic': [get_topic_by_id, filter_pages_by_topic],
- 'date_from': [parse_date_search_input, filter_pages_by_date_from],
- 'date_to': [parse_date_search_input, filter_pages_by_date_to]
+ "topic": [get_topic_by_id, filter_pages_by_topic],
+ "date_from": [parse_date_search_input, filter_pages_by_date_from],
+ "date_to": [parse_date_search_input, filter_pages_by_date_to],
}
class IESGStatementTopic(models.Model):
- page = ParentalKey(
- 'iesg_statement.IESGStatementPage',
- related_name='topics'
- )
+ page = ParentalKey("iesg_statement.IESGStatementPage", related_name="topics")
topic = models.ForeignKey(
- 'snippets.Topic',
- related_name='+',
+ "snippets.Topic",
+ related_name="+",
on_delete=models.CASCADE,
)
- panels = [
- SnippetChooserPanel('topic')
- ]
+ panels = [FieldPanel("topic")]
+
class IESGStatementPage(Page, BibliographyMixin, PromoteMixin):
date_published = models.DateTimeField(
- null=True, blank=True,
+ null=True,
+ blank=True,
help_text="Use this field to override the date that the "
- "blog post appears to have been published."
+ "blog post appears to have been published.",
)
introduction = models.CharField(
- max_length=511,
- help_text="The page introduction text."
+ max_length=511, help_text="The page introduction text."
)
body = StreamField(StandardBlock())
search_fields = Page.search_fields + [
- index.SearchField('introduction'),
- index.SearchField('body'),
+ index.SearchField("introduction"),
+ index.SearchField("body"),
]
# for bibliography
prepared_body = models.TextField(
- blank=True, null=True,
+ blank=True,
+ null=True,
help_text="The prepared body content after bibliography styling has been applied. Auto-generated on each save.",
)
- CONTENT_FIELD_MAP = {'body': 'prepared_body'}
+ CONTENT_FIELD_MAP = {"body": "prepared_body"}
- parent_page_types = ['iesg_statement.IESGStatementIndexPage']
+ parent_page_types = ["iesg_statement.IESGStatementIndexPage"]
subpage_types = []
-
@property
def date(self):
return self.date_published or self.first_published_at
@@ -134,14 +122,21 @@ def date(self):
def next(self):
if not self.date:
return None
- after = sorted([p for p in self.siblings.exclude(pk=self.pk) if p.date > self.date], key=lambda o:o.date)
+ after = sorted(
+ [p for p in self.siblings.exclude(pk=self.pk) if p.date > self.date],
+ key=lambda o: o.date,
+ )
return after and after[0] or None
@property
def previous(self):
if not self.date:
return None
- before = sorted([p for p in self.siblings.exclude(pk=self.pk) if p.date < self.date], key=lambda o:o.date, reverse=True)
+ before = sorted(
+ [p for p in self.siblings.exclude(pk=self.pk) if p.date < self.date],
+ key=lambda o: o.date,
+ reverse=True,
+ )
return before and before[0] or None
def coalesced_published_date(self):
@@ -153,9 +148,12 @@ def feed_text(self):
@functional.cached_property
def siblings(self):
- return self.__class__.objects.live().sibling_of(self).annotate(
- d=Coalesce('date_published', 'first_published_at')
- ).order_by('-d')
+ return (
+ self.__class__.objects.live()
+ .sibling_of(self)
+ .annotate(d=Coalesce("date_published", "first_published_at"))
+ .order_by("-d")
+ )
def get_context(self, request, *args, **kwargs):
context = super(IESGStatementPage, self).get_context(request, *args, **kwargs)
@@ -170,8 +168,9 @@ def get_context(self, request, *args, **kwargs):
related_object = functions[0](search_query)
siblings = functions[1](siblings, related_object)
query_string += "%s=%s&" % (parameter, search_query)
- filter_text_builder = partial(filter_text_builder,
- **{parameter: related_object.__str__()})
+ filter_text_builder = partial(
+ filter_text_builder, **{parameter: related_object.__str__()}
+ )
except (ValueError, ObjectDoesNotExist):
pass
@@ -179,56 +178,60 @@ def get_context(self, request, *args, **kwargs):
siblings = siblings.filter(d__lt=self.coalesced_published_date())[:5]
-
if filter_text:
if siblings:
filter_text = mark_safe("You have filtered by " + filter_text)
else:
- filter_text = mark_safe("No results for " + filter_text + ", showing latest")
+ filter_text = mark_safe(
+ "No results for " + filter_text + ", showing latest"
+ )
context.update(
parent_url=self.get_parent().url,
- filter_text = filter_text,
+ filter_text=filter_text,
siblings=siblings,
- topics=IESGStatementTopic.objects.all().values_list(
- 'topic__pk', 'topic__title'
- ).distinct(),
+ topics=IESGStatementTopic.objects.all()
+ .values_list("topic__pk", "topic__title")
+ .distinct(),
query_string=query_string,
# TODO blog_feed_title=feed_settings.blog_feed_title
)
return context
def serve_preview(self, request, mode_name):
- """ This is another hack to overcome the MRO issue we were seeing """
+ """This is another hack to overcome the MRO issue we were seeing"""
return BibliographyMixin.serve_preview(self, request, mode_name)
class Meta:
verbose_name = "IESG Statement Page"
+
IESGStatementPage.content_panels = Page.content_panels + [
- FieldPanel('date_published'),
- FieldPanel('introduction'),
- StreamFieldPanel('body'),
- InlinePanel('topics', label="Topics"),
+ FieldPanel("date_published"),
+ FieldPanel("introduction"),
+ FieldPanel("body"),
+ InlinePanel("topics", label="Topics"),
]
IESGStatementPage.promote_panels = Page.promote_panels + PromoteMixin.panels
class IESGStatementIndexPage(RoutablePageMixin, Page):
-
def get_context(self, request):
context = super().get_context(request)
- context['statements'] = IESGStatementPage.objects.child_of(self).live().annotate(
- d=Coalesce('date_published', 'first_published_at')
- ).order_by('-d')
+ context["statements"] = (
+ IESGStatementPage.objects.child_of(self)
+ .live()
+ .annotate(d=Coalesce("date_published", "first_published_at"))
+ .order_by("-d")
+ )
return context
- @route(r'^all/$')
+ @route(r"^all/$")
def all_entries(self, request, *args, **kwargs):
return super().serve(request, *args, **kwargs)
- @route(r'^$')
+ @route(r"^$")
def redirect_first(self, request, *args, **kwargs):
has_filter = False
for parameter, _ in parameter_functions_map.items():
@@ -236,10 +239,13 @@ def redirect_first(self, request, *args, **kwargs):
has_filter = True
break
- if (has_filter):
- statements = IESGStatementPage.objects.child_of(self).live().annotate(
- d=Coalesce('date_published', 'first_published_at')
- ).order_by('-d')
+ if has_filter:
+ statements = (
+ IESGStatementPage.objects.child_of(self)
+ .live()
+ .annotate(d=Coalesce("date_published", "first_published_at"))
+ .order_by("-d")
+ )
first_statement_url = statements.first().url
query_string = "?"
@@ -256,11 +262,9 @@ def redirect_first(self, request, *args, **kwargs):
first_statement_url = statements.first().url
return redirect(first_statement_url + query_string)
else:
- return super().serve(request,*args,**kwargs)
+ return super().serve(request, *args, **kwargs)
-
- subpage_types = ['iesg_statement.IESGStatementPage']
+ subpage_types = ["iesg_statement.IESGStatementPage"]
class Meta:
verbose_name = "IESG Statements Index Page"
-
diff --git a/ietf/iesg_statement/tests.py b/ietf/iesg_statement/tests.py
index f56d8d29..becd3e55 100644
--- a/ietf/iesg_statement/tests.py
+++ b/ietf/iesg_statement/tests.py
@@ -1,23 +1,22 @@
from django.test import Client, TestCase
+from wagtail.models import Page, Site
-from .models import IESGStatementIndexPage, IESGStatementPage
from ..home.models import HomePage
+from .models import IESGStatementIndexPage, IESGStatementPage
-from wagtail.core.models import Page, Site
class IESGStatementPageTests(TestCase):
-
def test_iesg_statement_page(self):
root = Page.get_first_root_node()
home = HomePage(
- slug = 'homepageslug',
- title = 'home page title',
- heading = 'home page heading',
- introduction = 'home page introduction',
- request_for_comments_section_body = 'rfc section body',
- working_groups_section_body = 'wg section body',
+ slug="homepageslug",
+ title="home page title",
+ heading="home page heading",
+ introduction="home page introduction",
+ request_for_comments_section_body="rfc section body",
+ working_groups_section_body="wg section body",
)
root.add_child(instance=home)
@@ -25,24 +24,24 @@ def test_iesg_statement_page(self):
Site.objects.all().delete()
Site.objects.create(
- hostname='localhost',
- root_page = home,
+ hostname="localhost",
+ root_page=home,
is_default_site=True,
- site_name='testingsitename',
+ site_name="testingsitename",
)
iesg_statement_index = IESGStatementIndexPage(
- slug = 'iesg_statement_index',
- title = 'iesg statement index page title',
+ slug="iesg_statement_index",
+ title="iesg statement index page title",
)
- home.add_child(instance = iesg_statement_index)
+ home.add_child(instance=iesg_statement_index)
iesg_statement_page = IESGStatementPage(
- slug = 'iesgstatement',
- title = 'iesg statement title',
- introduction = 'iesg statement introduction',
+ slug="iesgstatement",
+ title="iesg statement title",
+ introduction="iesg statement introduction",
)
- iesg_statement_index.add_child(instance = iesg_statement_page)
+ iesg_statement_index.add_child(instance=iesg_statement_page)
rindex = self.client.get(path=iesg_statement_index.url)
self.assertEqual(rindex.status_code, 200)
diff --git a/ietf/images/migrations/0001_initial.py b/ietf/images/migrations/0001_initial.py
index 5731ece4..d5dffcf0 100644
--- a/ietf/images/migrations/0001_initial.py
+++ b/ietf/images/migrations/0001_initial.py
@@ -2,13 +2,13 @@
# Generated by Django 1.11.29 on 2020-04-10 18:46
from __future__ import unicode_literals
-from django.conf import settings
-from django.db import migrations, models
import django.db.models.deletion
import taggit.managers
-import wagtail.core.models
import wagtail.images.models
+import wagtail.models
import wagtail.search.index
+from django.conf import settings
+from django.db import migrations, models
class Migration(migrations.Migration):
@@ -17,50 +17,135 @@ class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ('taggit', '0002_auto_20150616_2121'),
- ('wagtailcore', '0040_page_draft_title'),
+ ("taggit", "0002_auto_20150616_2121"),
+ ("wagtailcore", "0040_page_draft_title"),
]
operations = [
migrations.CreateModel(
- name='IETFImage',
+ name="IETFImage",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('title', models.CharField(max_length=255, verbose_name='title')),
- ('file', models.ImageField(height_field='height', upload_to=wagtail.images.models.get_upload_to, verbose_name='file', width_field='width')),
- ('width', models.IntegerField(editable=False, verbose_name='width')),
- ('height', models.IntegerField(editable=False, verbose_name='height')),
- ('created_at', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='created at')),
- ('focal_point_x', models.PositiveIntegerField(blank=True, null=True)),
- ('focal_point_y', models.PositiveIntegerField(blank=True, null=True)),
- ('focal_point_width', models.PositiveIntegerField(blank=True, null=True)),
- ('focal_point_height', models.PositiveIntegerField(blank=True, null=True)),
- ('file_size', models.PositiveIntegerField(editable=False, null=True)),
- ('file_hash', models.CharField(blank=True, editable=False, max_length=40)),
- ('caption', models.CharField(blank=True, max_length=255, null=True)),
- ('collection', models.ForeignKey(default=wagtail.core.models.get_root_collection_id, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailcore.Collection', verbose_name='collection')),
- ('tags', taggit.managers.TaggableManager(blank=True, help_text=None, through='taggit.TaggedItem', to='taggit.Tag', verbose_name='tags')),
- ('uploaded_by_user', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='uploaded by user')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("title", models.CharField(max_length=255, verbose_name="title")),
+ (
+ "file",
+ models.ImageField(
+ height_field="height",
+ upload_to=wagtail.images.models.get_upload_to,
+ verbose_name="file",
+ width_field="width",
+ ),
+ ),
+ ("width", models.IntegerField(editable=False, verbose_name="width")),
+ ("height", models.IntegerField(editable=False, verbose_name="height")),
+ (
+ "created_at",
+ models.DateTimeField(
+ auto_now_add=True, db_index=True, verbose_name="created at"
+ ),
+ ),
+ ("focal_point_x", models.PositiveIntegerField(blank=True, null=True)),
+ ("focal_point_y", models.PositiveIntegerField(blank=True, null=True)),
+ (
+ "focal_point_width",
+ models.PositiveIntegerField(blank=True, null=True),
+ ),
+ (
+ "focal_point_height",
+ models.PositiveIntegerField(blank=True, null=True),
+ ),
+ ("file_size", models.PositiveIntegerField(editable=False, null=True)),
+ (
+ "file_hash",
+ models.CharField(blank=True, editable=False, max_length=40),
+ ),
+ ("caption", models.CharField(blank=True, max_length=255, null=True)),
+ (
+ "collection",
+ models.ForeignKey(
+ default=wagtail.models.get_root_collection_id,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="wagtailcore.Collection",
+ verbose_name="collection",
+ ),
+ ),
+ (
+ "tags",
+ taggit.managers.TaggableManager(
+ blank=True,
+ help_text=None,
+ through="taggit.TaggedItem",
+ to="taggit.Tag",
+ verbose_name="tags",
+ ),
+ ),
+ (
+ "uploaded_by_user",
+ models.ForeignKey(
+ blank=True,
+ editable=False,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ to=settings.AUTH_USER_MODEL,
+ verbose_name="uploaded by user",
+ ),
+ ),
],
options={
- 'abstract': False,
+ "abstract": False,
},
bases=(wagtail.search.index.Indexed, models.Model),
),
migrations.CreateModel(
- name='IETFRendition',
+ name="IETFRendition",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('filter_spec', models.CharField(db_index=True, max_length=255)),
- ('file', models.ImageField(height_field='height', upload_to=wagtail.images.models.get_rendition_upload_to, width_field='width')),
- ('width', models.IntegerField(editable=False)),
- ('height', models.IntegerField(editable=False)),
- ('focal_point_key', models.CharField(blank=True, default='', editable=False, max_length=16)),
- ('image', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='renditions', to='images.IETFImage')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("filter_spec", models.CharField(db_index=True, max_length=255)),
+ (
+ "file",
+ models.ImageField(
+ height_field="height",
+ upload_to=wagtail.images.models.get_rendition_upload_to,
+ width_field="width",
+ ),
+ ),
+ ("width", models.IntegerField(editable=False)),
+ ("height", models.IntegerField(editable=False)),
+ (
+ "focal_point_key",
+ models.CharField(
+ blank=True, default="", editable=False, max_length=16
+ ),
+ ),
+ (
+ "image",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="renditions",
+ to="images.IETFImage",
+ ),
+ ),
],
),
migrations.AlterUniqueTogether(
- name='ietfrendition',
- unique_together=set([('image', 'filter_spec', 'focal_point_key')]),
+ name="ietfrendition",
+ unique_together=set([("image", "filter_spec", "focal_point_key")]),
),
]
diff --git a/ietf/images/migrations/0002_alter_ietfimage_file_hash.py b/ietf/images/migrations/0002_alter_ietfimage_file_hash.py
new file mode 100644
index 00000000..cd64bf42
--- /dev/null
+++ b/ietf/images/migrations/0002_alter_ietfimage_file_hash.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.2.13 on 2022-07-22 02:02
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('images', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='ietfimage',
+ name='file_hash',
+ field=models.CharField(blank=True, db_index=True, editable=False, max_length=40),
+ ),
+ ]
diff --git a/ietf/search/views.py b/ietf/search/views.py
index c1ddab7b..4dd0b0bb 100644
--- a/ietf/search/views.py
+++ b/ietf/search/views.py
@@ -1,17 +1,16 @@
+from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from django.shortcuts import render
-from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
-
-from wagtail.core.models import Page
-from wagtail.search.models import Query
from wagtail.contrib.search_promotions.models import SearchPromotion
+from wagtail.models import Page
+from wagtail.search.models import Query
def search(request):
- search_query = request.GET.get('query', None)
- page = request.GET.get('page', 1)
+ search_query = request.GET.get("query", None)
+ page = request.GET.get("page", 1)
# Search
- if search_query and '\x00' not in search_query:
+ if search_query and "\x00" not in search_query:
search_results = Page.objects.live().search(search_query)
query = Query.get(search_query)
@@ -33,8 +32,12 @@ def search(request):
except EmptyPage:
search_results = paginator.page(paginator.num_pages)
- return render(request, 'search/search.html', {
- 'search_query': search_query,
- 'search_results': search_results,
- 'search_picks': search_picks,
- })
+ return render(
+ request,
+ "search/search.html",
+ {
+ "search_query": search_query,
+ "search_results": search_results,
+ "search_picks": search_picks,
+ },
+ )
diff --git a/ietf/settings/base.py b/ietf/settings/base.py
index 98f05030..2f745a35 100644
--- a/ietf/settings/base.py
+++ b/ietf/settings/base.py
@@ -54,10 +54,9 @@
"wagtail.search",
"wagtail.contrib.search_promotions",
"wagtail.admin",
- "wagtail.core",
+ "wagtail",
"wagtail.contrib.settings",
"wagtail.contrib.table_block",
- "wagtail.contrib.postgres_search",
"wagtail.contrib.routable_page",
"wagtail.contrib.modeladmin",
"modelcluster",
@@ -96,7 +95,9 @@
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
- "DIRS": [os.path.join(PROJECT_DIR, "templates"),],
+ "DIRS": [
+ os.path.join(PROJECT_DIR, "templates"),
+ ],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
@@ -118,7 +119,10 @@
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
DATABASES = {
- "default": {"ENGINE": "django.db.backends.postgresql_psycopg2", "NAME": "ietf",}
+ "default": {
+ "ENGINE": "django.db.backends.postgresql_psycopg2",
+ "NAME": "ietf",
+ }
}
@@ -175,7 +179,9 @@
WAGTAILSEARCH_BACKENDS = {
- "default": {"BACKEND": "wagtail.contrib.postgres_search.backend",},
+ "default": {
+ "BACKEND": "wagtail.search.backends.database",
+ },
}
@@ -192,20 +198,35 @@
WAGTAILIMAGES_IMAGE_MODEL = "images.IETFImage"
WAGTAILDOCS_DOCUMENT_MODEL = "documents.IetfDocument"
WAGTAILADMIN_RICH_TEXT_EDITORS = {
- 'default': {
- 'WIDGET': 'wagtail.admin.rich_text.DraftailRichTextArea',
- 'OPTIONS': {
- 'features': [
- 'h2', 'h3', 'h4', 'h5', 'h6',
- 'ol', 'ul',
- 'bold', 'italic',
- 'superscript', 'subscript', 'strikethrough',
- 'hr', 'link', 'document-link',
- 'image', 'embed',
- 'code', 'blockquote']
- }
+ "default": {
+ "WIDGET": "wagtail.admin.rich_text.DraftailRichTextArea",
+ "OPTIONS": {
+ "features": [
+ "h2",
+ "h3",
+ "h4",
+ "h5",
+ "h6",
+ "ol",
+ "ul",
+ "bold",
+ "italic",
+ "superscript",
+ "subscript",
+ "strikethrough",
+ "hr",
+ "link",
+ "document-link",
+ "image",
+ "embed",
+ "code",
+ "blockquote",
+ ]
+ },
}
}
# Application-wide settings
DATATRACKER_URI = "https://datatracker.ietf.org"
+
+DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
diff --git a/ietf/settings/production.py b/ietf/settings/production.py
index 1aa30161..21af3828 100644
--- a/ietf/settings/production.py
+++ b/ietf/settings/production.py
@@ -42,7 +42,7 @@
ALLOWED_HOSTS = env['ALLOWED_HOSTS'].split(',')
if 'PRIMARY_HOST' in env:
- BASE_URL = 'http://%s/' % env['PRIMARY_HOST']
+ WAGTAILADMIN_BASE_URL = 'http://%s/' % env['PRIMARY_HOST']
if 'SERVER_EMAIL' in env:
SERVER_EMAIL = env['SERVER_EMAIL']
diff --git a/ietf/snippets/migrations/0001_initial.py b/ietf/snippets/migrations/0001_initial.py
index e90d6c10..a5a4beb5 100644
--- a/ietf/snippets/migrations/0001_initial.py
+++ b/ietf/snippets/migrations/0001_initial.py
@@ -2,11 +2,12 @@
# Generated by Django 1.11.29 on 2020-04-10 18:46
from __future__ import unicode_literals
-from django.db import migrations, models
import django.db.models.deletion
-import ietf.snippets.models
-import wagtail.core.fields
+import wagtail.fields
import wagtail.search.index
+from django.db import migrations, models
+
+import ietf.snippets.models
class Migration(migrations.Migration):
@@ -14,183 +15,435 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
- ('images', '0001_initial'),
- ('wagtailcore', '0040_page_draft_title'),
- ('wagtaildocs', '0008_document_file_size'),
+ ("images", "0001_initial"),
+ ("wagtailcore", "0040_page_draft_title"),
+ ("wagtaildocs", "0008_document_file_size"),
]
operations = [
migrations.CreateModel(
- name='CallToAction',
+ name="CallToAction",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('link_external', models.URLField(blank=True, verbose_name='External link')),
- ('title', models.CharField(help_text='Link title', max_length=255)),
- ('blurb', models.CharField(blank=True, help_text='An explanation of the call to action.', max_length=255)),
- ('button_text', models.CharField(help_text='Text that appears on the call to action link.', max_length=255)),
- ('link_document', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtaildocs.Document')),
- ('link_page', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailcore.Page')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "link_external",
+ models.URLField(blank=True, verbose_name="External link"),
+ ),
+ ("title", models.CharField(help_text="Link title", max_length=255)),
+ (
+ "blurb",
+ models.CharField(
+ blank=True,
+ help_text="An explanation of the call to action.",
+ max_length=255,
+ ),
+ ),
+ (
+ "button_text",
+ models.CharField(
+ help_text="Text that appears on the call to action link.",
+ max_length=255,
+ ),
+ ),
+ (
+ "link_document",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="wagtaildocs.Document",
+ ),
+ ),
+ (
+ "link_page",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="wagtailcore.Page",
+ ),
+ ),
],
options={
- 'verbose_name_plural': 'Calls to action',
- 'ordering': ['title'],
+ "verbose_name_plural": "Calls to action",
+ "ordering": ["title"],
},
- bases=(wagtail.search.index.Indexed, models.Model, ietf.snippets.models.RenderableSnippetMixin),
+ bases=(
+ wagtail.search.index.Indexed,
+ models.Model,
+ ietf.snippets.models.RenderableSnippetMixin,
+ ),
),
migrations.CreateModel(
- name='Charter',
+ name="Charter",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('name', models.CharField(max_length=511, unique=True)),
- ('title', models.TextField(blank=True)),
- ('abstract', models.TextField(blank=True)),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("name", models.CharField(max_length=511, unique=True)),
+ ("title", models.TextField(blank=True)),
+ ("abstract", models.TextField(blank=True)),
],
options={
- 'verbose_name': 'Charter',
- 'ordering': ['title'],
+ "verbose_name": "Charter",
+ "ordering": ["title"],
},
bases=(models.Model, wagtail.search.index.Indexed),
),
migrations.CreateModel(
- name='GlossaryItem',
+ name="GlossaryItem",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('title', models.CharField(help_text='The glossary term.', max_length=255)),
- ('body', wagtail.core.fields.RichTextField(help_text='Explanation of the glossary term.')),
- ('link', models.URLField(blank=True)),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "title",
+ models.CharField(help_text="The glossary term.", max_length=255),
+ ),
+ (
+ "body",
+ wagtail.fields.RichTextField(
+ help_text="Explanation of the glossary term."
+ ),
+ ),
+ ("link", models.URLField(blank=True)),
],
options={
- 'verbose_name': 'Glossary item',
- 'ordering': ['title'],
+ "verbose_name": "Glossary item",
+ "ordering": ["title"],
},
bases=(models.Model, wagtail.search.index.Indexed),
),
migrations.CreateModel(
- name='Group',
+ name="Group",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('name', models.CharField(help_text="This group's name.", max_length=255)),
- ('summary', models.CharField(blank=True, help_text='More information about this group.', max_length=511)),
- ('email', models.EmailField(blank=True, help_text="This group's email address.", max_length=254)),
- ('image', models.ForeignKey(blank=True, help_text='An image to represent this group.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='images.IETFImage')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "name",
+ models.CharField(help_text="This group's name.", max_length=255),
+ ),
+ (
+ "summary",
+ models.CharField(
+ blank=True,
+ help_text="More information about this group.",
+ max_length=511,
+ ),
+ ),
+ (
+ "email",
+ models.EmailField(
+ blank=True,
+ help_text="This group's email address.",
+ max_length=254,
+ ),
+ ),
+ (
+ "image",
+ models.ForeignKey(
+ blank=True,
+ help_text="An image to represent this group.",
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
],
options={
- 'ordering': ['name'],
+ "ordering": ["name"],
},
- bases=(models.Model, wagtail.search.index.Indexed, ietf.snippets.models.RenderableSnippetMixin),
+ bases=(
+ models.Model,
+ wagtail.search.index.Indexed,
+ ietf.snippets.models.RenderableSnippetMixin,
+ ),
),
migrations.CreateModel(
- name='MailingListSignup',
+ name="MailingListSignup",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('title', models.CharField(help_text='The header text for this content.', max_length=255)),
- ('blurb', models.CharField(blank=True, help_text='An explanation and call to action for this content.', max_length=255)),
- ('button_text', models.CharField(help_text='Text that appears on the mailing list link.', max_length=255)),
- ('sign_up', models.CharField(blank=True, help_text='The URL or email address where the user should sign up. If the working group is set then this does not need to be set.', max_length=255)),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "title",
+ models.CharField(
+ help_text="The header text for this content.", max_length=255
+ ),
+ ),
+ (
+ "blurb",
+ models.CharField(
+ blank=True,
+ help_text="An explanation and call to action for this content.",
+ max_length=255,
+ ),
+ ),
+ (
+ "button_text",
+ models.CharField(
+ help_text="Text that appears on the mailing list link.",
+ max_length=255,
+ ),
+ ),
+ (
+ "sign_up",
+ models.CharField(
+ blank=True,
+ help_text="The URL or email address where the user should sign up. If the working group is set then this does not need to be set.",
+ max_length=255,
+ ),
+ ),
],
options={
- 'ordering': ['title'],
+ "ordering": ["title"],
},
- bases=(models.Model, wagtail.search.index.Indexed, ietf.snippets.models.RenderableSnippetMixin),
+ bases=(
+ models.Model,
+ wagtail.search.index.Indexed,
+ ietf.snippets.models.RenderableSnippetMixin,
+ ),
),
migrations.CreateModel(
- name='Person',
+ name="Person",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('name', models.CharField(max_length=511)),
- ('link', models.URLField()),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("name", models.CharField(max_length=511)),
+ ("link", models.URLField()),
],
options={
- 'ordering': ['name'],
+ "ordering": ["name"],
},
bases=(models.Model, wagtail.search.index.Indexed),
),
migrations.CreateModel(
- name='RFC',
+ name="RFC",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('name', models.CharField(max_length=511)),
- ('title', models.TextField(blank=True)),
- ('rfc', models.CharField(help_text="The RFC's number (without any letters)", max_length=511, unique=True)),
- ('abstract', models.TextField(blank=True)),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("name", models.CharField(max_length=511)),
+ ("title", models.TextField(blank=True)),
+ (
+ "rfc",
+ models.CharField(
+ help_text="The RFC's number (without any letters)",
+ max_length=511,
+ unique=True,
+ ),
+ ),
+ ("abstract", models.TextField(blank=True)),
],
options={
- 'verbose_name': 'RFC',
- 'ordering': ['title'],
+ "verbose_name": "RFC",
+ "ordering": ["title"],
},
bases=(models.Model, wagtail.search.index.Indexed),
),
migrations.CreateModel(
- name='Role',
+ name="Role",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('name', models.CharField(help_text='A role within the IETF.', max_length=255)),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "name",
+ models.CharField(
+ help_text="A role within the IETF.", max_length=255
+ ),
+ ),
],
options={
- 'verbose_name': 'Role Override',
- 'ordering': ['name'],
+ "verbose_name": "Role Override",
+ "ordering": ["name"],
},
bases=(models.Model, wagtail.search.index.Indexed),
),
migrations.CreateModel(
- name='Sponsor',
+ name="Sponsor",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('title', models.CharField(help_text='The name of the organisation.', max_length=255)),
- ('link', models.URLField(blank=True)),
- ('logo', models.ForeignKey(help_text="The organisation's logo.", on_delete=django.db.models.deletion.CASCADE, related_name='+', to='images.IETFImage')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "title",
+ models.CharField(
+ help_text="The name of the organisation.", max_length=255
+ ),
+ ),
+ ("link", models.URLField(blank=True)),
+ (
+ "logo",
+ models.ForeignKey(
+ help_text="The organisation's logo.",
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
],
options={
- 'ordering': ['title'],
+ "ordering": ["title"],
},
bases=(models.Model, wagtail.search.index.Indexed),
),
migrations.CreateModel(
- name='Topic',
+ name="Topic",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('title', models.CharField(help_text='The name of this topic.', max_length=255)),
- ('slug', models.CharField(max_length=511, unique=True)),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "title",
+ models.CharField(
+ help_text="The name of this topic.", max_length=255
+ ),
+ ),
+ ("slug", models.CharField(max_length=511, unique=True)),
],
options={
- 'ordering': ['title'],
+ "ordering": ["title"],
},
bases=(models.Model, wagtail.search.index.Indexed),
),
migrations.CreateModel(
- name='WorkingGroup',
+ name="WorkingGroup",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('name', models.CharField(max_length=511)),
- ('acronym', models.CharField(blank=True, max_length=511)),
- ('description', models.CharField(blank=True, max_length=4096)),
- ('list_email', models.EmailField(blank=True, max_length=254)),
- ('list_subscribe', models.EmailField(blank=True, max_length=254)),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("name", models.CharField(max_length=511)),
+ ("acronym", models.CharField(blank=True, max_length=511)),
+ ("description", models.CharField(blank=True, max_length=4096)),
+ ("list_email", models.EmailField(blank=True, max_length=254)),
+ ("list_subscribe", models.EmailField(blank=True, max_length=254)),
],
options={
- 'verbose_name': 'Working Group',
- 'ordering': ['name'],
+ "verbose_name": "Working Group",
+ "ordering": ["name"],
},
bases=(models.Model, wagtail.search.index.Indexed),
),
migrations.AddField(
- model_name='rfc',
- name='working_group',
- field=models.ForeignKey(blank=True, help_text='The working group that produced this RFC', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='snippets.WorkingGroup'),
+ model_name="rfc",
+ name="working_group",
+ field=models.ForeignKey(
+ blank=True,
+ help_text="The working group that produced this RFC",
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="snippets.WorkingGroup",
+ ),
),
migrations.AddField(
- model_name='mailinglistsignup',
- name='working_group',
- field=models.ForeignKey(blank=True, help_text='The group whose mailing list sign up address should be used. If sign up is set then this does not need to be set.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='snippets.WorkingGroup'),
+ model_name="mailinglistsignup",
+ name="working_group",
+ field=models.ForeignKey(
+ blank=True,
+ help_text="The group whose mailing list sign up address should be used. If sign up is set then this does not need to be set.",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="snippets.WorkingGroup",
+ ),
),
migrations.AddField(
- model_name='group',
- name='role',
- field=models.ForeignKey(blank=True, help_text="This group's role within the IETF.", null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='snippets.Role'),
+ model_name="group",
+ name="role",
+ field=models.ForeignKey(
+ blank=True,
+ help_text="This group's role within the IETF.",
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="snippets.Role",
+ ),
),
migrations.AddField(
- model_name='charter',
- name='working_group',
- field=models.ForeignKey(blank=True, help_text="This charter's working group", null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='snippets.WorkingGroup'),
+ model_name="charter",
+ name="working_group",
+ field=models.ForeignKey(
+ blank=True,
+ help_text="This charter's working group",
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="snippets.WorkingGroup",
+ ),
),
]
diff --git a/ietf/snippets/models.py b/ietf/snippets/models.py
index d3bf5b4e..358983c0 100644
--- a/ietf/snippets/models.py
+++ b/ietf/snippets/models.py
@@ -1,25 +1,20 @@
+from django.conf import settings
from django.db import models
from django.template.loader import get_template
-from django.conf import settings
-
-from wagtail.snippets.models import register_snippet
-from wagtail.admin.edit_handlers import FieldPanel
-from wagtail.images.edit_handlers import ImageChooserPanel
-from wagtail.snippets.edit_handlers import SnippetChooserPanel
-from wagtail.search.index import Indexed
+from wagtail.admin.panels import FieldPanel
+from wagtail.fields import RichTextField
from wagtail.search import index
-from wagtail.core.fields import RichTextField
+from wagtail.search.index import Indexed
+from wagtail.snippets.models import register_snippet
from ..utils.models import RelatedLink
-class RenderableSnippetMixin():
-
+class RenderableSnippetMixin:
def render(self):
template = get_template(self.TEMPLATE_NAME)
- return template.render(
- {'snippet': self}
- )
+ return template.render({"snippet": self})
+
@register_snippet
class Charter(models.Model, index.Indexed):
@@ -27,16 +22,17 @@ class Charter(models.Model, index.Indexed):
title = models.TextField(blank=True)
abstract = models.TextField(blank=True)
working_group = models.ForeignKey(
- 'snippets.WorkingGroup',
- blank=True, null=True,
- related_name='+',
+ "snippets.WorkingGroup",
+ blank=True,
+ null=True,
+ related_name="+",
help_text="This charter's working group",
on_delete=models.CASCADE,
)
search_fields = [
- index.SearchField('title', partial_match=True, boost=10),
- index.SearchField('abstract'),
+ index.SearchField("title", partial_match=True, boost=10),
+ index.SearchField("abstract"),
]
def __str__(self):
@@ -50,9 +46,10 @@ def url(self):
return ""
class Meta:
- ordering = ['title']
+ ordering = ["title"]
verbose_name = "Charter"
+
@register_snippet
class WorkingGroup(models.Model, index.Indexed):
@@ -64,9 +61,9 @@ class WorkingGroup(models.Model, index.Indexed):
# There is no field currently to capture area/parent
search_fields = [
- index.SearchField('name', partial_match=True, boost=10),
- index.SearchField('acronym'),
- index.SearchField('description'),
+ index.SearchField("name", partial_match=True, boost=10),
+ index.SearchField("acronym"),
+ index.SearchField("description"),
]
@property
@@ -81,30 +78,34 @@ def __str__(self):
return self.name
class Meta:
- ordering = ['name']
+ ordering = ["name"]
verbose_name = "Working Group"
+
@register_snippet
class RFC(models.Model, index.Indexed):
name = models.CharField(max_length=511)
title = models.TextField(blank=True)
- rfc = models.CharField(max_length=511, unique=True, help_text="The RFC's number (without any letters)")
+ rfc = models.CharField(
+ max_length=511, unique=True, help_text="The RFC's number (without any letters)"
+ )
abstract = models.TextField(blank=True)
# There is currently no field for authors
working_group = models.ForeignKey(
- 'snippets.WorkingGroup',
- blank=True, null=True,
- related_name='+',
+ "snippets.WorkingGroup",
+ blank=True,
+ null=True,
+ related_name="+",
help_text="The working group that produced this RFC",
on_delete=models.SET_NULL,
)
search_fields = [
- index.SearchField('title', partial_match=True, boost=10),
- index.SearchField('rfc', boost=10),
- index.SearchField('authors'),
- index.SearchField('abstract'),
+ index.SearchField("title", partial_match=True, boost=10),
+ index.SearchField("rfc", boost=10),
+ index.SearchField("authors"),
+ index.SearchField("abstract"),
]
def __str__(self):
@@ -119,43 +120,38 @@ def url(self):
return settings.DATATRACKER_URI + "/doc/rfc" + self.rfc
class Meta:
- ordering = ['title']
+ ordering = ["title"]
verbose_name = "RFC"
+
@register_snippet
class Person(models.Model, Indexed):
name = models.CharField(max_length=511)
link = models.URLField()
- search_fields = [ index.SearchField('name')]
- panels = [ FieldPanel('name') ]
+ search_fields = [index.SearchField("name")]
+ panels = [FieldPanel("name")]
def __str__(self):
return self.name
class Meta:
- ordering = ['name']
+ ordering = ["name"]
+
@register_snippet
class Role(models.Model, Indexed):
- name = models.CharField(
- max_length=255,
- help_text="A role within the IETF."
- )
+ name = models.CharField(max_length=255, help_text="A role within the IETF.")
- search_fields = [
- index.SearchField('name')
- ]
+ search_fields = [index.SearchField("name")]
- panels = [
- FieldPanel('name')
- ]
+ panels = [FieldPanel("name")]
def __str__(self):
return self.name
class Meta:
- ordering = ['name']
+ ordering = ["name"]
verbose_name = "Role Override"
@@ -165,55 +161,50 @@ class Group(models.Model, Indexed, RenderableSnippetMixin):
A group of people within the IETF. Groups may appear on the site as
:model:`blog.BlogPage` author groups.
"""
- name = models.CharField(
- max_length=255,
- help_text="This group's name."
- )
+
+ name = models.CharField(max_length=255, help_text="This group's name.")
role = models.ForeignKey(
- 'snippets.Role',
- blank=True, null=True,
- related_name='+',
+ "snippets.Role",
+ blank=True,
+ null=True,
+ related_name="+",
help_text="This group's role within the IETF.",
on_delete=models.SET_NULL,
)
summary = models.CharField(
- blank=True,
- max_length=511,
- help_text="More information about this group."
- )
- email = models.EmailField(
- blank=True,
- help_text="This group's email address."
+ blank=True, max_length=511, help_text="More information about this group."
)
+ email = models.EmailField(blank=True, help_text="This group's email address.")
image = models.ForeignKey(
- 'images.IETFImage',
- blank=True, null=True,
- related_name='+',
+ "images.IETFImage",
+ blank=True,
+ null=True,
+ related_name="+",
help_text="An image to represent this group.",
on_delete=models.SET_NULL,
)
search_fields = [
- index.SearchField('name'),
- index.SearchField('summary'),
- index.SearchField('email'),
+ index.SearchField("name"),
+ index.SearchField("summary"),
+ index.SearchField("email"),
]
panels = [
- FieldPanel('name'),
- SnippetChooserPanel('role'),
- FieldPanel('summary'),
- FieldPanel('email'),
- ImageChooserPanel('image')
+ FieldPanel("name"),
+ FieldPanel("role"),
+ FieldPanel("summary"),
+ FieldPanel("email"),
+ FieldPanel("image"),
]
def __str__(self):
return self.name
- TEMPLATE_NAME = 'snippets/group.html'
+ TEMPLATE_NAME = "snippets/group.html"
class Meta:
- ordering = ['name']
+ ordering = ["name"]
@register_snippet
@@ -222,35 +213,33 @@ class CallToAction(Indexed, RelatedLink, RenderableSnippetMixin):
Content that guides the user to the next step after having
read a page.
"""
+
blurb = models.CharField(
- max_length=255,
- blank=True,
- help_text="An explanation of the call to action."
+ max_length=255, blank=True, help_text="An explanation of the call to action."
)
button_text = models.CharField(
- max_length=255,
- help_text="Text that appears on the call to action link."
+ max_length=255, help_text="Text that appears on the call to action link."
)
search_fields = [
- index.SearchField('title'),
- index.SearchField('blurb'),
- index.SearchField('button_text'),
+ index.SearchField("title"),
+ index.SearchField("blurb"),
+ index.SearchField("button_text"),
]
panels = RelatedLink.panels + [
- FieldPanel('blurb'),
- FieldPanel('button_text'),
+ FieldPanel("blurb"),
+ FieldPanel("button_text"),
]
def __str__(self):
return self.title
- TEMPLATE_NAME = 'snippets/call_to_action.html'
+ TEMPLATE_NAME = "snippets/call_to_action.html"
class Meta:
verbose_name_plural = "Calls to action"
- ordering = ['title']
+ ordering = ["title"]
@register_snippet
@@ -259,47 +248,47 @@ class MailingListSignup(models.Model, Indexed, RenderableSnippetMixin):
Page content that directs users to a mailing list sign up link
or address.
"""
+
title = models.CharField(
- max_length=255,
- help_text="The header text for this content."
+ max_length=255, help_text="The header text for this content."
)
blurb = models.CharField(
max_length=255,
blank=True,
- help_text="An explanation and call to action for this content."
+ help_text="An explanation and call to action for this content.",
)
button_text = models.CharField(
- max_length=255,
- help_text="Text that appears on the mailing list link."
+ max_length=255, help_text="Text that appears on the mailing list link."
)
sign_up = models.CharField(
max_length=255,
blank=True,
help_text="The URL or email address where the user should sign up. "
- "If the working group is set then this does not need to be set."
+ "If the working group is set then this does not need to be set.",
)
working_group = models.ForeignKey(
- 'snippets.WorkingGroup',
- null=True, blank=True,
+ "snippets.WorkingGroup",
+ null=True,
+ blank=True,
on_delete=models.SET_NULL,
- related_name='+',
+ related_name="+",
help_text="The group whose mailing list sign up address should be "
- "used. If sign up is set then this does not need to be set."
+ "used. If sign up is set then this does not need to be set.",
)
search_fields = [
- index.SearchField('title'),
- index.SearchField('blurb'),
- index.SearchField('button_text'),
- index.SearchField('sign_up'),
+ index.SearchField("title"),
+ index.SearchField("blurb"),
+ index.SearchField("button_text"),
+ index.SearchField("sign_up"),
]
panels = [
- FieldPanel('title'),
- FieldPanel('blurb'),
- FieldPanel('button_text'),
- FieldPanel('sign_up'),
- FieldPanel('working_group'),
+ FieldPanel("title"),
+ FieldPanel("blurb"),
+ FieldPanel("button_text"),
+ FieldPanel("sign_up"),
+ FieldPanel("working_group"),
]
@property
@@ -309,47 +298,44 @@ def link(self):
else:
link = self.working_group.list_subscribe
- if '@' in link:
- return 'mailto:{}'.format(link)
+ if "@" in link:
+ return "mailto:{}".format(link)
else:
return link
- TEMPLATE_NAME = 'snippets/mailing_list_signup.html'
+ TEMPLATE_NAME = "snippets/mailing_list_signup.html"
def __str__(self):
return self.title
class Meta:
- ordering = ['title']
+ ordering = ["title"]
@register_snippet
class Topic(models.Model, Indexed):
"""
- These snippets categorise blog posts.
+ These snippets categorise blog posts.
"""
- title = models.CharField(
- max_length=255,
- help_text="The name of this topic."
- )
- slug = models.CharField(max_length=511, unique=True)
+ title = models.CharField(max_length=255, help_text="The name of this topic.")
+ slug = models.CharField(max_length=511, unique=True)
search_fields = [
- index.SearchField('title'),
- index.SearchField('slug'),
+ index.SearchField("title"),
+ index.SearchField("slug"),
]
panels = [
- FieldPanel('title'),
- FieldPanel('slug'),
+ FieldPanel("title"),
+ FieldPanel("slug"),
]
def __str__(self):
return self.title
class Meta:
- ordering = ['title']
+ ordering = ["title"]
@register_snippet
@@ -357,33 +343,27 @@ class Sponsor(models.Model, Indexed):
"""
An organisation that sponsors IETF events.
"""
- title = models.CharField(
- max_length=255,
- help_text="The name of the organisation."
- )
+
+ title = models.CharField(max_length=255, help_text="The name of the organisation.")
logo = models.ForeignKey(
- 'images.IETFImage',
- related_name='+',
+ "images.IETFImage",
+ related_name="+",
help_text="The organisation's logo.",
- on_delete = models.CASCADE,
+ on_delete=models.CASCADE,
)
link = models.URLField(blank=True)
search_fields = [
- index.SearchField('title'),
+ index.SearchField("title"),
]
- panels = [
- FieldPanel('title'),
- ImageChooserPanel('logo'),
- FieldPanel('link')
- ]
+ panels = [FieldPanel("title"), FieldPanel("logo"), FieldPanel("link")]
def __str__(self):
return self.title
class Meta:
- ordering = ['title']
+ ordering = ["title"]
@register_snippet
@@ -392,24 +372,20 @@ class GlossaryItem(models.Model, Indexed):
A short explanation of a technical term.
Appears on the :models:`glossary.GlossaryPage`.
"""
- title = models.CharField(
- max_length=255,
- help_text="The glossary term."
- )
- body = RichTextField(
- help_text="Explanation of the glossary term."
- )
+
+ title = models.CharField(max_length=255, help_text="The glossary term.")
+ body = RichTextField(help_text="Explanation of the glossary term.")
link = models.URLField(blank=True)
search_fields = [
- index.SearchField('title'),
- index.SearchField('body'),
+ index.SearchField("title"),
+ index.SearchField("body"),
]
panels = [
- FieldPanel('title'),
- FieldPanel('body'),
- FieldPanel('link'),
+ FieldPanel("title"),
+ FieldPanel("body"),
+ FieldPanel("link"),
]
def __str__(self):
@@ -418,9 +394,9 @@ def __str__(self):
@property
def url(self):
from ietf.glossary.models import GlossaryPage
- return "{}?query={}".format(GlossaryPage.objects.first().url,
- self.title)
+
+ return "{}?query={}".format(GlossaryPage.objects.first().url, self.title)
class Meta:
- ordering = ['title']
+ ordering = ["title"]
verbose_name = "Glossary item"
diff --git a/ietf/standard/migrations/0001_initial.py b/ietf/standard/migrations/0001_initial.py
index cfd1c51c..d276a7ee 100644
--- a/ietf/standard/migrations/0001_initial.py
+++ b/ietf/standard/migrations/0001_initial.py
@@ -2,14 +2,14 @@
# Generated by Django 1.11.29 on 2020-04-10 18:46
from __future__ import unicode_literals
-from django.db import migrations, models
import django.db.models.deletion
import modelcluster.fields
+import wagtail.blocks
import wagtail.contrib.table_block.blocks
-import wagtail.core.blocks
-import wagtail.core.fields
import wagtail.embeds.blocks
+import wagtail.fields
import wagtail.images.blocks
+from django.db import migrations, models
class Migration(migrations.Migration):
@@ -17,93 +17,414 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
- ('wagtaildocs', '0008_document_file_size'),
- ('wagtailcore', '0040_page_draft_title'),
- ('images', '0001_initial'),
- ('snippets', '0001_initial'),
+ ("wagtaildocs", "0008_document_file_size"),
+ ("wagtailcore", "0040_page_draft_title"),
+ ("images", "0001_initial"),
+ ("snippets", "0001_initial"),
]
operations = [
migrations.CreateModel(
- name='StandardIndexPage',
+ name="StandardIndexPage",
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')),
- ('social_text', models.CharField(blank=True, help_text='Description of this page as it should appear when shared on social networks, or in Google results', max_length=255)),
- ('introduction', models.CharField(blank=True, help_text='Enter the title to display on the page, you can use only 255 characters.', max_length=255)),
- ('key_info', wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}))], blank=True)),
- ('in_depth', wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}))], blank=True)),
- ('feed_image', models.ForeignKey(blank=True, help_text='This image will be used in listings and indexes across the site, if no feed image is added, the social image will be used.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')),
- ('social_image', models.ForeignKey(blank=True, help_text="Image to appear alongside 'social text', particularly for sharing on social networks", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')),
+ (
+ "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",
+ ),
+ ),
+ (
+ "social_text",
+ models.CharField(
+ blank=True,
+ help_text="Description of this page as it should appear when shared on social networks, or in Google results",
+ max_length=255,
+ ),
+ ),
+ (
+ "introduction",
+ models.CharField(
+ blank=True,
+ help_text="Enter the title to display on the page, you can use only 255 characters.",
+ max_length=255,
+ ),
+ ),
+ (
+ "key_info",
+ wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ (
+ "raw_html",
+ wagtail.blocks.RawHTMLBlock(icon="placeholder"),
+ ),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"}
+ ),
+ ),
+ ],
+ blank=True,
+ ),
+ ),
+ (
+ "in_depth",
+ wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ (
+ "raw_html",
+ wagtail.blocks.RawHTMLBlock(icon="placeholder"),
+ ),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"}
+ ),
+ ),
+ ],
+ blank=True,
+ ),
+ ),
+ (
+ "feed_image",
+ models.ForeignKey(
+ blank=True,
+ help_text="This image will be used in listings and indexes across the site, if no feed image is added, the social image will be used.",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
+ (
+ "social_image",
+ models.ForeignKey(
+ blank=True,
+ help_text="Image to appear alongside 'social text', particularly for sharing on social networks",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
],
options={
- 'verbose_name': 'Index Page',
+ "verbose_name": "Index Page",
},
- bases=('wagtailcore.page', models.Model),
+ bases=("wagtailcore.page", models.Model),
),
migrations.CreateModel(
- name='StandardPage',
+ name="StandardPage",
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')),
- ('social_text', models.CharField(blank=True, help_text='Description of this page as it should appear when shared on social networks, or in Google results', max_length=255)),
- ('introduction', models.CharField(blank=True, help_text='Enter the title to display on the page, you can use only 255 characters.', max_length=255)),
- ('key_info', wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}))], blank=True)),
- ('in_depth', wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}))], blank=True)),
- ('prepared_key_info', models.TextField(blank=True, help_text='The prepared key info field after bibliography styling has been applied. Auto-generated on each save.', null=True)),
- ('prepared_in_depth', models.TextField(blank=True, help_text='The prepared in depth field after bibliography styling has been applied. Auto-generated on each save.', null=True)),
- ('call_to_action', models.ForeignKey(blank=True, help_text='Specify the page you would like visitors to go to next.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='snippets.CallToAction')),
- ('feed_image', models.ForeignKey(blank=True, help_text='This image will be used in listings and indexes across the site, if no feed image is added, the social image will be used.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')),
- ('mailing_list_signup', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='snippets.MailingListSignup')),
- ('social_image', models.ForeignKey(blank=True, help_text="Image to appear alongside 'social text', particularly for sharing on social networks", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')),
+ (
+ "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",
+ ),
+ ),
+ (
+ "social_text",
+ models.CharField(
+ blank=True,
+ help_text="Description of this page as it should appear when shared on social networks, or in Google results",
+ max_length=255,
+ ),
+ ),
+ (
+ "introduction",
+ models.CharField(
+ blank=True,
+ help_text="Enter the title to display on the page, you can use only 255 characters.",
+ max_length=255,
+ ),
+ ),
+ (
+ "key_info",
+ wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ (
+ "raw_html",
+ wagtail.blocks.RawHTMLBlock(icon="placeholder"),
+ ),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"}
+ ),
+ ),
+ ],
+ blank=True,
+ ),
+ ),
+ (
+ "in_depth",
+ wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ (
+ "raw_html",
+ wagtail.blocks.RawHTMLBlock(icon="placeholder"),
+ ),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"}
+ ),
+ ),
+ ],
+ blank=True,
+ ),
+ ),
+ (
+ "prepared_key_info",
+ models.TextField(
+ blank=True,
+ help_text="The prepared key info field after bibliography styling has been applied. Auto-generated on each save.",
+ null=True,
+ ),
+ ),
+ (
+ "prepared_in_depth",
+ models.TextField(
+ blank=True,
+ help_text="The prepared in depth field after bibliography styling has been applied. Auto-generated on each save.",
+ null=True,
+ ),
+ ),
+ (
+ "call_to_action",
+ models.ForeignKey(
+ blank=True,
+ help_text="Specify the page you would like visitors to go to next.",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="snippets.CallToAction",
+ ),
+ ),
+ (
+ "feed_image",
+ models.ForeignKey(
+ blank=True,
+ help_text="This image will be used in listings and indexes across the site, if no feed image is added, the social image will be used.",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
+ (
+ "mailing_list_signup",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="snippets.MailingListSignup",
+ ),
+ ),
+ (
+ "social_image",
+ models.ForeignKey(
+ blank=True,
+ help_text="Image to appear alongside 'social text', particularly for sharing on social networks",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
],
options={
- 'abstract': False,
+ "abstract": False,
},
- bases=('wagtailcore.page', models.Model),
+ bases=("wagtailcore.page", models.Model),
),
migrations.CreateModel(
- name='StandardPageFAQItem',
+ name="StandardPageFAQItem",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
- ('question', models.TextField()),
- ('answer', models.TextField()),
- ('page', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='faq_items', to='standard.StandardPage')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "sort_order",
+ models.IntegerField(blank=True, editable=False, null=True),
+ ),
+ ("question", models.TextField()),
+ ("answer", models.TextField()),
+ (
+ "page",
+ modelcluster.fields.ParentalKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="faq_items",
+ to="standard.StandardPage",
+ ),
+ ),
],
options={
- 'ordering': ['sort_order'],
- 'abstract': False,
+ "ordering": ["sort_order"],
+ "abstract": False,
},
),
migrations.CreateModel(
- name='StandardPageFeedRelatedLink',
+ name="StandardPageFeedRelatedLink",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
- ('link_external', models.URLField(blank=True, verbose_name='External link')),
- ('title', models.CharField(help_text='Link title', max_length=255)),
- ('link_document', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtaildocs.Document')),
- ('link_page', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailcore.Page')),
- ('page', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='feed_related_links', to='standard.StandardPage')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "sort_order",
+ models.IntegerField(blank=True, editable=False, null=True),
+ ),
+ (
+ "link_external",
+ models.URLField(blank=True, verbose_name="External link"),
+ ),
+ ("title", models.CharField(help_text="Link title", max_length=255)),
+ (
+ "link_document",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="wagtaildocs.Document",
+ ),
+ ),
+ (
+ "link_page",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="wagtailcore.Page",
+ ),
+ ),
+ (
+ "page",
+ modelcluster.fields.ParentalKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="feed_related_links",
+ to="standard.StandardPage",
+ ),
+ ),
],
options={
- 'ordering': ['sort_order'],
- 'abstract': False,
+ "ordering": ["sort_order"],
+ "abstract": False,
},
),
migrations.CreateModel(
- name='StandardPageRelatedLink',
+ name="StandardPageRelatedLink",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
- ('link_external', models.URLField(blank=True, verbose_name='External link')),
- ('title', models.CharField(help_text='Link title', max_length=255)),
- ('link_document', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtaildocs.Document')),
- ('link_page', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailcore.Page')),
- ('page', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='related_links', to='standard.StandardPage')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "sort_order",
+ models.IntegerField(blank=True, editable=False, null=True),
+ ),
+ (
+ "link_external",
+ models.URLField(blank=True, verbose_name="External link"),
+ ),
+ ("title", models.CharField(help_text="Link title", max_length=255)),
+ (
+ "link_document",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="wagtaildocs.Document",
+ ),
+ ),
+ (
+ "link_page",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="wagtailcore.Page",
+ ),
+ ),
+ (
+ "page",
+ modelcluster.fields.ParentalKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="related_links",
+ to="standard.StandardPage",
+ ),
+ ),
],
options={
- 'ordering': ['sort_order'],
- 'abstract': False,
+ "ordering": ["sort_order"],
+ "abstract": False,
},
),
]
diff --git a/ietf/standard/migrations/0002_auto_20210325_0442.py b/ietf/standard/migrations/0002_auto_20210325_0442.py
index b9f52b52..c36270e4 100644
--- a/ietf/standard/migrations/0002_auto_20210325_0442.py
+++ b/ietf/standard/migrations/0002_auto_20210325_0442.py
@@ -1,38 +1,122 @@
# Generated by Django 2.2.16 on 2021-03-25 04:42
-from django.db import migrations
+import wagtail.blocks
import wagtail.contrib.table_block.blocks
-import wagtail.core.blocks
-import wagtail.core.fields
import wagtail.embeds.blocks
+import wagtail.fields
import wagtail.images.blocks
+from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
- ('standard', '0001_initial'),
+ ("standard", "0001_initial"),
]
operations = [
migrations.AlterField(
- model_name='standardindexpage',
- name='in_depth',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True),
+ model_name="standardindexpage",
+ name="in_depth",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ],
+ blank=True,
+ ),
),
migrations.AlterField(
- model_name='standardindexpage',
- name='key_info',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True),
+ model_name="standardindexpage",
+ name="key_info",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ],
+ blank=True,
+ ),
),
migrations.AlterField(
- model_name='standardpage',
- name='in_depth',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True),
+ model_name="standardpage",
+ name="in_depth",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ],
+ blank=True,
+ ),
),
migrations.AlterField(
- model_name='standardpage',
- name='key_info',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True),
+ model_name="standardpage",
+ name="key_info",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ],
+ blank=True,
+ ),
),
]
diff --git a/ietf/standard/migrations/0003_auto_20211101_0113.py b/ietf/standard/migrations/0003_auto_20211101_0113.py
index 0d5d9876..d110b881 100644
--- a/ietf/standard/migrations/0003_auto_20211101_0113.py
+++ b/ietf/standard/migrations/0003_auto_20211101_0113.py
@@ -1,39 +1,127 @@
# Generated by Django 2.2.19 on 2021-11-01 01:13
-from django.db import migrations
+import wagtail.blocks
import wagtail.contrib.table_block.blocks
-import wagtail.core.blocks
-import wagtail.core.fields
import wagtail.embeds.blocks
+import wagtail.fields
import wagtail.images.blocks
import wagtailmarkdown.blocks
+from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
- ('standard', '0002_auto_20210325_0442'),
+ ("standard", "0002_auto_20210325_0442"),
]
operations = [
migrations.AlterField(
- model_name='standardindexpage',
- name='in_depth',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('markdown', wagtailmarkdown.blocks.MarkdownBlock(icon='code')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True),
+ model_name="standardindexpage",
+ name="in_depth",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("markdown", wagtailmarkdown.blocks.MarkdownBlock(icon="code")),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ],
+ blank=True,
+ ),
),
migrations.AlterField(
- model_name='standardindexpage',
- name='key_info',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('markdown', wagtailmarkdown.blocks.MarkdownBlock(icon='code')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True),
+ model_name="standardindexpage",
+ name="key_info",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("markdown", wagtailmarkdown.blocks.MarkdownBlock(icon="code")),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ],
+ blank=True,
+ ),
),
migrations.AlterField(
- model_name='standardpage',
- name='in_depth',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('markdown', wagtailmarkdown.blocks.MarkdownBlock(icon='code')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True),
+ model_name="standardpage",
+ name="in_depth",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("markdown", wagtailmarkdown.blocks.MarkdownBlock(icon="code")),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ],
+ blank=True,
+ ),
),
migrations.AlterField(
- model_name='standardpage',
- name='key_info',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('markdown', wagtailmarkdown.blocks.MarkdownBlock(icon='code')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True),
+ model_name="standardpage",
+ name="key_info",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("markdown", wagtailmarkdown.blocks.MarkdownBlock(icon="code")),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ],
+ blank=True,
+ ),
),
]
diff --git a/ietf/standard/migrations/0004_auto_20220902_0524.py b/ietf/standard/migrations/0004_auto_20220902_0524.py
new file mode 100644
index 00000000..bfc31686
--- /dev/null
+++ b/ietf/standard/migrations/0004_auto_20220902_0524.py
@@ -0,0 +1,39 @@
+# Generated by Django 3.2.13 on 2022-09-02 04:24
+
+from django.db import migrations
+import wagtail.blocks
+import wagtail.contrib.table_block.blocks
+import wagtail.embeds.blocks
+import wagtail.fields
+import wagtail.images.blocks
+import wagtailmarkdown.blocks
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('standard', '0003_auto_20211101_0113'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='standardindexpage',
+ name='in_depth',
+ field=wagtail.fields.StreamField([('heading', wagtail.blocks.CharBlock(icon='title')), ('paragraph', wagtail.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('markdown', wagtailmarkdown.blocks.MarkdownBlock(icon='code')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True, use_json_field=True),
+ ),
+ migrations.AlterField(
+ model_name='standardindexpage',
+ name='key_info',
+ field=wagtail.fields.StreamField([('heading', wagtail.blocks.CharBlock(icon='title')), ('paragraph', wagtail.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('markdown', wagtailmarkdown.blocks.MarkdownBlock(icon='code')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True, use_json_field=True),
+ ),
+ migrations.AlterField(
+ model_name='standardpage',
+ name='in_depth',
+ field=wagtail.fields.StreamField([('heading', wagtail.blocks.CharBlock(icon='title')), ('paragraph', wagtail.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('markdown', wagtailmarkdown.blocks.MarkdownBlock(icon='code')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True, use_json_field=True),
+ ),
+ migrations.AlterField(
+ model_name='standardpage',
+ name='key_info',
+ field=wagtail.fields.StreamField([('heading', wagtail.blocks.CharBlock(icon='title')), ('paragraph', wagtail.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('markdown', wagtailmarkdown.blocks.MarkdownBlock(icon='code')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True, use_json_field=True),
+ ),
+ ]
diff --git a/ietf/standard/models.py b/ietf/standard/models.py
index a9f47161..f352ee47 100644
--- a/ietf/standard/models.py
+++ b/ietf/standard/models.py
@@ -1,22 +1,15 @@
from collections import OrderedDict
from django.db import models
-
-from wagtail.core.models import Page, Orderable
-from wagtail.core.fields import StreamField
-from wagtail.admin.edit_handlers import (
- FieldPanel, StreamFieldPanel, InlinePanel
-)
-from wagtail.snippets.edit_handlers import (
- SnippetChooserPanel,
-)
-from wagtail.search import index
-
from modelcluster.fields import ParentalKey
+from wagtail.admin.panels import FieldPanel, InlinePanel
+from wagtail.fields import StreamField
+from wagtail.models import Orderable, Page
+from wagtail.search import index
-from ..utils.models import PromoteMixin, RelatedLink
-from ..utils.blocks import StandardBlock
from ..bibliography.models import BibliographyMixin
+from ..utils.blocks import StandardBlock
+from ..utils.models import PromoteMixin, RelatedLink
class StandardPageFAQItem(Orderable, models.Model):
@@ -24,24 +17,20 @@ class StandardPageFAQItem(Orderable, models.Model):
A question and answer pair that can be added to a Standard
Page.
"""
- page = ParentalKey('standard.StandardPage',
- related_name='faq_items')
+
+ page = ParentalKey("standard.StandardPage", related_name="faq_items")
question = models.TextField()
answer = models.TextField()
- panels = [
- FieldPanel('question'),
- FieldPanel('answer')
- ]
+ panels = [FieldPanel("question"), FieldPanel("answer")]
class StandardPageFeedRelatedLink(Orderable, RelatedLink):
- page = ParentalKey('standard.StandardPage',
- related_name='feed_related_links')
+ page = ParentalKey("standard.StandardPage", related_name="feed_related_links")
class StandardPageRelatedLink(Orderable, RelatedLink):
- page = ParentalKey('standard.StandardPage', related_name='related_links')
+ page = ParentalKey("standard.StandardPage", related_name="related_links")
class StandardPage(Page, BibliographyMixin, PromoteMixin):
@@ -49,43 +38,49 @@ class StandardPage(Page, BibliographyMixin, PromoteMixin):
blank=True,
max_length=255,
help_text="Enter the title to display on the page, "
- "you can use only 255 characters."
+ "you can use only 255 characters.",
)
- key_info = StreamField(StandardBlock(required=False), blank=True)
- in_depth = StreamField(StandardBlock(required=False), blank=True)
+ key_info = StreamField(StandardBlock(required=False), blank=True, use_json_field=True)
+ in_depth = StreamField(StandardBlock(required=False), blank=True, use_json_field=True)
call_to_action = models.ForeignKey(
- 'snippets.CallToAction',
- null=True, blank=True,
+ "snippets.CallToAction",
+ null=True,
+ blank=True,
on_delete=models.SET_NULL,
- related_name='+',
- help_text="Specify the page you would like visitors to go to next."
+ related_name="+",
+ help_text="Specify the page you would like visitors to go to next.",
)
mailing_list_signup = models.ForeignKey(
- 'snippets.MailingListSignup',
+ "snippets.MailingListSignup",
null=True,
- blank=True, on_delete=models.SET_NULL,
- related_name='+'
+ blank=True,
+ on_delete=models.SET_NULL,
+ related_name="+",
)
search_fields = Page.search_fields + [
- index.SearchField('introduction'),
- index.SearchField('key_info'),
- index.SearchField('in_depth'),
+ index.SearchField("introduction"),
+ index.SearchField("key_info"),
+ index.SearchField("in_depth"),
]
# for bibliography
prepared_key_info = models.TextField(
- blank=True, null=True,
+ blank=True,
+ null=True,
help_text="The prepared key info field after bibliography styling has been applied. Auto-generated on each save.",
)
prepared_in_depth = models.TextField(
- blank=True, null=True,
+ blank=True,
+ null=True,
help_text="The prepared in depth field after bibliography styling has been applied. Auto-generated on each save.",
)
- CONTENT_FIELD_MAP = OrderedDict([
- ('key_info', 'prepared_key_info'),
- ('in_depth', 'prepared_in_depth'),
- ])
+ CONTENT_FIELD_MAP = OrderedDict(
+ [
+ ("key_info", "prepared_key_info"),
+ ("in_depth", "prepared_in_depth"),
+ ]
+ )
@property
def feed_text(self):
@@ -96,42 +91,47 @@ def siblings(self):
return self.get_siblings().live().public().filter(show_in_menus=True).specific()
def serve_preview(self, request, mode_name):
- """ This is another hack to overcome the MRO issue we were seeing """
+ """This is another hack to overcome the MRO issue we were seeing"""
return BibliographyMixin.serve_preview(self, request, mode_name)
StandardPage.content_panels = Page.content_panels + [
- FieldPanel('introduction'),
- StreamFieldPanel('key_info'),
- StreamFieldPanel('in_depth'),
- SnippetChooserPanel('call_to_action'),
- SnippetChooserPanel('mailing_list_signup'),
- InlinePanel('related_links', label="Related Links"),
- InlinePanel('faq_items', label="FAQ Items"),
+ FieldPanel("introduction"),
+ FieldPanel("key_info"),
+ FieldPanel("in_depth"),
+ FieldPanel("call_to_action"),
+ FieldPanel("mailing_list_signup"),
+ InlinePanel("related_links", label="Related Links"),
+ InlinePanel("faq_items", label="FAQ Items"),
]
-StandardPage.promote_panels = Page.promote_panels + PromoteMixin.panels + [
- InlinePanel('feed_related_links', label="Feed related Links"),
-]
+StandardPage.promote_panels = (
+ Page.promote_panels
+ + PromoteMixin.panels
+ + [
+ InlinePanel("feed_related_links", label="Feed related Links"),
+ ]
+)
class StandardIndexPage(Page, PromoteMixin):
"""
An index for standard pages.
"""
+
introduction = models.CharField(
blank=True,
max_length=255,
help_text="Enter the title to display on the page, "
- "you can use only 255 characters."
+ "you can use only 255 characters.",
)
- key_info = StreamField(StandardBlock(required=False), blank=True)
- in_depth = StreamField(StandardBlock(required=False), blank=True)
+ key_info = StreamField(StandardBlock(required=False), blank=True, use_json_field=True)
+ in_depth = StreamField(StandardBlock(required=False), blank=True, use_json_field=True)
search_fields = Page.search_fields + [
- index.SearchField('introduction'),
- index.SearchField('key_info'),
- index.SearchField('in_depth'),
+ index.SearchField("introduction"),
+ index.SearchField("key_info"),
+ index.SearchField("in_depth"),
]
@property
@@ -143,9 +143,9 @@ class Meta:
StandardIndexPage.content_panels = Page.content_panels + [
- FieldPanel('introduction'),
- StreamFieldPanel('key_info'),
- StreamFieldPanel('in_depth'),
+ FieldPanel("introduction"),
+ FieldPanel("key_info"),
+ FieldPanel("in_depth"),
]
StandardIndexPage.promote_panels = Page.promote_panels + PromoteMixin.panels
diff --git a/ietf/standard/tests.py b/ietf/standard/tests.py
index 846bd249..6ac4bae1 100644
--- a/ietf/standard/tests.py
+++ b/ietf/standard/tests.py
@@ -1,23 +1,22 @@
from django.test import TestCase
+from wagtail.models import Page, Site
-from .models import StandardPage, StandardIndexPage
from ..home.models import HomePage
+from .models import StandardIndexPage, StandardPage
-from wagtail.core.models import Page, Site
class StandardPageTests(TestCase):
-
def test_standard_page(self):
root = Page.get_first_root_node()
home = HomePage(
- slug = 'homepageslug',
- title = 'home page title',
- heading = 'home page heading',
- introduction = 'home page introduction',
- request_for_comments_section_body = 'rfc section body',
- working_groups_section_body = 'wg section body',
+ slug="homepageslug",
+ title="home page title",
+ heading="home page heading",
+ introduction="home page introduction",
+ request_for_comments_section_body="rfc section body",
+ working_groups_section_body="wg section body",
)
root.add_child(instance=home)
@@ -25,25 +24,25 @@ def test_standard_page(self):
Site.objects.all().delete()
Site.objects.create(
- hostname='localhost',
- root_page = home,
+ hostname="localhost",
+ root_page=home,
is_default_site=True,
- site_name='testingsitename',
+ site_name="testingsitename",
)
standardindex = StandardIndexPage(
- slug = 'standardindex',
- title = 'standard index page title',
- introduction = 'standard index page introduction'
+ slug="standardindex",
+ title="standard index page title",
+ introduction="standard index page introduction",
)
- home.add_child(instance = standardindex)
+ home.add_child(instance=standardindex)
standardpage = StandardPage(
- slug = 'standard',
- title = 'standard title',
- introduction = 'standard introduction',
+ slug="standard",
+ title="standard title",
+ introduction="standard introduction",
)
- standardindex.add_child(instance = standardpage)
+ standardindex.add_child(instance=standardpage)
rindex = self.client.get(path=standardindex.url)
self.assertEqual(rindex.status_code, 200)
diff --git a/ietf/topics/migrations/0001_initial.py b/ietf/topics/migrations/0001_initial.py
index cab5b311..e67fd6fc 100644
--- a/ietf/topics/migrations/0001_initial.py
+++ b/ietf/topics/migrations/0001_initial.py
@@ -2,14 +2,14 @@
# Generated by Django 1.11.29 on 2020-04-10 18:46
from __future__ import unicode_literals
-from django.db import migrations, models
import django.db.models.deletion
import modelcluster.fields
+import wagtail.blocks
import wagtail.contrib.table_block.blocks
-import wagtail.core.blocks
-import wagtail.core.fields
import wagtail.embeds.blocks
+import wagtail.fields
import wagtail.images.blocks
+from django.db import migrations, models
class Migration(migrations.Migration):
@@ -17,67 +17,258 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
- ('images', '0001_initial'),
- ('snippets', '0001_initial'),
- ('wagtaildocs', '0008_document_file_size'),
- ('wagtailcore', '0040_page_draft_title'),
+ ("images", "0001_initial"),
+ ("snippets", "0001_initial"),
+ ("wagtaildocs", "0008_document_file_size"),
+ ("wagtailcore", "0040_page_draft_title"),
]
operations = [
migrations.CreateModel(
- name='PrimaryTopicPage',
+ name="PrimaryTopicPage",
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')),
- ('social_text', models.CharField(blank=True, help_text='Description of this page as it should appear when shared on social networks, or in Google results', max_length=255)),
- ('introduction', models.CharField(blank=True, help_text='Enter the title to display on the page, you can use only 255 characters.', max_length=255)),
- ('key_info', wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}))], blank=True)),
- ('in_depth', wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}))], blank=True)),
- ('call_to_action', models.ForeignKey(blank=True, help_text='Will only be displayed if no mailing list signup is selected.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='snippets.CallToAction')),
- ('feed_image', models.ForeignKey(blank=True, help_text='This image will be used in listings and indexes across the site, if no feed image is added, the social image will be used.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')),
- ('mailing_list_signup', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='snippets.MailingListSignup')),
- ('social_image', models.ForeignKey(blank=True, help_text="Image to appear alongside 'social text', particularly for sharing on social networks", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')),
+ (
+ "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",
+ ),
+ ),
+ (
+ "social_text",
+ models.CharField(
+ blank=True,
+ help_text="Description of this page as it should appear when shared on social networks, or in Google results",
+ max_length=255,
+ ),
+ ),
+ (
+ "introduction",
+ models.CharField(
+ blank=True,
+ help_text="Enter the title to display on the page, you can use only 255 characters.",
+ max_length=255,
+ ),
+ ),
+ (
+ "key_info",
+ wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ (
+ "raw_html",
+ wagtail.blocks.RawHTMLBlock(icon="placeholder"),
+ ),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"}
+ ),
+ ),
+ ],
+ blank=True,
+ ),
+ ),
+ (
+ "in_depth",
+ wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ (
+ "raw_html",
+ wagtail.blocks.RawHTMLBlock(icon="placeholder"),
+ ),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"}
+ ),
+ ),
+ ],
+ blank=True,
+ ),
+ ),
+ (
+ "call_to_action",
+ models.ForeignKey(
+ blank=True,
+ help_text="Will only be displayed if no mailing list signup is selected.",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="snippets.CallToAction",
+ ),
+ ),
+ (
+ "feed_image",
+ models.ForeignKey(
+ blank=True,
+ help_text="This image will be used in listings and indexes across the site, if no feed image is added, the social image will be used.",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
+ (
+ "mailing_list_signup",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="snippets.MailingListSignup",
+ ),
+ ),
+ (
+ "social_image",
+ models.ForeignKey(
+ blank=True,
+ help_text="Image to appear alongside 'social text', particularly for sharing on social networks",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
],
options={
- 'verbose_name': 'Topic Page',
+ "verbose_name": "Topic Page",
},
- bases=('wagtailcore.page', models.Model),
+ bases=("wagtailcore.page", models.Model),
),
migrations.CreateModel(
- name='PrimaryTopicPageRelatedLink',
+ name="PrimaryTopicPageRelatedLink",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
- ('link_external', models.URLField(blank=True, verbose_name='External link')),
- ('title', models.CharField(help_text='Link title', max_length=255)),
- ('link_document', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtaildocs.Document')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "sort_order",
+ models.IntegerField(blank=True, editable=False, null=True),
+ ),
+ (
+ "link_external",
+ models.URLField(blank=True, verbose_name="External link"),
+ ),
+ ("title", models.CharField(help_text="Link title", max_length=255)),
+ (
+ "link_document",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="wagtaildocs.Document",
+ ),
+ ),
],
options={
- 'ordering': ['sort_order'],
- 'abstract': False,
+ "ordering": ["sort_order"],
+ "abstract": False,
},
),
migrations.CreateModel(
- name='TopicIndexPage',
+ name="TopicIndexPage",
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')),
- ('social_text', models.CharField(blank=True, help_text='Description of this page as it should appear when shared on social networks, or in Google results', max_length=255)),
- ('introduction', models.CharField(help_text='Enter the introduction to display on the page, you can use only 255 characters.', max_length=255)),
- ('feed_image', models.ForeignKey(blank=True, help_text='This image will be used in listings and indexes across the site, if no feed image is added, the social image will be used.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')),
- ('social_image', models.ForeignKey(blank=True, help_text="Image to appear alongside 'social text', particularly for sharing on social networks", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')),
+ (
+ "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",
+ ),
+ ),
+ (
+ "social_text",
+ models.CharField(
+ blank=True,
+ help_text="Description of this page as it should appear when shared on social networks, or in Google results",
+ max_length=255,
+ ),
+ ),
+ (
+ "introduction",
+ models.CharField(
+ help_text="Enter the introduction to display on the page, you can use only 255 characters.",
+ max_length=255,
+ ),
+ ),
+ (
+ "feed_image",
+ models.ForeignKey(
+ blank=True,
+ help_text="This image will be used in listings and indexes across the site, if no feed image is added, the social image will be used.",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
+ (
+ "social_image",
+ models.ForeignKey(
+ blank=True,
+ help_text="Image to appear alongside 'social text', particularly for sharing on social networks",
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.IETFImage",
+ ),
+ ),
],
options={
- 'verbose_name': 'Topic Page List',
+ "verbose_name": "Topic Page List",
},
- bases=('wagtailcore.page', models.Model),
+ bases=("wagtailcore.page", models.Model),
),
migrations.AddField(
- model_name='primarytopicpagerelatedlink',
- name='link_page',
- field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailcore.Page'),
+ model_name="primarytopicpagerelatedlink",
+ name="link_page",
+ field=models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to="wagtailcore.Page",
+ ),
),
migrations.AddField(
- model_name='primarytopicpagerelatedlink',
- name='page',
- field=modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='related_links', to='topics.PrimaryTopicPage'),
+ model_name="primarytopicpagerelatedlink",
+ name="page",
+ field=modelcluster.fields.ParentalKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="related_links",
+ to="topics.PrimaryTopicPage",
+ ),
),
]
diff --git a/ietf/topics/migrations/0002_auto_20210325_0442.py b/ietf/topics/migrations/0002_auto_20210325_0442.py
index 45feea65..13da7d46 100644
--- a/ietf/topics/migrations/0002_auto_20210325_0442.py
+++ b/ietf/topics/migrations/0002_auto_20210325_0442.py
@@ -1,28 +1,70 @@
# Generated by Django 2.2.16 on 2021-03-25 04:42
-from django.db import migrations
+import wagtail.blocks
import wagtail.contrib.table_block.blocks
-import wagtail.core.blocks
-import wagtail.core.fields
import wagtail.embeds.blocks
+import wagtail.fields
import wagtail.images.blocks
+from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
- ('topics', '0001_initial'),
+ ("topics", "0001_initial"),
]
operations = [
migrations.AlterField(
- model_name='primarytopicpage',
- name='in_depth',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True),
+ model_name="primarytopicpage",
+ name="in_depth",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ],
+ blank=True,
+ ),
),
migrations.AlterField(
- model_name='primarytopicpage',
- name='key_info',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True),
+ model_name="primarytopicpage",
+ name="key_info",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ],
+ blank=True,
+ ),
),
]
diff --git a/ietf/topics/migrations/0003_auto_20211101_0113.py b/ietf/topics/migrations/0003_auto_20211101_0113.py
index 4148d8fc..09b97a6b 100644
--- a/ietf/topics/migrations/0003_auto_20211101_0113.py
+++ b/ietf/topics/migrations/0003_auto_20211101_0113.py
@@ -1,29 +1,73 @@
# Generated by Django 2.2.19 on 2021-11-01 01:13
-from django.db import migrations
+import wagtail.blocks
import wagtail.contrib.table_block.blocks
-import wagtail.core.blocks
-import wagtail.core.fields
import wagtail.embeds.blocks
+import wagtail.fields
import wagtail.images.blocks
import wagtailmarkdown.blocks
+from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
- ('topics', '0002_auto_20210325_0442'),
+ ("topics", "0002_auto_20210325_0442"),
]
operations = [
migrations.AlterField(
- model_name='primarytopicpage',
- name='in_depth',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('markdown', wagtailmarkdown.blocks.MarkdownBlock(icon='code')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True),
+ model_name="primarytopicpage",
+ name="in_depth",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("markdown", wagtailmarkdown.blocks.MarkdownBlock(icon="code")),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ],
+ blank=True,
+ ),
),
migrations.AlterField(
- model_name='primarytopicpage',
- name='key_info',
- field=wagtail.core.fields.StreamField([('heading', wagtail.core.blocks.CharBlock(icon='title')), ('paragraph', wagtail.core.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('markdown', wagtailmarkdown.blocks.MarkdownBlock(icon='code')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.core.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True),
+ model_name="primarytopicpage",
+ name="key_info",
+ field=wagtail.fields.StreamField(
+ [
+ ("heading", wagtail.blocks.CharBlock(icon="title")),
+ ("paragraph", wagtail.blocks.RichTextBlock(icon="pilcrow")),
+ (
+ "image",
+ wagtail.images.blocks.ImageChooserBlock(
+ icon="image", template="includes/imageblock.html"
+ ),
+ ),
+ ("markdown", wagtailmarkdown.blocks.MarkdownBlock(icon="code")),
+ ("embed", wagtail.embeds.blocks.EmbedBlock(icon="code")),
+ ("raw_html", wagtail.blocks.RawHTMLBlock(icon="placeholder")),
+ (
+ "table",
+ wagtail.contrib.table_block.blocks.TableBlock(
+ table_options={"renderer": "html"},
+ template="includes/tableblock.html",
+ ),
+ ),
+ ],
+ blank=True,
+ ),
),
]
diff --git a/ietf/topics/migrations/0004_auto_20220902_0524.py b/ietf/topics/migrations/0004_auto_20220902_0524.py
new file mode 100644
index 00000000..4e792178
--- /dev/null
+++ b/ietf/topics/migrations/0004_auto_20220902_0524.py
@@ -0,0 +1,29 @@
+# Generated by Django 3.2.13 on 2022-09-02 04:24
+
+from django.db import migrations
+import wagtail.blocks
+import wagtail.contrib.table_block.blocks
+import wagtail.embeds.blocks
+import wagtail.fields
+import wagtail.images.blocks
+import wagtailmarkdown.blocks
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('topics', '0003_auto_20211101_0113'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='primarytopicpage',
+ name='in_depth',
+ field=wagtail.fields.StreamField([('heading', wagtail.blocks.CharBlock(icon='title')), ('paragraph', wagtail.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('markdown', wagtailmarkdown.blocks.MarkdownBlock(icon='code')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True, use_json_field=True),
+ ),
+ migrations.AlterField(
+ model_name='primarytopicpage',
+ name='key_info',
+ field=wagtail.fields.StreamField([('heading', wagtail.blocks.CharBlock(icon='title')), ('paragraph', wagtail.blocks.RichTextBlock(icon='pilcrow')), ('image', wagtail.images.blocks.ImageChooserBlock(icon='image', template='includes/imageblock.html')), ('markdown', wagtailmarkdown.blocks.MarkdownBlock(icon='code')), ('embed', wagtail.embeds.blocks.EmbedBlock(icon='code')), ('raw_html', wagtail.blocks.RawHTMLBlock(icon='placeholder')), ('table', wagtail.contrib.table_block.blocks.TableBlock(table_options={'renderer': 'html'}, template='includes/tableblock.html'))], blank=True, use_json_field=True),
+ ),
+ ]
diff --git a/ietf/topics/models.py b/ietf/topics/models.py
index 18bd8edd..12e90c2a 100644
--- a/ietf/topics/models.py
+++ b/ietf/topics/models.py
@@ -1,19 +1,12 @@
from django.db import models
-
from modelcluster.fields import ParentalKey
-
-from wagtail.core.models import Page, Orderable
-from wagtail.core.fields import StreamField
-from wagtail.admin.edit_handlers import (
- FieldPanel, StreamFieldPanel, InlinePanel
-)
+from wagtail.admin.panels import FieldPanel, InlinePanel
+from wagtail.fields import StreamField
+from wagtail.models import Orderable, Page
from wagtail.search import index
-from wagtail.snippets.edit_handlers import (
- SnippetChooserPanel
-)
-from ..utils.models import PromoteMixin, RelatedLink
from ..utils.blocks import StandardBlock
+from ..utils.models import PromoteMixin, RelatedLink
class TopicIndexPage(Page, PromoteMixin):
@@ -21,18 +14,20 @@ class TopicIndexPage(Page, PromoteMixin):
This page organises topics. The :model:`topics.PrimaryTopicPage`
page should be placed beneath it in the page heirarchy.
"""
+
introduction = models.CharField(
max_length=255,
help_text="Enter the introduction to display on the page, "
- "you can use only 255 characters."
+ "you can use only 255 characters.",
)
search_fields = Page.search_fields + [
- index.SearchField('introduction'),
+ index.SearchField("introduction"),
]
- subpage_types = ['topics.PrimaryTopicPage',
- ]
+ subpage_types = [
+ "topics.PrimaryTopicPage",
+ ]
@property
def primary_topics(self):
@@ -41,18 +36,16 @@ def primary_topics(self):
class Meta:
verbose_name = "Topic Page List"
+
TopicIndexPage.content_panels = Page.content_panels + [
- FieldPanel('introduction'),
+ FieldPanel("introduction"),
]
TopicIndexPage.promote_panels = Page.promote_panels + PromoteMixin.panels
-
-
class PrimaryTopicPageRelatedLink(Orderable, RelatedLink):
- page = ParentalKey('topics.PrimaryTopicPage',
- related_name='related_links')
+ page = ParentalKey("topics.PrimaryTopicPage", related_name="related_links")
class PrimaryTopicPage(Page, PromoteMixin):
@@ -60,31 +53,34 @@ class PrimaryTopicPage(Page, PromoteMixin):
When this page is saved a :model:`snippets.PrimaryTopic` snippet
is created. The snippet is used for organising blog posts.
"""
+
introduction = models.CharField(
blank=True,
max_length=255,
- help_text="Enter the title to display on the page, you can use only 255 characters."
+ help_text="Enter the title to display on the page, you can use only 255 characters.",
)
- key_info = StreamField(StandardBlock(required=False), blank=True)
- in_depth = StreamField(StandardBlock(required=False), blank=True)
+ key_info = StreamField(StandardBlock(required=False), blank=True, use_json_field=True)
+ in_depth = StreamField(StandardBlock(required=False), blank=True, use_json_field=True)
call_to_action = models.ForeignKey(
- 'snippets.CallToAction',
- null=True, blank=True,
+ "snippets.CallToAction",
+ null=True,
+ blank=True,
on_delete=models.SET_NULL,
- related_name='+',
- help_text="Will only be displayed if no mailing list signup is selected."
+ related_name="+",
+ help_text="Will only be displayed if no mailing list signup is selected.",
)
mailing_list_signup = models.ForeignKey(
- 'snippets.MailingListSignup',
+ "snippets.MailingListSignup",
null=True,
- blank=True, on_delete=models.SET_NULL,
- related_name='+'
+ blank=True,
+ on_delete=models.SET_NULL,
+ related_name="+",
)
search_fields = Page.search_fields + [
- index.SearchField('introduction'),
- index.SearchField('key_info'),
- index.SearchField('in_depth'),
+ index.SearchField("introduction"),
+ index.SearchField("key_info"),
+ index.SearchField("in_depth"),
]
@property
@@ -100,14 +96,12 @@ class Meta:
PrimaryTopicPage.content_panels = Page.content_panels + [
- FieldPanel('introduction'),
- StreamFieldPanel('key_info'),
- StreamFieldPanel('in_depth'),
- SnippetChooserPanel('call_to_action'),
- SnippetChooserPanel('mailing_list_signup'),
- InlinePanel('related_links', label="Related Links"),
+ FieldPanel("introduction"),
+ FieldPanel("key_info"),
+ FieldPanel("in_depth"),
+ FieldPanel("call_to_action"),
+ FieldPanel("mailing_list_signup"),
+ InlinePanel("related_links", label="Related Links"),
]
PrimaryTopicPage.promote_panels = Page.promote_panels + PromoteMixin.panels
-
-
diff --git a/ietf/topics/test.py b/ietf/topics/test.py
index b49d53be..01e239bf 100644
--- a/ietf/topics/test.py
+++ b/ietf/topics/test.py
@@ -1,23 +1,22 @@
from django.test import TestCase
+from wagtail.models import Page, Site
-from .models import TopicIndexPage, PrimaryTopicPage
from ..home.models import HomePage
+from .models import PrimaryTopicPage, TopicIndexPage
-from wagtail.core.models import Page, Site
class StandardPageTests(TestCase):
-
def test_standard_page(self):
root = Page.get_first_root_node()
home = HomePage(
- slug = 'homepageslug',
- title = 'home page title',
- heading = 'home page heading',
- introduction = 'home page introduction',
- request_for_comments_section_body = 'rfc section body',
- working_groups_section_body = 'wg section body',
+ slug="homepageslug",
+ title="home page title",
+ heading="home page heading",
+ introduction="home page introduction",
+ request_for_comments_section_body="rfc section body",
+ working_groups_section_body="wg section body",
)
root.add_child(instance=home)
@@ -25,25 +24,25 @@ def test_standard_page(self):
Site.objects.all().delete()
Site.objects.create(
- hostname='localhost',
- root_page = home,
+ hostname="localhost",
+ root_page=home,
is_default_site=True,
- site_name='testingsitename',
+ site_name="testingsitename",
)
topicindex = TopicIndexPage(
- slug = 'topicindex',
- title = 'topic index page title',
- introduction = 'topic index page introduction'
+ slug="topicindex",
+ title="topic index page title",
+ introduction="topic index page introduction",
)
- home.add_child(instance = topicindex)
+ home.add_child(instance=topicindex)
topicpage = PrimaryTopicPage(
- slug = 'topic',
- title = 'topic title',
- introduction = 'topic introduction',
+ slug="topic",
+ title="topic title",
+ introduction="topic introduction",
)
- topicindex.add_child(instance = topicpage)
+ topicindex.add_child(instance=topicpage)
rindex = self.client.get(path=topicindex.url)
self.assertEqual(rindex.status_code, 200)
diff --git a/ietf/urls.py b/ietf/urls.py
index c96d1508..d1621e1f 100644
--- a/ietf/urls.py
+++ b/ietf/urls.py
@@ -2,9 +2,9 @@
from django.conf.urls import include, url
from django.contrib import admin
from django.urls import path
+from wagtail import urls as wagtail_urls
from wagtail.admin import urls as wagtailadmin_urls
from wagtail.contrib.sitemaps.views import sitemap
-from wagtail.core import urls as wagtail_urls
from wagtail.documents import urls as wagtaildocs_urls
from ietf.bibliography import urls as bibliography_urls
@@ -16,7 +16,7 @@
urlpatterns = [
- path('sitemap.xml', sitemap),
+ path("sitemap.xml", sitemap),
url(r"^admin/doc/", include("django.contrib.admindocs.urls")),
url(r"^bibliography/", include(bibliography_urls)),
url(r"^django-admin/", admin.site.urls),
diff --git a/ietf/utils/blocks.py b/ietf/utils/blocks.py
index f5acc325..2253fd79 100644
--- a/ietf/utils/blocks.py
+++ b/ietf/utils/blocks.py
@@ -1,17 +1,17 @@
-from wagtail.core.blocks import (
- CharBlock, RichTextBlock, StreamBlock, RawHTMLBlock
-)
+from wagtail.blocks import CharBlock, RawHTMLBlock, RichTextBlock, StreamBlock
from wagtail.contrib.table_block.blocks import TableBlock
-from wagtail.images.blocks import ImageChooserBlock
from wagtail.embeds.blocks import EmbedBlock
+from wagtail.images.blocks import ImageChooserBlock
from wagtailmarkdown.blocks import MarkdownBlock
class StandardBlock(StreamBlock):
heading = CharBlock(icon="title")
paragraph = RichTextBlock(icon="pilcrow")
- image = ImageChooserBlock(icon="image", template='includes/imageblock.html')
+ image = ImageChooserBlock(icon="image", template="includes/imageblock.html")
markdown = MarkdownBlock(icon="code")
embed = EmbedBlock(icon="code")
raw_html = RawHTMLBlock(icon="placeholder")
- table = TableBlock(table_options={'renderer': 'html'}, template="includes/tableblock.html")
+ table = TableBlock(
+ table_options={"renderer": "html"}, template="includes/tableblock.html"
+ )
diff --git a/ietf/utils/models.py b/ietf/utils/models.py
index c88eb35b..0b5e9cfc 100644
--- a/ietf/utils/models.py
+++ b/ietf/utils/models.py
@@ -3,16 +3,13 @@
from django.utils.translation import gettext_lazy as _
from modelcluster.fields import ParentalKey
from modelcluster.models import ClusterableModel
-from wagtail.admin.edit_handlers import (
+from wagtail.admin.panels import (
FieldPanel,
InlinePanel,
MultiFieldPanel,
- PageChooserPanel,
)
from wagtail.contrib.settings.models import BaseSetting, register_setting
-from wagtail.core.models import Orderable
-from wagtail.documents.edit_handlers import DocumentChooserPanel
-from wagtail.images.edit_handlers import ImageChooserPanel
+from wagtail.models import Orderable
from wagtailorderable.models import Orderable as WagtailOrderable
@@ -44,8 +41,8 @@ def link(self):
panels = [
FieldPanel("link_external"),
- PageChooserPanel("link_page"),
- DocumentChooserPanel("link_document"),
+ FieldPanel("link_page"),
+ FieldPanel("link_document"),
]
class Meta:
@@ -91,8 +88,8 @@ class PromoteMixin(models.Model):
MultiFieldPanel(
[
FieldPanel("social_text"),
- ImageChooserPanel("social_image"),
- ImageChooserPanel("feed_image"),
+ FieldPanel("social_image"),
+ FieldPanel("feed_image"),
],
"Social/Meta descriptions",
)
@@ -122,7 +119,7 @@ def url(self):
def title(self):
return self.text or getattr(self.page, "title", "")
- panels = [PageChooserPanel("page"), FieldPanel("link"), FieldPanel("text")]
+ panels = [FieldPanel("page"), FieldPanel("link"), FieldPanel("text")]
class MenuItem(ClusterableModel, WagtailOrderable):
@@ -136,7 +133,7 @@ class MenuItem(ClusterableModel, WagtailOrderable):
text = models.CharField(max_length=40, blank=True)
panels = [
FieldPanel("text"),
- PageChooserPanel("page"),
+ FieldPanel("page"),
InlinePanel(
"sub_menu_items",
label="Sub Menu Items",
@@ -150,7 +147,7 @@ def is_dropdown(self):
@property
def title(self):
return self.text or getattr(self.page, "title", "")
-
+
class Meta:
verbose_name_plural = "Secondary Menu"
@@ -191,7 +188,7 @@ class SocialMediaSettings(BaseSetting):
FieldPanel("twitter_handle"),
FieldPanel("facebook_app_id"),
FieldPanel("default_sharing_text"),
- ImageChooserPanel("default_sharing_image"),
+ FieldPanel("default_sharing_image"),
FieldPanel("site_name"),
]
diff --git a/ietf/utils/templatetags/ietf_tags.py b/ietf/utils/templatetags/ietf_tags.py
index 8af42f86..394379a9 100644
--- a/ietf/utils/templatetags/ietf_tags.py
+++ b/ietf/utils/templatetags/ietf_tags.py
@@ -1,12 +1,10 @@
from urllib.parse import quote
from django.template import Library
-
-from wagtail.core.models import Site
+from wagtail.models import Site
from ..models import SocialMediaSettings
-
register = Library()
@@ -26,19 +24,20 @@ def social_text(page, site, encode=False):
return text
-
@register.simple_tag(takes_context=False)
def social_image(page, site):
image = ""
if page and site:
try:
- image = page.social_image.get_rendition('original').url
+ image = page.social_image.get_rendition("original").url
except (AttributeError, ValueError):
try:
- image = SocialMediaSettings.for_site(
- site
- ).default_sharing_image.get_rendition('original').url
+ image = (
+ SocialMediaSettings.for_site(site)
+ .default_sharing_image.get_rendition("original")
+ .url
+ )
except (AttributeError, ValueError):
pass
diff --git a/ietf/utils/tests.py b/ietf/utils/tests.py
index 40d45c8b..940f4d48 100644
--- a/ietf/utils/tests.py
+++ b/ietf/utils/tests.py
@@ -1,6 +1,6 @@
from django.test import TestCase
-from wagtail.core.models import Page, Site
-from wagtail.tests.utils import WagtailTestUtils
+from wagtail.models import Page, Site
+from wagtail.test.utils import WagtailTestUtils
from ietf.events.models import EventListingPage, EventPage
from ietf.utils.models import MenuItem
diff --git a/ietf/utils/wagtail_hooks.py b/ietf/utils/wagtail_hooks.py
index e6452f00..fe81ea0d 100644
--- a/ietf/utils/wagtail_hooks.py
+++ b/ietf/utils/wagtail_hooks.py
@@ -1,7 +1,7 @@
from django.conf import settings
from django.utils.html import format_html
+from wagtail import hooks
from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
-from wagtail.core import hooks
from wagtailorderable.modeladmin.mixins import OrderableMixin
from ietf.utils.models import MenuItem
diff --git a/requirements.txt b/requirements.txt
index 082027f0..75a121ad 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,7 +4,7 @@
Django>=3.0,<3.3
djangorestframework>=3.8
psycopg2-binary>=2.7.5
-wagtail>=2.15.1,<2.16
+wagtail>=3.0,<3.1
django-libsass>=0.8
libsass>=0.8.3
future>=0.15.2