diff --git a/.github/workflows/ci-pre-commit.yml b/.github/workflows/ci-pre-commit.yml new file mode 100644 index 00000000..c3c01762 --- /dev/null +++ b/.github/workflows/ci-pre-commit.yml @@ -0,0 +1,24 @@ +name: Run pre-commit +on: + push: + branches: + - main + pull_request: + branches: + - '*' + +jobs: + check: + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + + - name: Install Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Run pre-commit + uses: pre-commit/action@v3.0.1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..05e42bdb --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,22 @@ +default_language_version: + node: system + python: python3.12 +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-toml + - id: check-merge-conflict + - id: check-byte-order-marker + - id: check-case-conflict + - id: debug-statements + - id: detect-private-key + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.4.9 + hooks: + - id: ruff + args: [--fix, --exit-non-zero-on-fix] + - repo: https://github.com/psf/black-pre-commit-mirror + rev: 24.4.2 + hooks: + - id: black diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9d2afb2a..39ed4ea8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,6 +22,14 @@ The testsuite uses [pytest](https://docs.pytest.org/) and [pytest-django](https: pytest ``` +### Linting + +To ensure a uniform code style, this project uses [black](https://black.readthedocs.io/en/stable/) and [ruff](https://docs.astral.sh/ruff/). You can install the [pre-commit](https://pre-commit.com) hook to run them automatically when making a git commit: + +```bash +pre-commit install +``` + ## Frontend Development This project uses Bootstrap. The exact version is specified in the `package.json` file. diff --git a/docker/gunicorn.py b/docker/gunicorn.py index eeeccaa4..7c76d82c 100644 --- a/docker/gunicorn.py +++ b/docker/gunicorn.py @@ -1,5 +1,7 @@ import json +import gunicorn + accesslog = "-" errorlog = "-" access_log_format = json.dumps( @@ -27,5 +29,4 @@ chdir = "/app" # Obfuscate the Server header (to the md5sum of "Springload") -import gunicorn gunicorn.SERVER_SOFTWARE = "04e96149a2f64d6135c82d199ab62122" diff --git a/docker/init-test.sh b/docker/init-test.sh index 0438a83f..a94bb33f 100755 --- a/docker/init-test.sh +++ b/docker/init-test.sh @@ -2,10 +2,10 @@ set -x +python /app/manage.py makemigrations --dry-run --no-input +python /app/manage.py makemigrations --check --no-input python /app/manage.py migrate --no-input python /app/manage.py createcachetable python /app/manage.py collectstatic --no-input pytest --cov --cov-report=xml if [ -d /coverage ]; then cp .coverage coverage.xml /coverage/; fi -python /app/manage.py makemigrations --dry-run --no-input -python /app/manage.py makemigrations --check --no-input diff --git a/ietf/__init__.py b/ietf/__init__.py index c3961685..e69de29b 100644 --- a/ietf/__init__.py +++ b/ietf/__init__.py @@ -1 +0,0 @@ -from __future__ import absolute_import diff --git a/ietf/announcements/factories.py b/ietf/announcements/factories.py index 2e98791c..8b329f85 100644 --- a/ietf/announcements/factories.py +++ b/ietf/announcements/factories.py @@ -2,6 +2,7 @@ import wagtail_factories from ietf.utils.factories import StandardBlockFactory + from .models import IABAnnouncementIndexPage, IABAnnouncementPage diff --git a/ietf/announcements/migrations/0004_alter_iabannouncementpage_body.py b/ietf/announcements/migrations/0004_alter_iabannouncementpage_body.py index a7b31302..29dd3127 100644 --- a/ietf/announcements/migrations/0004_alter_iabannouncementpage_body.py +++ b/ietf/announcements/migrations/0004_alter_iabannouncementpage_body.py @@ -1,6 +1,5 @@ # Generated by Django 4.2.7 on 2024-04-03 13:40 -from django.db import migrations import wagtail.blocks import wagtail.contrib.table_block.blocks import wagtail.contrib.typed_table_block.blocks @@ -8,18 +7,72 @@ import wagtail.fields import wagtail.images.blocks import wagtailmarkdown.blocks +from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('announcements', '0003_alter_iabannouncementpage_body'), + ("announcements", "0003_alter_iabannouncementpage_body"), ] operations = [ migrations.AlterField( - model_name='iabannouncementpage', - 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')), ('typed_table', wagtail.contrib.typed_table_block.blocks.TypedTableBlock([('text', wagtail.blocks.CharBlock(required=False)), ('numeric', wagtail.blocks.FloatBlock(required=False, template='blocks/float_block.html')), ('rich_text', wagtail.blocks.RichTextBlock(required=False)), ('image', wagtail.images.blocks.ImageChooserBlock(required=False))])), ('note_well', wagtail.blocks.StructBlock([], icon='placeholder', label='Note Well Text'))], use_json_field=True), + model_name="iabannouncementpage", + 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", + ), + ), + ( + "typed_table", + wagtail.contrib.typed_table_block.blocks.TypedTableBlock( + [ + ("text", wagtail.blocks.CharBlock(required=False)), + ( + "numeric", + wagtail.blocks.FloatBlock( + required=False, + template="blocks/float_block.html", + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock(required=False), + ), + ( + "image", + wagtail.images.blocks.ImageChooserBlock( + required=False + ), + ), + ] + ), + ), + ( + "note_well", + wagtail.blocks.StructBlock( + [], icon="placeholder", label="Note Well Text" + ), + ), + ], + use_json_field=True, + ), ), ] diff --git a/ietf/announcements/models.py b/ietf/announcements/models.py index 992ba5c1..f124f008 100644 --- a/ietf/announcements/models.py +++ b/ietf/announcements/models.py @@ -68,7 +68,11 @@ class Meta: @property def children(self): announcements = self.get_children().live().specific() - return sorted(announcements, key=lambda announcement: announcement.specific.date, reverse=True) + return sorted( + announcements, + key=lambda announcement: announcement.specific.date, + reverse=True, + ) IABAnnouncementIndexPage.content_panels = Page.content_panels + [ diff --git a/ietf/announcements/tests.py b/ietf/announcements/tests.py index 66102d46..f008bc5a 100644 --- a/ietf/announcements/tests.py +++ b/ietf/announcements/tests.py @@ -1,11 +1,12 @@ from datetime import timedelta + +import pytest from bs4 import BeautifulSoup from django.test import Client from django.utils import timezone -import pytest - from ietf.home.models import IABHomePage + from .factories import IABAnnouncementIndexPageFactory, IABAnnouncementPageFactory from .models import IABAnnouncementIndexPage, IABAnnouncementPage @@ -55,7 +56,7 @@ def test_announcement_page(self): assert self.announcement_3.introduction in html def test_homepage(self): - """ The two most recent announcements are shown on the homepage """ + """The two most recent announcements are shown on the homepage""" response = self.client.get(self.home.url) assert response.status_code == 200 html = response.content.decode() diff --git a/ietf/bibliography/__init__.py b/ietf/bibliography/__init__.py index eba9bf7b..7624e62a 100644 --- a/ietf/bibliography/__init__.py +++ b/ietf/bibliography/__init__.py @@ -4,4 +4,3 @@ # X model mixin with pre-parser method # item rendering template tag # itemS rendering template tag - diff --git a/ietf/bibliography/apps.py b/ietf/bibliography/apps.py index 41478baf..b012d68a 100644 --- a/ietf/bibliography/apps.py +++ b/ietf/bibliography/apps.py @@ -2,5 +2,5 @@ class BibliographyAppConfig(AppConfig): - name = 'ietf.bibliography' + name = "ietf.bibliography" verbose_name = "Bibliography items" diff --git a/ietf/bibliography/management/commands/fix_BMI_page_links.py b/ietf/bibliography/management/commands/fix_BMI_page_links.py index 30841957..4c4d69aa 100644 --- a/ietf/bibliography/management/commands/fix_BMI_page_links.py +++ b/ietf/bibliography/management/commands/fix_BMI_page_links.py @@ -20,10 +20,10 @@ def change_links(page): 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(): + for fieldname in page.CONTENT_FIELD_MAP: field = getattr(page, fieldname) for item in field.stream_data: - if not item["type"] in ("paragraph", "raw_html"): + if item["type"] not in ("paragraph", "raw_html"): continue soup = BeautifulSoup(item["value"], "html.parser") for tag in soup.find_all("a", string=rfc_pattern): diff --git a/ietf/bibliography/migrations/0001_initial.py b/ietf/bibliography/migrations/0001_initial.py index a44b13f9..36dcc793 100644 --- a/ietf/bibliography/migrations/0001_initial.py +++ b/ietf/bibliography/migrations/0001_initial.py @@ -1,9 +1,7 @@ -# -*- coding: utf-8 -*- # 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 +from django.db import migrations, models class Migration(migrations.Migration): @@ -11,23 +9,70 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('wagtailcore', '0040_page_draft_title'), - ('contenttypes', '0002_remove_content_type_name'), + ("wagtailcore", "0040_page_draft_title"), + ("contenttypes", "0002_remove_content_type_name"), ] operations = [ migrations.CreateModel( - name='BibliographyItem', + name="BibliographyItem", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('ordering', models.PositiveIntegerField(help_text='The bibliography items on each referring page are sorted and numbered with this ordering number.')), - ('content_key', models.CharField(help_text='The "key" with which this item was created, eg. "rfc" in [[rfc:3514]].', max_length=127)), - ('content_identifier', models.CharField(help_text='The "value" with which this item was created, eg. "3514" in [[rfc:3514]].', max_length=127)), - ('content_long_title', models.CharField(blank=True, max_length=127)), - ('content_title', models.CharField(help_text='The link title for this item, eg. "RFC 7168" for [[rfc:7168]].', max_length=127)), - ('object_id', models.PositiveIntegerField(blank=True, null=True)), - ('content_type', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')), - ('page', models.ForeignKey(help_text='The page that this item links to.', on_delete=django.db.models.deletion.CASCADE, related_name='bibliography_items', to='wagtailcore.Page')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "ordering", + models.PositiveIntegerField( + help_text="The bibliography items on each referring page are sorted and numbered with this ordering number." + ), + ), + ( + "content_key", + models.CharField( + help_text='The "key" with which this item was created, eg. "rfc" in [[rfc:3514]].', + max_length=127, + ), + ), + ( + "content_identifier", + models.CharField( + help_text='The "value" with which this item was created, eg. "3514" in [[rfc:3514]].', + max_length=127, + ), + ), + ("content_long_title", models.CharField(blank=True, max_length=127)), + ( + "content_title", + models.CharField( + help_text='The link title for this item, eg. "RFC 7168" for [[rfc:7168]].', + max_length=127, + ), + ), + ("object_id", models.PositiveIntegerField(blank=True, null=True)), + ( + "content_type", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="contenttypes.ContentType", + ), + ), + ( + "page", + models.ForeignKey( + help_text="The page that this item links to.", + on_delete=django.db.models.deletion.CASCADE, + related_name="bibliography_items", + to="wagtailcore.Page", + ), + ), ], ), ] diff --git a/ietf/bibliography/models.py b/ietf/bibliography/models.py index 01c82950..fcf526a1 100644 --- a/ietf/bibliography/models.py +++ b/ietf/bibliography/models.py @@ -85,9 +85,7 @@ def render(self, request=None): template = BibliographyItem.TEMPLATE_CACHE[self.content_key] else: try: - template = get_template( - "bibliography/item_{}.html".format(self.content_key) - ) + template = get_template(f"bibliography/item_{self.content_key}.html") except TemplateDoesNotExist: template = None BibliographyItem.TEMPLATE_CACHE[self.content_key] = template @@ -100,7 +98,7 @@ def render(self, request=None): return str(object) def __str__(self): # pragma: no cover - return "Bibliography Item #{}: {}".format(self.ordering, self.content_object) + return f"Bibliography Item #{self.ordering}: {self.content_object}" class BibliographyMixin(models.Model): @@ -127,7 +125,7 @@ def save(self, *args, **kwargs): ] prepared_fields_being_updated = [ prepared_field in update_fields - for prepared_field in self.CONTENT_FIELD_MAP.keys() + for prepared_field in self.CONTENT_FIELD_MAP ] if any(source_fields_being_updated) or any(prepared_fields_being_updated): @@ -147,7 +145,7 @@ def save(self, *args, **kwargs): all_content = "".join( [ str(getattr(self, content_field)) or "" - for content_field in self.CONTENT_FIELD_MAP.keys() + for content_field in self.CONTENT_FIELD_MAP ] ) all_soup = BeautifulSoup(all_content, "html.parser") @@ -161,7 +159,9 @@ def save(self, *args, **kwargs): # Look for nodes that are tagged with bibliographic markup, # create BibliographyItem records, and turn the nodes into # footnote links. - for index, tag in enumerate(all_soup.find_all("a", attrs={"data-app": True})): + for index, tag in enumerate( + all_soup.find_all("a", attrs={"data-app": True}) + ): app = tag["data-app"] model = tag["data-linktype"] obj_id = tag["data-id"] @@ -190,7 +190,7 @@ def save(self, *args, **kwargs): ordering=index + 1, content_key=model, content_identifier=obj_id, - **object_details + **object_details, ) for soup in subsoups.values(): for t in soup.find_all( @@ -206,7 +206,7 @@ def save(self, *args, **kwargs): for prepared_content_field, prepared_soup in subsoups.items(): setattr(self, prepared_content_field, prepared_soup.__unicode__()) - return super(BibliographyMixin, self).save(*args, **kwargs) + return super().save(*args, **kwargs) class Meta: abstract = True diff --git a/ietf/bibliography/templatetags/bibliography.py b/ietf/bibliography/templatetags/bibliography.py index 7a9e5d8e..86f77e03 100644 --- a/ietf/bibliography/templatetags/bibliography.py +++ b/ietf/bibliography/templatetags/bibliography.py @@ -1,6 +1,5 @@ from django import template - register = template.Library() @@ -14,13 +13,15 @@ def bibliography(page): """ items = [] - for item in page.bibliography_items.all().order_by('ordering'): - items.append({ - 'title': item.render_title(), - 'long_title': item.content_long_title, - 'content': item.render(), - 'ordering': item.ordering, - 'uri': item.render_uri - }) + for item in page.bibliography_items.all().order_by("ordering"): + items.append( + { + "title": item.render_title(), + "long_title": item.content_long_title, + "content": item.render(), + "ordering": item.ordering, + "uri": item.render_uri, + } + ) - return {'items': items} + return {"items": items} diff --git a/ietf/bibliography/tests.py b/ietf/bibliography/tests.py index fc062ac9..08127d13 100644 --- a/ietf/bibliography/tests.py +++ b/ietf/bibliography/tests.py @@ -74,9 +74,10 @@ def test_referenced_objects(self, admin_client): ) assert response.status_code == 200 html = response.content.decode() - assert reverse( - "referencing_pages", args=[rfc_content_type.pk, self.rfc_2026.pk] - ) in html + assert ( + reverse("referencing_pages", args=[rfc_content_type.pk, self.rfc_2026.pk]) + in html + ) assert "RFC 2026" in html def test_referencing_pages(self, admin_client): @@ -132,6 +133,9 @@ def test_update_fields_with_all_prepared_fields_succeeds(self): """ self.standard_page.save( update_fields=[ - "key_info", "in_depth", "prepared_key_info", "prepared_in_depth" + "key_info", + "in_depth", + "prepared_key_info", + "prepared_in_depth", ] ) diff --git a/ietf/bibliography/urls.py b/ietf/bibliography/urls.py index 27f2acbc..771cfc4b 100644 --- a/ietf/bibliography/urls.py +++ b/ietf/bibliography/urls.py @@ -1,14 +1,17 @@ from django.urls import re_path from .views import ( - referenced_types, referenced_objects, + referenced_types, referencing_pages, ) - urlpatterns = [ - re_path(r'^referenced_types/$', referenced_types, name='referenced_types'), - re_path(r'^referenced_objects/(\d+)/$', referenced_objects, name='referenced_objects'), - re_path(r'^referencing_pages/(\d+)/(\d+)/$', referencing_pages, name='referencing_pages'), - ] + re_path(r"^referenced_types/$", referenced_types, name="referenced_types"), + re_path( + r"^referenced_objects/(\d+)/$", referenced_objects, name="referenced_objects" + ), + re_path( + r"^referencing_pages/(\d+)/(\d+)/$", referencing_pages, name="referencing_pages" + ), +] diff --git a/ietf/blog/feeds.py b/ietf/blog/feeds.py index 1275744e..5fb74f5a 100644 --- a/ietf/blog/feeds.py +++ b/ietf/blog/feeds.py @@ -1,6 +1,5 @@ from django.contrib.syndication.views import Feed from django.db.models.functions import Coalesce -from django.utils.functional import cached_property from wagtail.models import Site from ..blog.models import BlogPage @@ -41,6 +40,7 @@ def item_author_name(self, item): def item_pubdate(self, item): return item.date + class TopicBlogFeed(BlogFeed): def __init__(self, topic): self.topic = topic @@ -60,6 +60,7 @@ def items(self): .order_by("-d") ) + class AuthorBlogFeed(BlogFeed): def __init__(self, person, queryset): self.person = person diff --git a/ietf/blog/migrations/0001_initial.py b/ietf/blog/migrations/0001_initial.py index 9033b944..121daaba 100644 --- a/ietf/blog/migrations/0001_initial.py +++ b/ietf/blog/migrations/0001_initial.py @@ -1,6 +1,4 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.11.29 on 2020-04-10 18:46 -from __future__ import unicode_literals import django.db.models.deletion import modelcluster.fields diff --git a/ietf/blog/migrations/0004_alter_blogpage_body.py b/ietf/blog/migrations/0004_alter_blogpage_body.py index dc2a0134..6cf9d555 100644 --- a/ietf/blog/migrations/0004_alter_blogpage_body.py +++ b/ietf/blog/migrations/0004_alter_blogpage_body.py @@ -1,24 +1,46 @@ # 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 +from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('blog', '0003_auto_20211101_0113'), + ("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), + 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/migrations/0008_alter_blogpageauthor_author.py b/ietf/blog/migrations/0008_alter_blogpageauthor_author.py index f3c13cfb..f22c3f6a 100644 --- a/ietf/blog/migrations/0008_alter_blogpageauthor_author.py +++ b/ietf/blog/migrations/0008_alter_blogpageauthor_author.py @@ -1,20 +1,24 @@ # Generated by Django 3.2.20 on 2023-11-24 13:34 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('snippets', '0002_auto_20200414_2027'), - ('blog', '0007_alter_blogpage_body'), + ("snippets", "0002_auto_20200414_2027"), + ("blog", "0007_alter_blogpage_body"), ] operations = [ migrations.AlterField( - model_name='blogpageauthor', - name='author', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='snippets.person'), + model_name="blogpageauthor", + name="author", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="+", + to="snippets.person", + ), ), ] diff --git a/ietf/blog/migrations/0009_alter_blogpage_body.py b/ietf/blog/migrations/0009_alter_blogpage_body.py index cb5c356d..0e66a122 100644 --- a/ietf/blog/migrations/0009_alter_blogpage_body.py +++ b/ietf/blog/migrations/0009_alter_blogpage_body.py @@ -1,6 +1,5 @@ # Generated by Django 4.2.7 on 2024-04-03 13:40 -from django.db import migrations import wagtail.blocks import wagtail.contrib.table_block.blocks import wagtail.contrib.typed_table_block.blocks @@ -8,18 +7,72 @@ import wagtail.fields import wagtail.images.blocks import wagtailmarkdown.blocks +from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('blog', '0008_alter_blogpageauthor_author'), + ("blog", "0008_alter_blogpageauthor_author"), ] 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')), ('typed_table', wagtail.contrib.typed_table_block.blocks.TypedTableBlock([('text', wagtail.blocks.CharBlock(required=False)), ('numeric', wagtail.blocks.FloatBlock(required=False, template='blocks/float_block.html')), ('rich_text', wagtail.blocks.RichTextBlock(required=False)), ('image', wagtail.images.blocks.ImageChooserBlock(required=False))])), ('note_well', wagtail.blocks.StructBlock([], icon='placeholder', label='Note Well Text'))], use_json_field=True), + 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", + ), + ), + ( + "typed_table", + wagtail.contrib.typed_table_block.blocks.TypedTableBlock( + [ + ("text", wagtail.blocks.CharBlock(required=False)), + ( + "numeric", + wagtail.blocks.FloatBlock( + required=False, + template="blocks/float_block.html", + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock(required=False), + ), + ( + "image", + wagtail.images.blocks.ImageChooserBlock( + required=False + ), + ), + ] + ), + ), + ( + "note_well", + wagtail.blocks.StructBlock( + [], icon="placeholder", label="Note Well Text" + ), + ), + ], + use_json_field=True, + ), ), ] diff --git a/ietf/blog/models.py b/ietf/blog/models.py index 6a7ab6e6..5331f5a2 100644 --- a/ietf/blog/models.py +++ b/ietf/blog/models.py @@ -230,7 +230,8 @@ def get_authors(self): return [ { "name": author.author.name, - "url": index_page.url + index_page.reverse_subpage( + "url": index_page.url + + index_page.reverse_subpage( "index_by_author", kwargs={"slug": author.author.slug} ), "role": author.role, @@ -239,7 +240,7 @@ def get_authors(self): ] def get_context(self, request, *args, **kwargs): - context = super(BlogPage, self).get_context(request, *args, **kwargs) + context = super().get_context(request, *args, **kwargs) siblings = self.siblings max_siblings_to_show = 5 query_string = "?" @@ -253,7 +254,7 @@ def get_context(self, request, *args, **kwargs): try: related_object = functions[0](search_query) siblings = functions[1](siblings, related_object) - query_string += "%s=%s&" % (parameter, search_query) + query_string += f"{parameter}={search_query}&" filter_text_builder = partial( filter_text_builder, **{parameter: related_object.__str__()} ) @@ -297,13 +298,13 @@ def serve(self, request, *args, **kwargs): try: topic_id = int(topic_id) except ValueError: - raise Http404 + raise Http404 from None filter_topic = get_object_or_404(Topic, id=topic_id) query_string_segments = [] - for parameter, function in parameter_functions_map.items(): + 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_segments.append(f"{parameter}={search_query}") query_string = "&".join(query_string_segments) target_url = self.get_parent().specific.reverse_subpage( "redirect_first", args=(filter_topic.slug,) @@ -352,7 +353,11 @@ def get_ancestors(self): return self.parent.get_ancestors(inclusive=True) def get_entries_queryset(self): - qs = BlogPage.objects.child_of(self.parent).filter(authors__author=self.person).live() + qs = ( + BlogPage.objects.child_of(self.parent) + .filter(authors__author=self.person) + .live() + ) qs = qs.annotate( coalesced_published_date=Coalesce("date_published", "first_published_at") ).order_by("-coalesced_published_date") @@ -462,7 +467,7 @@ def redirect_first(self, request, slug=None, *args, **kwargs): try: related_object = functions[0](search_query) blogs = functions[1](blogs, related_object) - query_string += "%s=%s&" % (parameter, search_query) + query_string += f"{parameter}={search_query}&" except (ValueError, ObjectDoesNotExist): pass diff --git a/ietf/blog/tests.py b/ietf/blog/tests.py index 0e5beb7d..263919fe 100644 --- a/ietf/blog/tests.py +++ b/ietf/blog/tests.py @@ -1,14 +1,15 @@ from datetime import timedelta + +import pytest from bs4 import BeautifulSoup from django.test import Client from django.utils import timezone -import pytest - -from ietf.snippets.factories import PersonFactory, TopicFactory from ietf.home.models import HomePage +from ietf.snippets.factories import PersonFactory, TopicFactory from ietf.snippets.models import Topic from ietf.utils.models import FeedSettings + from .factories import BlogIndexPageFactory, BlogPageFactory from .models import ( IESG_STATEMENT_TOPIC_ID, @@ -89,9 +90,9 @@ def test_blog(self): assert self.blog_page.title in html assert self.blog_page.body[0].value in html assert self.blog_page.introduction in html - assert ('href="%s"' % self.next_blog_page.url) in html - assert ('href="%s"' % self.prev_blog_page.url) in html - assert ('href="%s"' % self.other_blog_page.url) in html + assert (f'href="{self.next_blog_page.url}"') in html + assert (f'href="{self.prev_blog_page.url}"') in html + assert (f'href="{self.other_blog_page.url}"') in html def test_previous_next_links_correct(self): assert self.prev_blog_page.date < self.blog_page.date @@ -137,7 +138,9 @@ def test_topic_feed(self): assert iesg_response.status_code == 200 iesg_feed = iesg_response.content.decode() - assert f"{self.feed_settings.blog_feed_title} – iesg" in iesg_feed + assert ( + f"{self.feed_settings.blog_feed_title} – iesg" in iesg_feed + ) assert self.next_blog_page.url in iesg_feed assert self.blog_page.url not in iesg_feed assert self.other_blog_page.url not in iesg_feed @@ -157,7 +160,7 @@ def test_author_feed(self): assert self.blog_page.url not in feed def test_homepage(self): - """ The two most recent blog posts are shown on the homepage. """ + """The two most recent blog posts are shown on the homepage.""" response = self.client.get(path=self.home.url) assert response.status_code == 200 html = response.content.decode() @@ -166,7 +169,7 @@ def test_homepage(self): assert self.blog_page.title in html def test_all_page(self): - """ The /blog/all/ page shows all the published blog posts. """ + """The /blog/all/ page shows all the published blog posts.""" response = self.client.get(f"{self.blog_index.url}all/") assert response.status_code == 200 html = response.content.decode() diff --git a/ietf/conftest.py b/ietf/conftest.py index 6194af43..f39a459d 100644 --- a/ietf/conftest.py +++ b/ietf/conftest.py @@ -1,4 +1,5 @@ from unittest.mock import Mock + import pytest from wagtail.models import Page, Site @@ -45,4 +46,4 @@ def iab_blog_feed(monkeypatch: pytest.MonkeyPatch): mock_get = Mock() mock_get.return_value.text = "" monkeypatch.setattr("ietf.home.models.get_request", mock_get) - return mock_get \ No newline at end of file + return mock_get diff --git a/ietf/context_processors.py b/ietf/context_processors.py index d5bc0941..6491950c 100644 --- a/ietf/context_processors.py +++ b/ietf/context_processors.py @@ -3,8 +3,8 @@ from wagtail.models import Site from ietf.home.models import HomePage, IABHomePage -from ietf.utils.models import SecondaryMenuItem, SocialMediaSettings from ietf.utils.context_processors import get_footer, get_main_menu +from ietf.utils.models import SecondaryMenuItem, SocialMediaSettings def home_page(site): diff --git a/ietf/documents/apps.py b/ietf/documents/apps.py index 0fd65195..8b706f03 100644 --- a/ietf/documents/apps.py +++ b/ietf/documents/apps.py @@ -2,4 +2,4 @@ class DocumentsConfig(AppConfig): - name = 'ietf.documents' + name = "ietf.documents" diff --git a/ietf/documents/migrations/0001_initial.py b/ietf/documents/migrations/0001_initial.py index b7b3dce0..4b8f1cf3 100644 --- a/ietf/documents/migrations/0001_initial.py +++ b/ietf/documents/migrations/0001_initial.py @@ -1,9 +1,7 @@ -# -*- coding: utf-8 -*- # 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 +from django.db import migrations, models class Migration(migrations.Migration): @@ -11,19 +9,29 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('wagtaildocs', '0008_document_file_size'), + ("wagtaildocs", "0008_document_file_size"), ] operations = [ migrations.CreateModel( - name='IetfDocument', + name="IetfDocument", fields=[ - ('document_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtaildocs.Document')), + ( + "document_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="wagtaildocs.Document", + ), + ), ], options={ - 'verbose_name': 'document', - 'abstract': False, + "verbose_name": "document", + "abstract": False, }, - bases=('wagtaildocs.document',), + bases=("wagtaildocs.document",), ), ] diff --git a/ietf/documents/migrations/0002_wagtail_upgrade_peturbations.py b/ietf/documents/migrations/0002_wagtail_upgrade_peturbations.py index 69c05f55..5baa1c6f 100644 --- a/ietf/documents/migrations/0002_wagtail_upgrade_peturbations.py +++ b/ietf/documents/migrations/0002_wagtail_upgrade_peturbations.py @@ -6,12 +6,12 @@ class Migration(migrations.Migration): dependencies = [ - ('documents', '0001_initial'), + ("documents", "0001_initial"), ] operations = [ migrations.AlterModelOptions( - name='ietfdocument', - options={'verbose_name': 'document', 'verbose_name_plural': 'documents'}, + name="ietfdocument", + options={"verbose_name": "document", "verbose_name_plural": "documents"}, ), ] diff --git a/ietf/documents/models.py b/ietf/documents/models.py index 4e20f452..2221e105 100644 --- a/ietf/documents/models.py +++ b/ietf/documents/models.py @@ -1,6 +1,6 @@ - from wagtail.documents.models import Document + class IetfDocument(Document): @property diff --git a/ietf/events/factories.py b/ietf/events/factories.py index d780a44f..fcaf1ad4 100644 --- a/ietf/events/factories.py +++ b/ietf/events/factories.py @@ -2,6 +2,7 @@ import wagtail_factories from ietf.utils.factories import StandardBlockFactory + from .models import EventListingPage, EventPage diff --git a/ietf/events/migrations/0001_initial.py b/ietf/events/migrations/0001_initial.py index d22eddf6..e1231646 100644 --- a/ietf/events/migrations/0001_initial.py +++ b/ietf/events/migrations/0001_initial.py @@ -1,6 +1,4 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.11.29 on 2020-04-10 18:46 -from __future__ import unicode_literals import django.db.models.deletion import modelcluster.fields diff --git a/ietf/events/migrations/0003_auto_20210704_2343.py b/ietf/events/migrations/0003_auto_20210704_2343.py index 8aca9787..6efad039 100644 --- a/ietf/events/migrations/0003_auto_20210704_2343.py +++ b/ietf/events/migrations/0003_auto_20210704_2343.py @@ -6,13 +6,16 @@ class Migration(migrations.Migration): dependencies = [ - ('events', '0002_auto_20210325_0442'), + ("events", "0002_auto_20210325_0442"), ] operations = [ migrations.AlterField( - model_name='eventpage', - name='introduction', - field=models.CharField(help_text='The introduction for the event page. Limited to 511 characters.', max_length=511), + model_name="eventpage", + name="introduction", + field=models.CharField( + help_text="The introduction for the event page. Limited to 511 characters.", + max_length=511, + ), ), ] diff --git a/ietf/events/migrations/0005_auto_20220902_0524.py b/ietf/events/migrations/0005_auto_20220902_0524.py index bb51e7c6..1851dce9 100644 --- a/ietf/events/migrations/0005_auto_20220902_0524.py +++ b/ietf/events/migrations/0005_auto_20220902_0524.py @@ -1,7 +1,5 @@ # 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 @@ -10,48 +8,185 @@ import wagtail.images.blocks import wagtail.snippets.blocks import wagtailmarkdown.blocks +from django.db import migrations + +import ietf.snippets.models class Migration(migrations.Migration): dependencies = [ - ('events', '0004_auto_20211101_0113'), + ("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), + 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), + 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), + 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), + 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), + 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), + 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), + 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/migrations/0009_alter_eventpage_body.py b/ietf/events/migrations/0009_alter_eventpage_body.py index cab4aa2d..b2fc676c 100644 --- a/ietf/events/migrations/0009_alter_eventpage_body.py +++ b/ietf/events/migrations/0009_alter_eventpage_body.py @@ -1,6 +1,5 @@ # Generated by Django 4.2.7 on 2024-04-03 13:40 -from django.db import migrations import wagtail.blocks import wagtail.contrib.table_block.blocks import wagtail.contrib.typed_table_block.blocks @@ -8,18 +7,72 @@ import wagtail.fields import wagtail.images.blocks import wagtailmarkdown.blocks +from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('events', '0008_alter_eventpage_body'), + ("events", "0008_alter_eventpage_body"), ] 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')), ('typed_table', wagtail.contrib.typed_table_block.blocks.TypedTableBlock([('text', wagtail.blocks.CharBlock(required=False)), ('numeric', wagtail.blocks.FloatBlock(required=False, template='blocks/float_block.html')), ('rich_text', wagtail.blocks.RichTextBlock(required=False)), ('image', wagtail.images.blocks.ImageChooserBlock(required=False))])), ('note_well', wagtail.blocks.StructBlock([], icon='placeholder', label='Note Well Text'))], use_json_field=True), + 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", + ), + ), + ( + "typed_table", + wagtail.contrib.typed_table_block.blocks.TypedTableBlock( + [ + ("text", wagtail.blocks.CharBlock(required=False)), + ( + "numeric", + wagtail.blocks.FloatBlock( + required=False, + template="blocks/float_block.html", + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock(required=False), + ), + ( + "image", + wagtail.images.blocks.ImageChooserBlock( + required=False + ), + ), + ] + ), + ), + ( + "note_well", + wagtail.blocks.StructBlock( + [], icon="placeholder", label="Note Well Text" + ), + ), + ], + use_json_field=True, + ), ), ] diff --git a/ietf/events/models.py b/ietf/events/models.py index 43233263..e25268bc 100644 --- a/ietf/events/models.py +++ b/ietf/events/models.py @@ -34,7 +34,7 @@ class LinkBlock(StructBlock): link_document = DocumentChooserBlock(required=False) def get_context(self, value, parent_context=None): - context = super(LinkBlock, self).get_context(value, parent_context) + context = super().get_context(value, parent_context) if value["link_page"]: link = value["link_page"].url elif value["link_document"]: @@ -120,10 +120,14 @@ class EventPage(Page, PromoteMixin): max_length=255, default="Meeting venue information", blank=True ) venue = StreamField( - [("address_line", blocks.CharBlock(classname="full title"))], blank=True, use_json_field=True + [("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 + [("extra", blocks.CharBlock(classname="full title"))], + blank=True, + use_json_field=True, ) reservation_name = models.CharField(max_length=255, blank=True) room_rates = StreamField( @@ -136,15 +140,21 @@ class EventPage(Page, PromoteMixin): ) 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_detail", blocks.CharBlock(classname="full title"))], + blank=True, + use_json_field=True, ) - key_details = StreamField([("item", NamedLinkGroupBlock())], blank=True, use_json_field=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, use_json_field=True) + sponsors = StreamField( + [("sponsor_category", SponsorCategoryBlock())], blank=True, use_json_field=True + ) listing_location = models.CharField( max_length=255, blank=True, diff --git a/ietf/events/tests.py b/ietf/events/tests.py index 03504e5e..40d80e5c 100644 --- a/ietf/events/tests.py +++ b/ietf/events/tests.py @@ -5,6 +5,7 @@ from django.utils import timezone from ietf.home.models import HomePage + from .factories import EventListingPageFactory, EventPageFactory from .models import EventListingPage, EventPage @@ -45,7 +46,7 @@ def test_event_page(self): assert f'href="{self.event_listing.url}"' in html def test_home_page(self): - """ The first two upcoming events are shown on the homepage. """ + """The first two upcoming events are shown on the homepage.""" response = self.client.get(path=self.home.url) assert response.status_code == 200 html = response.content.decode() diff --git a/ietf/forms/migrations/0001_initial.py b/ietf/forms/migrations/0001_initial.py index c7b6f257..82291204 100644 --- a/ietf/forms/migrations/0001_initial.py +++ b/ietf/forms/migrations/0001_initial.py @@ -1,6 +1,4 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.11.29 on 2020-04-10 18:46 -from __future__ import unicode_literals import django.db.models.deletion import modelcluster.fields diff --git a/ietf/forms/migrations/0002_formfield_clean_name.py b/ietf/forms/migrations/0002_formfield_clean_name.py index b31c82f1..79b6f5bd 100644 --- a/ietf/forms/migrations/0002_formfield_clean_name.py +++ b/ietf/forms/migrations/0002_formfield_clean_name.py @@ -6,13 +6,19 @@ class Migration(migrations.Migration): dependencies = [ - ('forms', '0001_initial'), + ("forms", "0001_initial"), ] operations = [ migrations.AddField( - model_name='formfield', - name='clean_name', - field=models.CharField(blank=True, default='', help_text='Safe name of the form field, the label converted to ascii_snake_case', max_length=255, verbose_name='name'), + model_name="formfield", + name="clean_name", + field=models.CharField( + blank=True, + default="", + help_text="Safe name of the form field, the label converted to ascii_snake_case", + max_length=255, + verbose_name="name", + ), ), ] diff --git a/ietf/forms/migrations/0003_auto_20220722_0302.py b/ietf/forms/migrations/0003_auto_20220722_0302.py index abee178c..f59e1af7 100644 --- a/ietf/forms/migrations/0003_auto_20220722_0302.py +++ b/ietf/forms/migrations/0003_auto_20220722_0302.py @@ -1,34 +1,50 @@ # Generated by Django 3.2.13 on 2022-07-22 02:02 -from django.db import migrations, models import wagtail.contrib.forms.models +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('forms', '0002_formfield_clean_name'), + ("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'), + 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'), + 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'), + 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'), + 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 index 1266ca54..72710c68 100644 --- a/ietf/forms/migrations/0004_convert_unicode_to_text.py +++ b/ietf/forms/migrations/0004_convert_unicode_to_text.py @@ -1,20 +1,18 @@ +from django.db import migrations -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') + 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.form_data = str(submission.form_data.replace("\\u0000", "")) submission.save() class Migration(migrations.Migration): dependencies = [ - ('forms', '0003_auto_20220722_0302'), + ("forms", "0003_auto_20220722_0302"), ] - operations = [ - migrations.RunPython(convert_unicode_to_text) - ] + operations = [migrations.RunPython(convert_unicode_to_text)] diff --git a/ietf/forms/models.py b/ietf/forms/models.py index 54450ab8..98aed430 100644 --- a/ietf/forms/models.py +++ b/ietf/forms/models.py @@ -1,14 +1,11 @@ from logging import Logger from django.contrib import messages -from django.views.defaults import server_error from modelcluster.fields import ParentalKey from wagtail.admin.panels import FieldPanel, InlinePanel, MultiFieldPanel from wagtail.contrib.forms.models import AbstractEmailForm, AbstractFormField from wagtail.fields import RichTextField -from ietf.views import server_error - logger = Logger(__name__) @@ -35,17 +32,17 @@ def send_mail(self, form): try: super().send_mail(form) except Exception as ex: - logger.error("Failed to send email with exception: {}".format(ex)) - raise EmailException + logger.error(f"Failed to send email with exception: {ex}") + raise EmailException from ex def serve(self, request, *args, **kwargs): try: return super().serve(request, *args, **kwargs) - except EmailException as Ex: + except EmailException: messages.add_message( request, messages.ERROR, message="Failed to send email" ) - raise EmailException + raise FormPage.content_panels = [ diff --git a/ietf/forms/tests.py b/ietf/forms/tests.py index 37674c02..32dc5724 100644 --- a/ietf/forms/tests.py +++ b/ietf/forms/tests.py @@ -3,6 +3,7 @@ from django.test import Client from ietf.home.models import HomePage + from .factories import FormPageFactory from .models import FormPage diff --git a/ietf/glossary/migrations/0001_initial.py b/ietf/glossary/migrations/0001_initial.py index e0d6a4f2..02466913 100644 --- a/ietf/glossary/migrations/0001_initial.py +++ b/ietf/glossary/migrations/0001_initial.py @@ -1,10 +1,8 @@ -# -*- coding: utf-8 -*- # 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 +from django.db import migrations, models class Migration(migrations.Migration): @@ -12,43 +10,144 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('snippets', '0001_initial'), - ('images', '0001_initial'), - ('wagtailcore', '0040_page_draft_title'), - ('wagtaildocs', '0008_document_file_size'), + ("snippets", "0001_initial"), + ("images", "0001_initial"), + ("wagtailcore", "0040_page_draft_title"), + ("wagtaildocs", "0008_document_file_size"), ] operations = [ migrations.CreateModel( - name='GlossaryPage', + name="GlossaryPage", 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='The page introduction text. You can only use 511 characters.', max_length=511)), - ('call_to_action', models.ForeignKey(blank=True, 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="The page introduction text. You can only use 511 characters.", + max_length=511, + ), + ), + ( + "call_to_action", + models.ForeignKey( + blank=True, + 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='GlossaryPageRelatedLink', + name="GlossaryPageRelatedLink", 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='glossary.GlossaryPage')), + ( + "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="glossary.GlossaryPage", + ), + ), ], options={ - 'ordering': ['sort_order'], - 'abstract': False, + "ordering": ["sort_order"], + "abstract": False, }, ), ] diff --git a/ietf/glossary/models.py b/ietf/glossary/models.py index e610df2a..43af0ba9 100644 --- a/ietf/glossary/models.py +++ b/ietf/glossary/models.py @@ -45,7 +45,7 @@ def siblings(self): return self.get_siblings().live().public().filter(show_in_menus=True).specific() def get_context(self, request, *args, **kwargs): - context = super(GlossaryPage, self).get_context(request, *args, **kwargs) + context = super().get_context(request, *args, **kwargs) glossary_items = GlossaryItem.objects.all() if request.GET.get("query"): @@ -54,7 +54,7 @@ def get_context(self, request, *args, **kwargs): context["glossary_items"] = {} for item in glossary_items: - if item.title[0:1].upper() not in context["glossary_items"].keys(): + if item.title[0:1].upper() not in context["glossary_items"]: context["glossary_items"][item.title[0:1].upper()] = [item] else: context["glossary_items"][item.title[0:1].upper()].append(item) diff --git a/ietf/glossary/tests.py b/ietf/glossary/tests.py index 75669463..0d20f682 100644 --- a/ietf/glossary/tests.py +++ b/ietf/glossary/tests.py @@ -2,6 +2,7 @@ from django.test import Client from ietf.home.models import HomePage + from .factories import GlossaryPageFactory from .models import GlossaryPage diff --git a/ietf/home/migrations/0001_initial.py b/ietf/home/migrations/0001_initial.py index d7cb7dbe..299de8a5 100644 --- a/ietf/home/migrations/0001_initial.py +++ b/ietf/home/migrations/0001_initial.py @@ -1,10 +1,8 @@ -# -*- coding: utf-8 -*- # 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 +from django.db import migrations, models class Migration(migrations.Migration): @@ -12,59 +10,186 @@ 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='HomePage', + name="HomePage", 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')), - ('heading', models.CharField(max_length=255)), - ('introduction', models.CharField(max_length=255)), - ('button_text', models.CharField(blank=True, max_length=255)), - ('request_for_comments_section_body', models.CharField(max_length=500)), - ('working_groups_section_body', models.CharField(max_length=500)), - ('button_link', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailcore.Page')), - ('call_to_action', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='snippets.CallToAction')), - ('highlighted_request_for_comment', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='snippets.RFC')), - ('highlighted_working_group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='snippets.WorkingGroup')), - ('main_image', models.ForeignKey(blank=True, 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", + ), + ), + ("heading", models.CharField(max_length=255)), + ("introduction", models.CharField(max_length=255)), + ("button_text", models.CharField(blank=True, max_length=255)), + ("request_for_comments_section_body", models.CharField(max_length=500)), + ("working_groups_section_body", models.CharField(max_length=500)), + ( + "button_link", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailcore.Page", + ), + ), + ( + "call_to_action", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="snippets.CallToAction", + ), + ), + ( + "highlighted_request_for_comment", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="snippets.RFC", + ), + ), + ( + "highlighted_working_group", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="snippets.WorkingGroup", + ), + ), + ( + "main_image", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="images.IETFImage", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('wagtailcore.page',), + bases=("wagtailcore.page",), ), migrations.CreateModel( - name='RequestForCommentsSectionLinks', + name="RequestForCommentsSectionLinks", 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)), - ('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='request_for_comments_section_links', to='home.HomePage')), + ( + "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)), + ( + "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="request_for_comments_section_links", + to="home.HomePage", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='WorkingGroupsSectionLinks', + name="WorkingGroupsSectionLinks", 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)), - ('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='working_groups_section_links', to='home.HomePage')), + ( + "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)), + ( + "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="working_groups_section_links", + to="home.HomePage", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), ] diff --git a/ietf/home/migrations/0003_remove_bottom_content.py b/ietf/home/migrations/0003_remove_bottom_content.py index 7f3d7952..bf1fe8e3 100644 --- a/ietf/home/migrations/0003_remove_bottom_content.py +++ b/ietf/home/migrations/0003_remove_bottom_content.py @@ -6,42 +6,42 @@ class Migration(migrations.Migration): dependencies = [ - ('home', '0002_iabhomepage'), + ("home", "0002_iabhomepage"), ] operations = [ migrations.RemoveField( - model_name='workinggroupssectionlinks', - name='link_document', + model_name="workinggroupssectionlinks", + name="link_document", ), migrations.RemoveField( - model_name='workinggroupssectionlinks', - name='link_page', + model_name="workinggroupssectionlinks", + name="link_page", ), migrations.RemoveField( - model_name='workinggroupssectionlinks', - name='page', + model_name="workinggroupssectionlinks", + name="page", ), migrations.RemoveField( - model_name='homepage', - name='highlighted_request_for_comment', + model_name="homepage", + name="highlighted_request_for_comment", ), migrations.RemoveField( - model_name='homepage', - name='highlighted_working_group', + model_name="homepage", + name="highlighted_working_group", ), migrations.RemoveField( - model_name='homepage', - name='request_for_comments_section_body', + model_name="homepage", + name="request_for_comments_section_body", ), migrations.RemoveField( - model_name='homepage', - name='working_groups_section_body', + model_name="homepage", + name="working_groups_section_body", ), migrations.DeleteModel( - name='RequestForCommentsSectionLinks', + name="RequestForCommentsSectionLinks", ), migrations.DeleteModel( - name='WorkingGroupsSectionLinks', + name="WorkingGroupsSectionLinks", ), ] diff --git a/ietf/home/models.py b/ietf/home/models.py index 9994fcba..850b4ae2 100644 --- a/ietf/home/models.py +++ b/ietf/home/models.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from datetime import datetime from xml.etree import ElementTree @@ -61,7 +59,9 @@ def event_index(self): def blog_index(self): return BlogIndexPage.objects.live().first() - def blogs(self, bp_kwargs={}): + def blogs(self, bp_kwargs=None): + if bp_kwargs is None: + bp_kwargs = {} return ( BlogPage.objects.live() .filter(**bp_kwargs) @@ -120,33 +120,33 @@ class Meta: blog_index_url = settings.IAB_IETF_BLOG_URL def announcements(self): - return ( - IABAnnouncementPage.objects.all() - .live() - .order_by("-date")[:2] - ) + return IABAnnouncementPage.objects.all().live().order_by("-date")[:2] def announcement_index(self): return IABAnnouncementIndexPage.objects.live().first() - def blogs(self, bp_kwargs={}): + def blogs(self, bp_kwargs=None): + if bp_kwargs is None: + bp_kwargs = {} entries = [] try: response = get_request(settings.IAB_FEED_URL) xml_data = response.text root = ElementTree.fromstring(xml_data) - for item in root.iter('item'): - title = item.find('title').text - description = item.find('description').text - link = item.find('link').text - published_date = datetime.strptime(item.find('pubDate').text, '%a, %d %b %Y %H:%M:%S %z') + for item in root.iter("item"): + title = item.find("title").text + description = item.find("description").text + link = item.find("link").text + published_date = datetime.strptime( + item.find("pubDate").text, "%a, %d %b %Y %H:%M:%S %z" + ) entry_data = { - 'title': title, - 'description': description, - 'link': link, - 'published_date': published_date, + "title": title, + "description": description, + "link": link, + "published_date": published_date, } entries.append(entry_data) except Exception as _: diff --git a/ietf/home/tests.py b/ietf/home/tests.py index 5558c2bf..071e0c3d 100644 --- a/ietf/home/tests.py +++ b/ietf/home/tests.py @@ -1,5 +1,5 @@ -from django.test import Client import pytest +from django.test import Client from ietf.standard.factories import IABStandardPageFactory, StandardPageFactory from ietf.standard.models import StandardPage diff --git a/ietf/iesg_statement/factories.py b/ietf/iesg_statement/factories.py index 7e8a01a6..7825cf84 100644 --- a/ietf/iesg_statement/factories.py +++ b/ietf/iesg_statement/factories.py @@ -2,6 +2,7 @@ import wagtail_factories from ietf.utils.factories import StandardBlockFactory + from .models import IESGStatementIndexPage, IESGStatementPage diff --git a/ietf/iesg_statement/management/commands/move_iesg_statements.py b/ietf/iesg_statement/management/commands/move_iesg_statements.py index 07f89f2f..ecee0b0b 100644 --- a/ietf/iesg_statement/management/commands/move_iesg_statements.py +++ b/ietf/iesg_statement/management/commands/move_iesg_statements.py @@ -1,125 +1,139 @@ -from django.core.management.base import BaseCommand from django.contrib.auth.models import User - +from django.core.management.base import BaseCommand from wagtail.contrib.redirects.models import Redirect from ietf.blog.models import BlogPage -from ietf.iesg_statement.models import IESGStatementPage, IESGStatementIndexPage, IESGStatementTopic -from ietf.standard.models import StandardPage +from ietf.iesg_statement.models import ( + IESGStatementIndexPage, + IESGStatementPage, + IESGStatementTopic, +) from ietf.snippets.models import PrimaryTopic +from ietf.standard.models import StandardPage slug_map = { - 'iesg-statement-maximizing-encrypted-access-ietf-information' : 'maximizing-encrypted-access', - 'iesg-statement-internet-draft-authorship' : 'internet-draft-authorship', - 'iesg-statement-designating-rfcs-historic' : 'designating-rfcs-historic-2014-07-20', - 'discuss-criteria-iesg-review' : 'iesg-discuss-criteria', - 'guidance-face-face-and-virtual-interim-meetings' : 'interim-meetings-guidance-2016-01-16', - 'writable-mib-module-iesg-statement' : 'writable-mib-module', - 'ietf-anti-harassment-policy' : 'anti-harassment-policy', - 'iesg-statement-removal-internet-draft-ietf-web-site' : 'internet-draft-removal', - 'iesg-statement-ethertypes' : 'ethertypes', - 'iesg-statement-designating-rfcs-historic-2011-10-20' : 'designating-rfcs-historic-2011-10-20', - 'iesg-statement-designating-rfcs-historic-2011-06-27' : 'designating-rfcs-historic-2011-06-27', - 'iesg-statement-iesg-processing-rfc-errata-concerning-rfc-metadata' : 'rfc-metadata-errata', - 'iesg-statement-document-shepherds' : 'document-shepherds', - 'iesg-statement-nomcom-eligibility-and-day-passes' : 'nomcom-eligibility-day-passes', - 'iesg-statement-usage-assignable-codepoints-addresses-and-names-specification-examples' : 'assignable-codepoints-addresses-names', - 'iesg-statement-copyright' : 'copyright-2009-09-08', - 'proposed-status-ietf-documents-reserving-resources-example-purposes' : 'reserving-resources-examples', - 'guidance-interim-meetings-conference-calls-and-jabber-sessions' : 'interim-meetings-guidance-2008-09-02', - 'iesg-processing-rfc-errata-ietf-stream' : 'processing-rfc-errata', - 'iesg-statement-spam-control-ietf-mailing-lists' : 'spam-control-2008-04-14', - 'guidance-spam-control-ietf-mailing-lists' : 'spam-control-2006-01-09', - 'iesg-guidance-moderation-ietf-working-group-mailing-lists' : 'mailing-lists-moderation', - 'iesg-statement-registration-requests-uris-containing-telephone-numbers' : 'registration-requests-uris', - 'iesg-statement-rfc3406-and-urn-namespaces-registry-review' : 'urn-namespaces-registry', - 'advice-wg-chairs-dealing-topic-postings' : 'off-topic-postings', - 'appeals-iesg-and-area-director-actions-and-decisions' : 'appeals-actions-decisions', - 'experimental-specification-new-congestion-control-algorithms' : 'experimental-congestion-control', - 'guidance-area-director-sponsoring-documents' : 'area-director-sponsoring-documents', - 'last-call-guidance-community' : 'last-call-guidance', - 'iesg-statement-normative-and-informative-references' : 'normative-informative-references', - 'iesg-statement-disruptive-posting' : 'disruptive-posting', - 'iesg-statement-auth48-state' : 'auth48', - 'syntax-format-definitions' : 'syntax-format-definitions', - 'iesg-statement-idn' : 'idn', - 'copyright-statement-mib-and-pib-modules' : 'copyright-2002-11-27', - 'guidance-spam-control-ietf-mailing-lists-2002-03-13' : 'spam-control-2002-03-13', - 'design-teams' : 'design-teams', - 'guidelines-use-formal-languages-ietf-specifications' : 'formal-languages-use', - 'establishment-temporary-sub-ip-area' : 'sub-ip-area-2001-03-21', - 'plans-organize-sub-ip-technologies-ietf' : 'sub-ip-area-2000-11-20', - 'new-ietf-work-area' : 'sub-ip-area-2000-12-06', - 'guidance-interim-ietf-working-group-meetings-and-conference-calls' : 'interim-meetings-guidance-2000-08-29', - 'ietf-meeting-photography-policy' : 'meeting-photography-policy', - 'support-documents-ietf-working-groups' : 'support-documents', - 'license-file-open-source-repositories' : 'open-source-repositories-license', + "iesg-statement-maximizing-encrypted-access-ietf-information": "maximizing-encrypted-access", + "iesg-statement-internet-draft-authorship": "internet-draft-authorship", + "iesg-statement-designating-rfcs-historic": "designating-rfcs-historic-2014-07-20", + "discuss-criteria-iesg-review": "iesg-discuss-criteria", + "guidance-face-face-and-virtual-interim-meetings": "interim-meetings-guidance-2016-01-16", + "writable-mib-module-iesg-statement": "writable-mib-module", + "ietf-anti-harassment-policy": "anti-harassment-policy", + "iesg-statement-removal-internet-draft-ietf-web-site": "internet-draft-removal", + "iesg-statement-ethertypes": "ethertypes", + "iesg-statement-designating-rfcs-historic-2011-10-20": "designating-rfcs-historic-2011-10-20", + "iesg-statement-designating-rfcs-historic-2011-06-27": "designating-rfcs-historic-2011-06-27", + "iesg-statement-iesg-processing-rfc-errata-concerning-rfc-metadata": "rfc-metadata-errata", + "iesg-statement-document-shepherds": "document-shepherds", + "iesg-statement-nomcom-eligibility-and-day-passes": "nomcom-eligibility-day-passes", + "iesg-statement-usage-assignable-codepoints-addresses-and-names-specification-examples": "assignable-codepoints-addresses-names", + "iesg-statement-copyright": "copyright-2009-09-08", + "proposed-status-ietf-documents-reserving-resources-example-purposes": "reserving-resources-examples", + "guidance-interim-meetings-conference-calls-and-jabber-sessions": "interim-meetings-guidance-2008-09-02", + "iesg-processing-rfc-errata-ietf-stream": "processing-rfc-errata", + "iesg-statement-spam-control-ietf-mailing-lists": "spam-control-2008-04-14", + "guidance-spam-control-ietf-mailing-lists": "spam-control-2006-01-09", + "iesg-guidance-moderation-ietf-working-group-mailing-lists": "mailing-lists-moderation", + "iesg-statement-registration-requests-uris-containing-telephone-numbers": "registration-requests-uris", + "iesg-statement-rfc3406-and-urn-namespaces-registry-review": "urn-namespaces-registry", + "advice-wg-chairs-dealing-topic-postings": "off-topic-postings", + "appeals-iesg-and-area-director-actions-and-decisions": "appeals-actions-decisions", + "experimental-specification-new-congestion-control-algorithms": "experimental-congestion-control", + "guidance-area-director-sponsoring-documents": "area-director-sponsoring-documents", + "last-call-guidance-community": "last-call-guidance", + "iesg-statement-normative-and-informative-references": "normative-informative-references", + "iesg-statement-disruptive-posting": "disruptive-posting", + "iesg-statement-auth48-state": "auth48", + "syntax-format-definitions": "syntax-format-definitions", + "iesg-statement-idn": "idn", + "copyright-statement-mib-and-pib-modules": "copyright-2002-11-27", + "guidance-spam-control-ietf-mailing-lists-2002-03-13": "spam-control-2002-03-13", + "design-teams": "design-teams", + "guidelines-use-formal-languages-ietf-specifications": "formal-languages-use", + "establishment-temporary-sub-ip-area": "sub-ip-area-2001-03-21", + "plans-organize-sub-ip-technologies-ietf": "sub-ip-area-2000-11-20", + "new-ietf-work-area": "sub-ip-area-2000-12-06", + "guidance-interim-ietf-working-group-meetings-and-conference-calls": "interim-meetings-guidance-2000-08-29", + "ietf-meeting-photography-policy": "meeting-photography-policy", + "support-documents-ietf-working-groups": "support-documents", + "license-file-open-source-repositories": "open-source-repositories-license", } class Command(BaseCommand): - help = 'Moves the iesg statements from the blog app to the iesg_statements app' + help = "Moves the iesg statements from the blog app to the iesg_statements app" def handle(self, *args, **options): if IESGStatementPage.objects.exists(): - print("IESGStatementPages exist. This command has probably already been run.") + print( + "IESGStatementPages exist. This command has probably already been run." + ) print("Exiting without making any changes.") return - + iesg_page = StandardPage.objects.get(pk=1210) index_page = IESGStatementIndexPage( - title='IESG Statements', - slug='statements', - url_path=iesg_page.url_path+'/statements/' + title="IESG Statements", + slug="statements", + url_path=iesg_page.url_path + "/statements/", ) iesg_page.add_child(instance=index_page) iesg_page.save() - for stmt in BlogPage.objects.filter(primary_topics__topic__title="IESG Statements"): + for stmt in BlogPage.objects.filter( + primary_topics__topic__title="IESG Statements" + ): if stmt.slug in slug_map: new_slug = slug_map[stmt.slug] else: - new_slug = stmt.slug[15:] if stmt.slug.startswith('iesg-statement-') else stmt.slug + new_slug = ( + stmt.slug[15:] + if stmt.slug.startswith("iesg-statement-") + else stmt.slug + ) new_page = IESGStatementPage( - title = stmt.title, - slug = new_slug, - date_published = stmt.date_published, - introduction = stmt.introduction, - url_path = index_page.url_path+'/'+new_slug, - draft_title = stmt.draft_title, - owner = stmt.owner, - seo_title= stmt.seo_title, - live = stmt.live, - has_unpublished_changes = stmt.has_unpublished_changes, - show_in_menus = stmt.show_in_menus, - search_description = stmt.search_description, - go_live_at = stmt.go_live_at, - expire_at = stmt.expire_at, - expired = stmt.expired, - locked = stmt.locked, - first_published_at = stmt.first_published_at, - last_published_at = stmt.last_published_at, - latest_revision_created_at = stmt.latest_revision_created_at, - live_revision = stmt.live_revision, - ) + title=stmt.title, + slug=new_slug, + date_published=stmt.date_published, + introduction=stmt.introduction, + url_path=index_page.url_path + "/" + new_slug, + draft_title=stmt.draft_title, + owner=stmt.owner, + seo_title=stmt.seo_title, + live=stmt.live, + has_unpublished_changes=stmt.has_unpublished_changes, + show_in_menus=stmt.show_in_menus, + search_description=stmt.search_description, + go_live_at=stmt.go_live_at, + expire_at=stmt.expire_at, + expired=stmt.expired, + locked=stmt.locked, + first_published_at=stmt.first_published_at, + last_published_at=stmt.last_published_at, + latest_revision_created_at=stmt.latest_revision_created_at, + live_revision=stmt.live_revision, + ) index_page.add_child(instance=new_page) # Intentionally not creating/publishing a new revision new_page.body = stmt.body new_page.save() for st in stmt.secondary_topics.all(): - IESGStatementTopic.objects.create(page=new_page,topic=st.topic) + IESGStatementTopic.objects.create(page=new_page, topic=st.topic) Redirect.objects.create( - old_path=stmt.url[:-1] if stmt.url.endswith('/') else stmt.url, + old_path=stmt.url[:-1] if stmt.url.endswith("/") else stmt.url, is_permanent=True, - redirect_page=new_page + redirect_page=new_page, ) - BlogPage.objects.filter(primary_topics__topic__title="IESG Statements").delete() PrimaryTopic.objects.filter(title="IESG Statements").delete() # todo - make this robust in case the iesg page gets edited before this is run on production - iesg_page.key_info[6].value.source = '

List\xa0All\xa0\xa0| \xa0On\xa0Mailing\xa0Lists\xa0|\xa0On\xa0Meetings\xa0|\xa0On\xa0Procedures\xa0|\xa0On\xa0Technical\xa0Issues

' - iesg_page.save_revision(user=User.objects.get(username='robert.sparks')).publish() + iesg_page.key_info[6].value.source = ( + '

List\xa0All\xa0\xa0| \xa0On\xa0Mailing\xa0Lists\xa0|\xa0On\xa0Meetings\xa0|\xa0On\xa0Procedures\xa0|\xa0On\xa0Technical\xa0Issues

' + ) + iesg_page.save_revision( + user=User.objects.get(username="robert.sparks") + ).publish() diff --git a/ietf/iesg_statement/migrations/0001_initial.py b/ietf/iesg_statement/migrations/0001_initial.py index 3bb27277..677e999b 100644 --- a/ietf/iesg_statement/migrations/0001_initial.py +++ b/ietf/iesg_statement/migrations/0001_initial.py @@ -1,6 +1,4 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.11.29 on 2020-04-10 18:46 -from __future__ import unicode_literals import django.db.models.deletion import modelcluster.fields diff --git a/ietf/iesg_statement/migrations/0008_alter_iesgstatementpage_body.py b/ietf/iesg_statement/migrations/0008_alter_iesgstatementpage_body.py index c6190cee..58f89e90 100644 --- a/ietf/iesg_statement/migrations/0008_alter_iesgstatementpage_body.py +++ b/ietf/iesg_statement/migrations/0008_alter_iesgstatementpage_body.py @@ -1,6 +1,5 @@ # Generated by Django 4.2.7 on 2024-04-03 13:40 -from django.db import migrations import wagtail.blocks import wagtail.contrib.table_block.blocks import wagtail.contrib.typed_table_block.blocks @@ -8,18 +7,72 @@ import wagtail.fields import wagtail.images.blocks import wagtailmarkdown.blocks +from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('iesg_statement', '0007_alter_iesgstatementpage_body'), + ("iesg_statement", "0007_alter_iesgstatementpage_body"), ] operations = [ migrations.AlterField( - 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')), ('typed_table', wagtail.contrib.typed_table_block.blocks.TypedTableBlock([('text', wagtail.blocks.CharBlock(required=False)), ('numeric', wagtail.blocks.FloatBlock(required=False, template='blocks/float_block.html')), ('rich_text', wagtail.blocks.RichTextBlock(required=False)), ('image', wagtail.images.blocks.ImageChooserBlock(required=False))])), ('note_well', wagtail.blocks.StructBlock([], icon='placeholder', label='Note Well Text'))], use_json_field=True), + 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", + ), + ), + ( + "typed_table", + wagtail.contrib.typed_table_block.blocks.TypedTableBlock( + [ + ("text", wagtail.blocks.CharBlock(required=False)), + ( + "numeric", + wagtail.blocks.FloatBlock( + required=False, + template="blocks/float_block.html", + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock(required=False), + ), + ( + "image", + wagtail.images.blocks.ImageChooserBlock( + required=False + ), + ), + ] + ), + ), + ( + "note_well", + wagtail.blocks.StructBlock( + [], icon="placeholder", label="Note Well Text" + ), + ), + ], + use_json_field=True, + ), ), ] diff --git a/ietf/iesg_statement/models.py b/ietf/iesg_statement/models.py index 831e3bc8..7855493d 100644 --- a/ietf/iesg_statement/models.py +++ b/ietf/iesg_statement/models.py @@ -18,7 +18,6 @@ from ..bibliography.models import BibliographyMixin from ..snippets.models import Topic from ..utils.blocks import StandardBlock - from ..utils.models import PromoteMixin @@ -159,7 +158,7 @@ def siblings(self): ) def get_context(self, request, *args, **kwargs): - context = super(IESGStatementPage, self).get_context(request, *args, **kwargs) + context = super().get_context(request, *args, **kwargs) siblings = self.siblings query_string = "?" filter_text_builder = build_filter_text @@ -170,7 +169,7 @@ def get_context(self, request, *args, **kwargs): try: related_object = functions[0](search_query) siblings = functions[1](siblings, related_object) - query_string += "%s=%s&" % (parameter, search_query) + query_string += f"{parameter}={search_query}&" filter_text_builder = partial( filter_text_builder, **{parameter: related_object.__str__()} ) @@ -258,7 +257,7 @@ def redirect_first(self, request, *args, **kwargs): try: related_object = functions[0](search_query) statements = functions[1](statements, related_object) - query_string += "%s=%s&" % (parameter, search_query) + query_string += f"{parameter}={search_query}&" except (ValueError, ObjectDoesNotExist): pass if statements: diff --git a/ietf/iesg_statement/tests.py b/ietf/iesg_statement/tests.py index 9ca417db..56569884 100644 --- a/ietf/iesg_statement/tests.py +++ b/ietf/iesg_statement/tests.py @@ -1,12 +1,12 @@ from datetime import timedelta -import factory import pytest from bs4 import BeautifulSoup from django.test import Client from django.utils import timezone from ietf.home.models import HomePage + from .factories import IESGStatementIndexPageFactory, IESGStatementPageFactory from .models import IESGStatementIndexPage, IESGStatementPage diff --git a/ietf/images/migrations/0001_initial.py b/ietf/images/migrations/0001_initial.py index d5dffcf0..2d4fdf2b 100644 --- a/ietf/images/migrations/0001_initial.py +++ b/ietf/images/migrations/0001_initial.py @@ -1,6 +1,4 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.11.29 on 2020-04-10 18:46 -from __future__ import unicode_literals import django.db.models.deletion import taggit.managers diff --git a/ietf/images/migrations/0002_alter_ietfimage_file_hash.py b/ietf/images/migrations/0002_alter_ietfimage_file_hash.py index cd64bf42..20df0236 100644 --- a/ietf/images/migrations/0002_alter_ietfimage_file_hash.py +++ b/ietf/images/migrations/0002_alter_ietfimage_file_hash.py @@ -6,13 +6,15 @@ class Migration(migrations.Migration): dependencies = [ - ('images', '0001_initial'), + ("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), + model_name="ietfimage", + name="file_hash", + field=models.CharField( + blank=True, db_index=True, editable=False, max_length=40 + ), ), ] diff --git a/ietf/images/migrations/0003_wagtail_42_wagtailimagefield.py b/ietf/images/migrations/0003_wagtail_42_wagtailimagefield.py index 5844449f..5ecdf480 100644 --- a/ietf/images/migrations/0003_wagtail_42_wagtailimagefield.py +++ b/ietf/images/migrations/0003_wagtail_42_wagtailimagefield.py @@ -1,24 +1,33 @@ # Generated by Django 4.0.10 on 2023-11-29 10:19 -from django.db import migrations import wagtail.images.models +from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('images', '0002_alter_ietfimage_file_hash'), + ("images", "0002_alter_ietfimage_file_hash"), ] operations = [ migrations.AlterField( - model_name='ietfimage', - name='file', - field=wagtail.images.models.WagtailImageField(height_field='height', upload_to=wagtail.images.models.get_upload_to, verbose_name='file', width_field='width'), + model_name="ietfimage", + name="file", + field=wagtail.images.models.WagtailImageField( + height_field="height", + upload_to=wagtail.images.models.get_upload_to, + verbose_name="file", + width_field="width", + ), ), migrations.AlterField( - model_name='ietfrendition', - name='file', - field=wagtail.images.models.WagtailImageField(height_field='height', upload_to=wagtail.images.models.get_rendition_upload_to, width_field='width'), + model_name="ietfrendition", + name="file", + field=wagtail.images.models.WagtailImageField( + height_field="height", + upload_to=wagtail.images.models.get_rendition_upload_to, + width_field="width", + ), ), ] diff --git a/ietf/images/migrations/0004_django_42_rendition_storage.py b/ietf/images/migrations/0004_django_42_rendition_storage.py index e5348115..4772265b 100644 --- a/ietf/images/migrations/0004_django_42_rendition_storage.py +++ b/ietf/images/migrations/0004_django_42_rendition_storage.py @@ -1,19 +1,24 @@ # Generated by Django 4.2.7 on 2023-11-29 12:17 -from django.db import migrations import wagtail.images.models +from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('images', '0003_wagtail_42_wagtailimagefield'), + ("images", "0003_wagtail_42_wagtailimagefield"), ] operations = [ migrations.AlterField( - model_name='ietfrendition', - name='file', - field=wagtail.images.models.WagtailImageField(height_field='height', storage=wagtail.images.models.get_rendition_storage, upload_to=wagtail.images.models.get_rendition_upload_to, width_field='width'), + model_name="ietfrendition", + name="file", + field=wagtail.images.models.WagtailImageField( + height_field="height", + storage=wagtail.images.models.get_rendition_storage, + upload_to=wagtail.images.models.get_rendition_upload_to, + width_field="width", + ), ), ] diff --git a/ietf/images/models.py b/ietf/images/models.py index 062aa9da..a07564c9 100644 --- a/ietf/images/models.py +++ b/ietf/images/models.py @@ -1,20 +1,17 @@ from django.db import models - -from wagtail.images.models import Image, AbstractImage, AbstractRendition +from wagtail.images.models import AbstractImage, AbstractRendition, Image class IETFImage(AbstractImage): caption = models.CharField(max_length=255, null=True, blank=True) - admin_form_fields = Image.admin_form_fields + ( - 'caption', - ) + admin_form_fields = Image.admin_form_fields + ("caption",) class IETFRendition(AbstractRendition): - image = models.ForeignKey(IETFImage, related_name='renditions', on_delete=models.CASCADE) + image = models.ForeignKey( + IETFImage, related_name="renditions", on_delete=models.CASCADE + ) class Meta: - unique_together = ( - ('image', 'filter_spec', 'focal_point_key'), - ) + unique_together = (("image", "filter_spec", "focal_point_key"),) diff --git a/ietf/search/tests.py b/ietf/search/tests.py index 592ef6d2..f60f52b5 100644 --- a/ietf/search/tests.py +++ b/ietf/search/tests.py @@ -27,8 +27,9 @@ def test_search(self): assert resp.status_code == 200 assert resp.context["search_query"] == query - assert list(resp.context["search_results"]) == \ - [Page.objects.get(pk=self.standard_page.pk)] + assert list(resp.context["search_results"]) == [ + Page.objects.get(pk=self.standard_page.pk) + ] def test_empty_query(self): resp = self.client.get(f"{reverse('search')}?query=") @@ -38,12 +39,14 @@ def test_empty_page(self): query = "random" resp = self.client.get(f"{reverse('search')}?query={query}&page=100") assert resp.status_code == 200 - assert list(resp.context["search_results"]) == \ - [Page.objects.get(pk=self.standard_page.pk)] + assert list(resp.context["search_results"]) == [ + Page.objects.get(pk=self.standard_page.pk) + ] def test_non_integer_page(self): query = "random" resp = self.client.get(f"{reverse('search')}?query={query}&page=foo") assert resp.status_code == 200 - assert list(resp.context["search_results"]) == \ - [Page.objects.get(pk=self.standard_page.pk)] + assert list(resp.context["search_results"]) == [ + Page.objects.get(pk=self.standard_page.pk) + ] diff --git a/ietf/search/views.py b/ietf/search/views.py index 448951fd..a7614460 100644 --- a/ietf/search/views.py +++ b/ietf/search/views.py @@ -1,7 +1,7 @@ from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator from django.shortcuts import render -from wagtail.models import Page from wagtail.contrib.search_promotions.models import Query +from wagtail.models import Page def search(request): diff --git a/ietf/settings/base.py b/ietf/settings/base.py index 9115f39a..e7c2acd4 100644 --- a/ietf/settings/base.py +++ b/ietf/settings/base.py @@ -13,8 +13,6 @@ # Build paths inside the project like this: os.path.join(BASE_DIR, ...) import os -from django.conf import global_settings - PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(PROJECT_DIR) @@ -246,7 +244,7 @@ _cf_purge_bearer_token = os.environ.get("CLOUDFLARE_CACHE_PURGE_BEARER_TOKEN") _cf_purge_zone_id = os.environ.get("CLOUDFLARE_CACHE_PURGE_ZONE_ID") if _cf_purge_bearer_token and _cf_purge_zone_id: # pragma: no cover - INSTALLED_APPS += ( "wagtail.contrib.frontend_cache", ) + INSTALLED_APPS += ("wagtail.contrib.frontend_cache",) WAGTAILFRONTENDCACHE = { "cloudflare": { "BACKEND": "wagtail.contrib.frontend_cache.backends.CloudflareBackend", diff --git a/ietf/settings/dev.py b/ietf/settings/dev.py index 848a5481..b593a467 100644 --- a/ietf/settings/dev.py +++ b/ietf/settings/dev.py @@ -1,14 +1,15 @@ -from .base import * +import contextlib +from .base import * # noqa: F403 # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'CHANGEME!!!' +SECRET_KEY = "CHANGEME!!!" -EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' +EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" # Process all tasks synchronously. @@ -16,7 +17,5 @@ CELERY_EAGER_PROPAGATES_EXCEPTIONS = True CELERY_ALWAYS_EAGER = True -try: # pragma: no cover - from .local import * -except ImportError: # pragma: no cover - pass +with contextlib.suppress(ImportError): + from .local import * # noqa: F403 diff --git a/ietf/settings/docker/__init__.py b/ietf/settings/docker/__init__.py index 3b2a403a..4e665532 100644 --- a/ietf/settings/docker/__init__.py +++ b/ietf/settings/docker/__init__.py @@ -1,10 +1,11 @@ from typed_environment_configuration import ( BoolVariable, - StringVariable, - StringListVariable, FillVars, + StringListVariable, + StringVariable, ) -from ..base import * + +from ..base import * # noqa: F403 _ENVVARS = [ StringVariable( @@ -30,4 +31,4 @@ FillVars(_ENVVARS, vars()) FillVars(_DJANGO_ENVVARS, vars(), "DJANGO_") -ALLOWED_HOSTS = ADDRESSES +ALLOWED_HOSTS = ADDRESSES # noqa: F405 diff --git a/ietf/settings/docker/base.py b/ietf/settings/docker/base.py index d764d0bf..9cde3a0b 100644 --- a/ietf/settings/docker/base.py +++ b/ietf/settings/docker/base.py @@ -1,4 +1,3 @@ -from . import * - -from .grains.database import * -from .grains.logging import * +from . import * # noqa: F403 +from .grains.database import * # noqa: F403 +from .grains.logging import * # noqa: F403 diff --git a/ietf/settings/docker/dev.py b/ietf/settings/docker/dev.py index 99684588..8923e8be 100644 --- a/ietf/settings/docker/dev.py +++ b/ietf/settings/docker/dev.py @@ -1,4 +1,4 @@ -from .base import * +from .base import * # noqa: F403 DEBUG = True CACHE_MIDDLEWARE_ALIAS = "dummy" diff --git a/ietf/settings/production.py b/ietf/settings/production.py index ca495e2d..84ff4736 100644 --- a/ietf/settings/production.py +++ b/ietf/settings/production.py @@ -1,7 +1,7 @@ +import contextlib import os -import sys -from .base import * +from .base import * # noqa: F403 # Do not set SECRET_KEY, Postgres or LDAP password or any other sensitive data here. # Instead, create a local.py file on the server. @@ -17,58 +17,57 @@ # On Torchbox servers, many environment variables are prefixed with "CFG_" for key, value in os.environ.items(): - if key.startswith('CFG_'): + if key.startswith("CFG_"): env[key[4:]] = value # Basic configuration -APP_NAME = env.get('APP_NAME', 'ietf') +APP_NAME = env.get("APP_NAME", "ietf") -if 'SECRET_KEY' in env: - SECRET_KEY = env['SECRET_KEY'] +if "SECRET_KEY" in env: + SECRET_KEY = env["SECRET_KEY"] -if 'ALLOWED_HOSTS' in env: - ALLOWED_HOSTS = env['ALLOWED_HOSTS'].split(',') +if "ALLOWED_HOSTS" in env: + ALLOWED_HOSTS = env["ALLOWED_HOSTS"].split(",") -if 'CSRF_TRUSTED_ORIGINS' in env: - CSRF_TRUSTED_ORIGINS = env['CSRF_TRUSTED_ORIGINS'].split(',') +if "CSRF_TRUSTED_ORIGINS" in env: + CSRF_TRUSTED_ORIGINS = env["CSRF_TRUSTED_ORIGINS"].split(",") -if 'PRIMARY_HOST' in env: - WAGTAILADMIN_BASE_URL = 'http://%s/' % env['PRIMARY_HOST'] +if "PRIMARY_HOST" in env: + WAGTAILADMIN_BASE_URL = "http://{}/".format(env["PRIMARY_HOST"]) -if 'SERVER_EMAIL' in env: - SERVER_EMAIL = env['SERVER_EMAIL'] +if "SERVER_EMAIL" in env: + SERVER_EMAIL = env["SERVER_EMAIL"] -if 'CACHE_PURGE_URL' in env: - INSTALLED_APPS += ( 'wagtail.contrib.frontend_cache', ) +if "CACHE_PURGE_URL" in env: + INSTALLED_APPS += ("wagtail.contrib.frontend_cache",) # noqa: F405 WAGTAILFRONTENDCACHE = { - 'default': { - 'BACKEND': 'wagtail.contrib.frontend_cache.backends.HTTPBackend', - 'LOCATION': env['CACHE_PURGE_URL'], + "default": { + "BACKEND": "wagtail.contrib.frontend_cache.backends.HTTPBackend", + "LOCATION": env["CACHE_PURGE_URL"], }, } -if 'STATIC_URL' in env: - STATIC_URL = env['STATIC_URL'] +if "STATIC_URL" in env: + STATIC_URL = env["STATIC_URL"] -if 'STATIC_DIR' in env: - STATIC_ROOT = env['STATIC_DIR'] +if "STATIC_DIR" in env: + STATIC_ROOT = env["STATIC_DIR"] -if 'MEDIA_URL' in env: - MEDIA_URL = env['MEDIA_URL'] +if "MEDIA_URL" in env: + MEDIA_URL = env["MEDIA_URL"] -if 'MEDIA_DIR' in env: - MEDIA_ROOT = env['MEDIA_DIR'] +if "MEDIA_DIR" in env: + MEDIA_ROOT = env["MEDIA_DIR"] # Database DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': env.get('PGDATABASE', APP_NAME), - 'CONN_MAX_AGE': 600, # number of seconds database connections should persist for - + "default": { + "ENGINE": "django.db.backends.postgresql_psycopg2", + "NAME": env.get("PGDATABASE", APP_NAME), + "CONN_MAX_AGE": 600, # number of seconds database connections should persist for # User, host and port can be configured by the PGUSER, PGHOST and # PGPORT environment variables (these get picked up by libpq). } @@ -76,52 +75,50 @@ # Caches -if 'CACHE_DEFAULT' in env: - CACHES['default']['LOCATION'] = env.get('CACHE_DEFAULT') +if "CACHE_DEFAULT" in env: + CACHES["default"]["LOCATION"] = env.get("CACHE_DEFAULT") # noqa: F405 -if 'CACHE_SESSIONS' in env: - CACHES['sessions']['LOCATION'] = env.get('CACHE_SESSIONS') +if "CACHE_SESSIONS" in env: + CACHES["sessions"]["LOCATION"] = env.get("CACHE_SESSIONS") # noqa: F405 # Logging LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'handlers': { - 'mail_admins': { - 'level': 'ERROR', - 'class': 'django.utils.log.AdminEmailHandler', + "version": 1, + "disable_existing_loggers": False, + "handlers": { + "mail_admins": { + "level": "ERROR", + "class": "django.utils.log.AdminEmailHandler", }, }, - 'loggers': { - 'django.request': { - 'handlers': ['mail_admins'], - 'level': 'ERROR', - 'propagate': False, + "loggers": { + "django.request": { + "handlers": ["mail_admins"], + "level": "ERROR", + "propagate": False, }, - 'django.security': { - 'handlers': ['mail_admins'], - 'level': 'ERROR', - 'propagate': False, + "django.security": { + "handlers": ["mail_admins"], + "level": "ERROR", + "propagate": False, }, }, } # Log errors to file -if 'ERROR_LOG' in env: - LOGGING['handlers']['errors_file'] = { - 'level': 'ERROR', - 'class': 'logging.handlers.RotatingFileHandler', - 'filename': env['ERROR_LOG'], - 'maxBytes': 5242880, # 5MB - 'backupCount': 5 +if "ERROR_LOG" in env: + LOGGING["handlers"]["errors_file"] = { + "level": "ERROR", + "class": "logging.handlers.RotatingFileHandler", + "filename": env["ERROR_LOG"], + "maxBytes": 5242880, # 5MB + "backupCount": 5, } - LOGGING['loggers']['django.request']['handlers'].append('errors_file') - LOGGING['loggers']['django.security']['handlers'].append('errors_file') + LOGGING["loggers"]["django.request"]["handlers"].append("errors_file") + LOGGING["loggers"]["django.security"]["handlers"].append("errors_file") -try: - from .local import * # pyflakes:ignore -except ImportError: - pass +with contextlib.suppress(ImportError): + from .local import * # noqa: F403 diff --git a/ietf/snippets/migrations/0001_initial.py b/ietf/snippets/migrations/0001_initial.py index a5a4beb5..1b8f72bd 100644 --- a/ietf/snippets/migrations/0001_initial.py +++ b/ietf/snippets/migrations/0001_initial.py @@ -1,6 +1,4 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.11.29 on 2020-04-10 18:46 -from __future__ import unicode_literals import django.db.models.deletion import wagtail.fields diff --git a/ietf/snippets/migrations/0002_auto_20200414_2027.py b/ietf/snippets/migrations/0002_auto_20200414_2027.py index f4cc307a..cc9c8f6a 100644 --- a/ietf/snippets/migrations/0002_auto_20200414_2027.py +++ b/ietf/snippets/migrations/0002_auto_20200414_2027.py @@ -1,31 +1,50 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.11.29 on 2020-04-14 20:27 -from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('snippets', '0001_initial'), + ("snippets", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='group', - name='image', - field=models.ForeignKey(blank=True, help_text='An image to represent this group.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage'), + model_name="group", + name="image", + field=models.ForeignKey( + blank=True, + help_text="An image to represent this group.", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="images.IETFImage", + ), ), migrations.AlterField( - 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.SET_NULL, 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.SET_NULL, + related_name="+", + to="snippets.Role", + ), ), migrations.AlterField( - 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.SET_NULL, 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.SET_NULL, + related_name="+", + to="snippets.WorkingGroup", + ), ), ] diff --git a/ietf/snippets/migrations/0003_alter_workinggroup_list_subscribe.py b/ietf/snippets/migrations/0003_alter_workinggroup_list_subscribe.py index 8fe4e083..3ea9c610 100644 --- a/ietf/snippets/migrations/0003_alter_workinggroup_list_subscribe.py +++ b/ietf/snippets/migrations/0003_alter_workinggroup_list_subscribe.py @@ -6,13 +6,13 @@ class Migration(migrations.Migration): dependencies = [ - ('snippets', '0002_auto_20200414_2027'), + ("snippets", "0002_auto_20200414_2027"), ] operations = [ migrations.AlterField( - model_name='workinggroup', - name='list_subscribe', + model_name="workinggroup", + name="list_subscribe", field=models.URLField(blank=True), ), ] diff --git a/ietf/snippets/migrations/0003_person_slug.py b/ietf/snippets/migrations/0003_person_slug.py index 2185cee4..076bbf5c 100644 --- a/ietf/snippets/migrations/0003_person_slug.py +++ b/ietf/snippets/migrations/0003_person_slug.py @@ -14,14 +14,14 @@ def generate_person_slugs(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ('snippets', '0002_auto_20200414_2027'), + ("snippets", "0002_auto_20200414_2027"), ] operations = [ migrations.AddField( - model_name='person', - name='slug', - field=models.SlugField(default='', max_length=511), + model_name="person", + name="slug", + field=models.SlugField(default="", max_length=511), preserve_default=False, ), migrations.RunPython(generate_person_slugs, migrations.RunPython.noop), diff --git a/ietf/snippets/migrations/0004_merge_20231215_0352.py b/ietf/snippets/migrations/0004_merge_20231215_0352.py index 4c423377..e7c180df 100644 --- a/ietf/snippets/migrations/0004_merge_20231215_0352.py +++ b/ietf/snippets/migrations/0004_merge_20231215_0352.py @@ -6,14 +6,14 @@ class Migration(migrations.Migration): dependencies = [ - ('snippets', '0003_alter_workinggroup_list_subscribe'), - ('snippets', '0003_person_slug'), + ("snippets", "0003_alter_workinggroup_list_subscribe"), + ("snippets", "0003_person_slug"), ] operations = [ migrations.AlterField( - model_name='person', - name='slug', + model_name="person", + name="slug", field=models.SlugField(max_length=511, unique=True), ), ] diff --git a/ietf/snippets/models.py b/ietf/snippets/models.py index 8114bfe8..3bacf85e 100644 --- a/ietf/snippets/models.py +++ b/ietf/snippets/models.py @@ -119,7 +119,7 @@ class RFC(models.Model, index.Indexed): ] def __str__(self): # pragma: no cover - return "RFC {}".format(self.rfc) + return f"RFC {self.rfc}" @property def long_title(self): @@ -323,13 +323,10 @@ class MailingListSignup(models.Model, Indexed, RenderableSnippetMixin): @property def link(self): - if self.sign_up: - link = self.sign_up - else: - link = self.working_group.list_subscribe + link = self.sign_up if self.sign_up else self.working_group.list_subscribe if "@" in link: - return "mailto:{}".format(link) + return f"mailto:{link}" else: return link @@ -430,7 +427,7 @@ def __str__(self): # pragma: no cover def url(self): from ietf.glossary.models import GlossaryPage - return "{}?query={}".format(GlossaryPage.objects.first().url, self.title) + return f"{GlossaryPage.objects.first().url}?query={self.title}" class Meta: ordering = ["title"] diff --git a/ietf/snippets/tests/test_charter.py b/ietf/snippets/tests/test_charter.py index 1a73e277..8e59aad2 100644 --- a/ietf/snippets/tests/test_charter.py +++ b/ietf/snippets/tests/test_charter.py @@ -1,4 +1,5 @@ import pytest + from ietf.snippets.factories import CharterFactory, WorkingGroupFactory pytestmark = pytest.mark.django_db diff --git a/ietf/snippets/tests/test_mailing_list_signup.py b/ietf/snippets/tests/test_mailing_list_signup.py index 27cf1f56..8f615e98 100644 --- a/ietf/snippets/tests/test_mailing_list_signup.py +++ b/ietf/snippets/tests/test_mailing_list_signup.py @@ -1,11 +1,11 @@ -from bs4 import BeautifulSoup -from django.urls import reverse import pytest +from bs4 import BeautifulSoup from django.test import Client +from django.urls import reverse from ietf.home.models import HomePage -from ietf.standard.factories import StandardPageFactory from ietf.snippets.factories import MailingListSignupFactory, WorkingGroupFactory +from ietf.standard.factories import StandardPageFactory pytestmark = pytest.mark.django_db diff --git a/ietf/snippets/urls.py b/ietf/snippets/urls.py index 1e2d4824..c7bd7565 100644 --- a/ietf/snippets/urls.py +++ b/ietf/snippets/urls.py @@ -2,7 +2,6 @@ from .views import disclaimer - urlpatterns = [ - re_path(r'^disclaimer/(\d+)/$', disclaimer, name='disclaimer'), - ] + re_path(r"^disclaimer/(\d+)/$", disclaimer, name="disclaimer"), +] diff --git a/ietf/snippets/views.py b/ietf/snippets/views.py index 1adc2d07..a3b9bc66 100644 --- a/ietf/snippets/views.py +++ b/ietf/snippets/views.py @@ -1,5 +1,5 @@ -from django.shortcuts import get_object_or_404, render from django.conf import settings +from django.shortcuts import get_object_or_404, render from .models import MailingListSignup diff --git a/ietf/standard/migrations/0001_initial.py b/ietf/standard/migrations/0001_initial.py index d276a7ee..31e7eed2 100644 --- a/ietf/standard/migrations/0001_initial.py +++ b/ietf/standard/migrations/0001_initial.py @@ -1,6 +1,4 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.11.29 on 2020-04-10 18:46 -from __future__ import unicode_literals import django.db.models.deletion import modelcluster.fields diff --git a/ietf/standard/migrations/0004_auto_20220902_0524.py b/ietf/standard/migrations/0004_auto_20220902_0524.py index bfc31686..d913adc8 100644 --- a/ietf/standard/migrations/0004_auto_20220902_0524.py +++ b/ietf/standard/migrations/0004_auto_20220902_0524.py @@ -1,39 +1,131 @@ # 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 +from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('standard', '0003_auto_20211101_0113'), + ("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), + 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), + 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), + 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), + 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/migrations/0005_iabstandardpage.py b/ietf/standard/migrations/0005_iabstandardpage.py index ea8719c9..87eefe8d 100644 --- a/ietf/standard/migrations/0005_iabstandardpage.py +++ b/ietf/standard/migrations/0005_iabstandardpage.py @@ -1,6 +1,5 @@ # Generated by Django 3.2.13 on 2023-02-27 20:53 -from django.db import migrations, models import django.db.models.deletion import wagtail.blocks import wagtail.contrib.table_block.blocks @@ -8,36 +7,178 @@ import wagtail.fields import wagtail.images.blocks import wagtailmarkdown.blocks +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('snippets', '0002_auto_20200414_2027'), - ('wagtailcore', '0078_referenceindex'), - ('images', '0002_alter_ietfimage_file_hash'), - ('standard', '0004_auto_20220902_0524'), + ("snippets", "0002_auto_20200414_2027"), + ("wagtailcore", "0078_referenceindex"), + ("images", "0002_alter_ietfimage_file_hash"), + ("standard", "0004_auto_20220902_0524"), ] operations = [ migrations.CreateModel( - name='IABStandardPage', + name="IABStandardPage", 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.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)), - ('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')), ('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)), - ('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" + ), + ), + ( + "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, + ), + ), + ( + "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" + ), + ), + ( + "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, + ), + ), + ( + "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={ - 'verbose_name': 'IAB Standard Page', + "verbose_name": "IAB Standard Page", }, - bases=('wagtailcore.page', models.Model), + bases=("wagtailcore.page", models.Model), ), ] diff --git a/ietf/standard/migrations/0009_alter_iabstandardpage_in_depth_and_more.py b/ietf/standard/migrations/0009_alter_iabstandardpage_in_depth_and_more.py index d1f32eac..0c345d99 100644 --- a/ietf/standard/migrations/0009_alter_iabstandardpage_in_depth_and_more.py +++ b/ietf/standard/migrations/0009_alter_iabstandardpage_in_depth_and_more.py @@ -1,6 +1,5 @@ # Generated by Django 4.2.7 on 2024-04-03 13:40 -from django.db import migrations import wagtail.blocks import wagtail.contrib.table_block.blocks import wagtail.contrib.typed_table_block.blocks @@ -8,43 +7,368 @@ import wagtail.fields import wagtail.images.blocks import wagtailmarkdown.blocks +from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('standard', '0008_auto_20230414_0340'), + ("standard", "0008_auto_20230414_0340"), ] operations = [ migrations.AlterField( - model_name='iabstandardpage', - 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')), ('typed_table', wagtail.contrib.typed_table_block.blocks.TypedTableBlock([('text', wagtail.blocks.CharBlock(required=False)), ('numeric', wagtail.blocks.FloatBlock(required=False, template='blocks/float_block.html')), ('rich_text', wagtail.blocks.RichTextBlock(required=False)), ('image', wagtail.images.blocks.ImageChooserBlock(required=False))])), ('note_well', wagtail.blocks.StructBlock([], icon='placeholder', label='Note Well Text'))], blank=True, use_json_field=True), + model_name="iabstandardpage", + 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", + ), + ), + ( + "typed_table", + wagtail.contrib.typed_table_block.blocks.TypedTableBlock( + [ + ("text", wagtail.blocks.CharBlock(required=False)), + ( + "numeric", + wagtail.blocks.FloatBlock( + required=False, + template="blocks/float_block.html", + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock(required=False), + ), + ( + "image", + wagtail.images.blocks.ImageChooserBlock( + required=False + ), + ), + ] + ), + ), + ( + "note_well", + wagtail.blocks.StructBlock( + [], icon="placeholder", label="Note Well Text" + ), + ), + ], + blank=True, + use_json_field=True, + ), ), migrations.AlterField( - model_name='iabstandardpage', - 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')), ('typed_table', wagtail.contrib.typed_table_block.blocks.TypedTableBlock([('text', wagtail.blocks.CharBlock(required=False)), ('numeric', wagtail.blocks.FloatBlock(required=False, template='blocks/float_block.html')), ('rich_text', wagtail.blocks.RichTextBlock(required=False)), ('image', wagtail.images.blocks.ImageChooserBlock(required=False))])), ('note_well', wagtail.blocks.StructBlock([], icon='placeholder', label='Note Well Text'))], blank=True, use_json_field=True), + model_name="iabstandardpage", + 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", + ), + ), + ( + "typed_table", + wagtail.contrib.typed_table_block.blocks.TypedTableBlock( + [ + ("text", wagtail.blocks.CharBlock(required=False)), + ( + "numeric", + wagtail.blocks.FloatBlock( + required=False, + template="blocks/float_block.html", + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock(required=False), + ), + ( + "image", + wagtail.images.blocks.ImageChooserBlock( + required=False + ), + ), + ] + ), + ), + ( + "note_well", + wagtail.blocks.StructBlock( + [], icon="placeholder", label="Note Well Text" + ), + ), + ], + blank=True, + use_json_field=True, + ), ), 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')), ('typed_table', wagtail.contrib.typed_table_block.blocks.TypedTableBlock([('text', wagtail.blocks.CharBlock(required=False)), ('numeric', wagtail.blocks.FloatBlock(required=False, template='blocks/float_block.html')), ('rich_text', wagtail.blocks.RichTextBlock(required=False)), ('image', wagtail.images.blocks.ImageChooserBlock(required=False))])), ('note_well', wagtail.blocks.StructBlock([], icon='placeholder', label='Note Well Text'))], blank=True, use_json_field=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", + ), + ), + ( + "typed_table", + wagtail.contrib.typed_table_block.blocks.TypedTableBlock( + [ + ("text", wagtail.blocks.CharBlock(required=False)), + ( + "numeric", + wagtail.blocks.FloatBlock( + required=False, + template="blocks/float_block.html", + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock(required=False), + ), + ( + "image", + wagtail.images.blocks.ImageChooserBlock( + required=False + ), + ), + ] + ), + ), + ( + "note_well", + wagtail.blocks.StructBlock( + [], icon="placeholder", label="Note Well Text" + ), + ), + ], + 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')), ('typed_table', wagtail.contrib.typed_table_block.blocks.TypedTableBlock([('text', wagtail.blocks.CharBlock(required=False)), ('numeric', wagtail.blocks.FloatBlock(required=False, template='blocks/float_block.html')), ('rich_text', wagtail.blocks.RichTextBlock(required=False)), ('image', wagtail.images.blocks.ImageChooserBlock(required=False))])), ('note_well', wagtail.blocks.StructBlock([], icon='placeholder', label='Note Well Text'))], blank=True, use_json_field=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", + ), + ), + ( + "typed_table", + wagtail.contrib.typed_table_block.blocks.TypedTableBlock( + [ + ("text", wagtail.blocks.CharBlock(required=False)), + ( + "numeric", + wagtail.blocks.FloatBlock( + required=False, + template="blocks/float_block.html", + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock(required=False), + ), + ( + "image", + wagtail.images.blocks.ImageChooserBlock( + required=False + ), + ), + ] + ), + ), + ( + "note_well", + wagtail.blocks.StructBlock( + [], icon="placeholder", label="Note Well Text" + ), + ), + ], + 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')), ('typed_table', wagtail.contrib.typed_table_block.blocks.TypedTableBlock([('text', wagtail.blocks.CharBlock(required=False)), ('numeric', wagtail.blocks.FloatBlock(required=False, template='blocks/float_block.html')), ('rich_text', wagtail.blocks.RichTextBlock(required=False)), ('image', wagtail.images.blocks.ImageChooserBlock(required=False))])), ('note_well', wagtail.blocks.StructBlock([], icon='placeholder', label='Note Well Text'))], blank=True, use_json_field=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", + ), + ), + ( + "typed_table", + wagtail.contrib.typed_table_block.blocks.TypedTableBlock( + [ + ("text", wagtail.blocks.CharBlock(required=False)), + ( + "numeric", + wagtail.blocks.FloatBlock( + required=False, + template="blocks/float_block.html", + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock(required=False), + ), + ( + "image", + wagtail.images.blocks.ImageChooserBlock( + required=False + ), + ), + ] + ), + ), + ( + "note_well", + wagtail.blocks.StructBlock( + [], icon="placeholder", label="Note Well Text" + ), + ), + ], + 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')), ('typed_table', wagtail.contrib.typed_table_block.blocks.TypedTableBlock([('text', wagtail.blocks.CharBlock(required=False)), ('numeric', wagtail.blocks.FloatBlock(required=False, template='blocks/float_block.html')), ('rich_text', wagtail.blocks.RichTextBlock(required=False)), ('image', wagtail.images.blocks.ImageChooserBlock(required=False))])), ('note_well', wagtail.blocks.StructBlock([], icon='placeholder', label='Note Well Text'))], blank=True, use_json_field=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", + ), + ), + ( + "typed_table", + wagtail.contrib.typed_table_block.blocks.TypedTableBlock( + [ + ("text", wagtail.blocks.CharBlock(required=False)), + ( + "numeric", + wagtail.blocks.FloatBlock( + required=False, + template="blocks/float_block.html", + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock(required=False), + ), + ( + "image", + wagtail.images.blocks.ImageChooserBlock( + required=False + ), + ), + ] + ), + ), + ( + "note_well", + wagtail.blocks.StructBlock( + [], icon="placeholder", label="Note Well Text" + ), + ), + ], + blank=True, + use_json_field=True, + ), ), ] diff --git a/ietf/standard/templatetags/has_tabs.py b/ietf/standard/templatetags/has_tabs.py index 9ec07130..3009697d 100644 --- a/ietf/standard/templatetags/has_tabs.py +++ b/ietf/standard/templatetags/has_tabs.py @@ -2,6 +2,7 @@ register = template.Library() + @register.simple_tag def has_tabs(key_info, in_depth): - return True if key_info and in_depth else False + return bool(key_info and in_depth) diff --git a/ietf/standard/tests.py b/ietf/standard/tests.py index 8152fe2b..f09b8ecd 100644 --- a/ietf/standard/tests.py +++ b/ietf/standard/tests.py @@ -1,8 +1,13 @@ -from django.test import Client import pytest +from django.test import Client from ietf.home.models import HomePage, IABHomePage -from .factories import IABStandardPageFactory, StandardIndexPageFactory, StandardPageFactory + +from .factories import ( + IABStandardPageFactory, + StandardIndexPageFactory, + StandardPageFactory, +) from .models import IABStandardPage, StandardIndexPage, StandardPage pytestmark = pytest.mark.django_db diff --git a/ietf/topics/factories.py b/ietf/topics/factories.py index bf9ffded..83f9d0b2 100644 --- a/ietf/topics/factories.py +++ b/ietf/topics/factories.py @@ -1,7 +1,7 @@ import factory import wagtail_factories -from .models import TopicIndexPage, PrimaryTopicPage +from .models import PrimaryTopicPage, TopicIndexPage class PrimaryTopicPageFactory(wagtail_factories.PageFactory): diff --git a/ietf/topics/migrations/0001_initial.py b/ietf/topics/migrations/0001_initial.py index e67fd6fc..5e7091a2 100644 --- a/ietf/topics/migrations/0001_initial.py +++ b/ietf/topics/migrations/0001_initial.py @@ -1,6 +1,4 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.11.29 on 2020-04-10 18:46 -from __future__ import unicode_literals import django.db.models.deletion import modelcluster.fields diff --git a/ietf/topics/migrations/0004_auto_20220902_0524.py b/ietf/topics/migrations/0004_auto_20220902_0524.py index 4e792178..b491ebf6 100644 --- a/ietf/topics/migrations/0004_auto_20220902_0524.py +++ b/ietf/topics/migrations/0004_auto_20220902_0524.py @@ -1,29 +1,75 @@ # 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 +from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('topics', '0003_auto_20211101_0113'), + ("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), + 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), + 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/migrations/0008_alter_primarytopicpage_in_depth_and_more.py b/ietf/topics/migrations/0008_alter_primarytopicpage_in_depth_and_more.py index a9c724e8..ec147a1f 100644 --- a/ietf/topics/migrations/0008_alter_primarytopicpage_in_depth_and_more.py +++ b/ietf/topics/migrations/0008_alter_primarytopicpage_in_depth_and_more.py @@ -1,6 +1,5 @@ # Generated by Django 4.2.7 on 2024-04-03 13:40 -from django.db import migrations import wagtail.blocks import wagtail.contrib.table_block.blocks import wagtail.contrib.typed_table_block.blocks @@ -8,23 +7,132 @@ import wagtail.fields import wagtail.images.blocks import wagtailmarkdown.blocks +from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('topics', '0007_auto_20230414_0340'), + ("topics", "0007_auto_20230414_0340"), ] 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')), ('typed_table', wagtail.contrib.typed_table_block.blocks.TypedTableBlock([('text', wagtail.blocks.CharBlock(required=False)), ('numeric', wagtail.blocks.FloatBlock(required=False, template='blocks/float_block.html')), ('rich_text', wagtail.blocks.RichTextBlock(required=False)), ('image', wagtail.images.blocks.ImageChooserBlock(required=False))])), ('note_well', wagtail.blocks.StructBlock([], icon='placeholder', label='Note Well Text'))], blank=True, use_json_field=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", + ), + ), + ( + "typed_table", + wagtail.contrib.typed_table_block.blocks.TypedTableBlock( + [ + ("text", wagtail.blocks.CharBlock(required=False)), + ( + "numeric", + wagtail.blocks.FloatBlock( + required=False, + template="blocks/float_block.html", + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock(required=False), + ), + ( + "image", + wagtail.images.blocks.ImageChooserBlock( + required=False + ), + ), + ] + ), + ), + ( + "note_well", + wagtail.blocks.StructBlock( + [], icon="placeholder", label="Note Well Text" + ), + ), + ], + 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')), ('typed_table', wagtail.contrib.typed_table_block.blocks.TypedTableBlock([('text', wagtail.blocks.CharBlock(required=False)), ('numeric', wagtail.blocks.FloatBlock(required=False, template='blocks/float_block.html')), ('rich_text', wagtail.blocks.RichTextBlock(required=False)), ('image', wagtail.images.blocks.ImageChooserBlock(required=False))])), ('note_well', wagtail.blocks.StructBlock([], icon='placeholder', label='Note Well Text'))], blank=True, use_json_field=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", + ), + ), + ( + "typed_table", + wagtail.contrib.typed_table_block.blocks.TypedTableBlock( + [ + ("text", wagtail.blocks.CharBlock(required=False)), + ( + "numeric", + wagtail.blocks.FloatBlock( + required=False, + template="blocks/float_block.html", + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock(required=False), + ), + ( + "image", + wagtail.images.blocks.ImageChooserBlock( + required=False + ), + ), + ] + ), + ), + ( + "note_well", + wagtail.blocks.StructBlock( + [], icon="placeholder", label="Note Well Text" + ), + ), + ], + blank=True, + use_json_field=True, + ), ), ] diff --git a/ietf/topics/models.py b/ietf/topics/models.py index 9ea68381..bea2546f 100644 --- a/ietf/topics/models.py +++ b/ietf/topics/models.py @@ -62,8 +62,12 @@ class PrimaryTopicPage(Page, PromoteMixin): max_length=255, help_text="Enter the title to display on the page, you can use only 255 characters.", ) - key_info = StreamField(StandardBlock(required=False), blank=True, use_json_field=True) - in_depth = StreamField(StandardBlock(required=False), blank=True, use_json_field=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, diff --git a/ietf/topics/test.py b/ietf/topics/test.py index d8ccea12..ed337f46 100644 --- a/ietf/topics/test.py +++ b/ietf/topics/test.py @@ -2,6 +2,7 @@ from django.test import Client from ietf.home.models import HomePage + from .factories import PrimaryTopicPageFactory, TopicIndexPageFactory from .models import PrimaryTopicPage, TopicIndexPage diff --git a/ietf/utils/apps.py b/ietf/utils/apps.py index b01340df..40788f4c 100644 --- a/ietf/utils/apps.py +++ b/ietf/utils/apps.py @@ -2,7 +2,7 @@ class UtilsAppConfig(AppConfig): - name = 'ietf.utils' + name = "ietf.utils" verbose_name = "IETF Website Utils" def ready(self): diff --git a/ietf/utils/blocks.py b/ietf/utils/blocks.py index 2c12ac43..ee60825d 100644 --- a/ietf/utils/blocks.py +++ b/ietf/utils/blocks.py @@ -1,3 +1,4 @@ +from django.conf import settings from django.utils.functional import cached_property from wagtail.blocks import ( CharBlock, @@ -17,13 +18,11 @@ from wagtail.images.blocks import ImageChooserBlock from wagtailmarkdown.blocks import MarkdownBlock -from django.conf import settings - class NoteWellBlock(StructBlock): def get_context(self, value): context = super().get_context(value) - context['note_well_git_url'] = settings.NOTE_WELL_REPO + context["note_well_git_url"] = settings.NOTE_WELL_REPO return context class Meta: diff --git a/ietf/utils/context_processors.py b/ietf/utils/context_processors.py index 3b200206..f985ff10 100644 --- a/ietf/utils/context_processors.py +++ b/ietf/utils/context_processors.py @@ -90,8 +90,7 @@ def get_footer(): def get_preview_footer(current): items = [ - current if item == current else item - for item in FooterColumn.objects.all() + current if item == current else item for item in FooterColumn.objects.all() ] if not current.pk: items.append(current) diff --git a/ietf/utils/migrations/0001_initial.py b/ietf/utils/migrations/0001_initial.py index 0bf9e9b5..6a7b08ac 100644 --- a/ietf/utils/migrations/0001_initial.py +++ b/ietf/utils/migrations/0001_initial.py @@ -1,10 +1,8 @@ -# -*- coding: utf-8 -*- # 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 +from django.db import migrations, models class Migration(migrations.Migration): @@ -12,94 +10,272 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('images', '0001_initial'), - ('wagtaildocs', '0008_document_file_size'), - ('wagtailcore', '0040_page_draft_title'), + ("images", "0001_initial"), + ("wagtaildocs", "0008_document_file_size"), + ("wagtailcore", "0040_page_draft_title"), ] operations = [ migrations.CreateModel( - name='FeedSettings', + name="FeedSettings", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('blog_feed_title', models.CharField(blank=True, max_length=255)), - ('blog_feed_description', models.CharField(blank=True, max_length=255)), - ('site', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, to='wagtailcore.Site')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("blog_feed_title", models.CharField(blank=True, max_length=255)), + ("blog_feed_description", models.CharField(blank=True, max_length=255)), + ( + "site", + models.OneToOneField( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + to="wagtailcore.Site", + ), + ), ], options={ - 'verbose_name': 'Feeds', + "verbose_name": "Feeds", }, ), migrations.CreateModel( - name='FooterLinkItem', + name="FooterLinkItem", 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(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", + ), + ), + ( + "sort_order", + models.IntegerField(blank=True, editable=False, null=True), + ), + ( + "link_external", + models.URLField(blank=True, verbose_name="External link"), + ), + ("title", models.CharField(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={ - 'ordering': ['sort_order'], - 'abstract': False, + "ordering": ["sort_order"], + "abstract": False, }, ), migrations.CreateModel( - name='FooterLinks', + name="FooterLinks", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('site', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, to='wagtailcore.Site')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "site", + models.OneToOneField( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + to="wagtailcore.Site", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='SecondaryMenu', + name="SecondaryMenu", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('contact_page', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailcore.Page')), - ('site', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, to='wagtailcore.Site')), - ('tools_page', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailcore.Page')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "contact_page", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailcore.Page", + ), + ), + ( + "site", + models.OneToOneField( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + to="wagtailcore.Site", + ), + ), + ( + "tools_page", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailcore.Page", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='SocialMediaSettings', + name="SocialMediaSettings", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('twitter_handle', models.CharField(blank='True', help_text='Your Twitter username without the @, e.g. flickr', max_length=255)), - ('facebook_app_id', models.CharField(blank='True', help_text='Your Facebook app id', max_length=255)), - ('default_sharing_text', models.CharField(blank='True', help_text='Default sharing text to use if social text has not been set on a page.', max_length=255)), - ('site_name', models.CharField(blank='True', default='ietf', help_text='Site name, used by facebook open graph.', max_length=255)), - ('default_sharing_image', models.ForeignKey(blank=True, help_text='Default sharing image to use if social image has not been set on a page.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.IETFImage')), - ('site', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, to='wagtailcore.Site')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "twitter_handle", + models.CharField( + blank="True", + help_text="Your Twitter username without the @, e.g. flickr", + max_length=255, + ), + ), + ( + "facebook_app_id", + models.CharField( + blank="True", help_text="Your Facebook app id", max_length=255 + ), + ), + ( + "default_sharing_text", + models.CharField( + blank="True", + help_text="Default sharing text to use if social text has not been set on a page.", + max_length=255, + ), + ), + ( + "site_name", + models.CharField( + blank="True", + default="ietf", + help_text="Site name, used by facebook open graph.", + max_length=255, + ), + ), + ( + "default_sharing_image", + models.ForeignKey( + blank=True, + help_text="Default sharing image to use if social image has not been set on a page.", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="images.IETFImage", + ), + ), + ( + "site", + models.OneToOneField( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + to="wagtailcore.Site", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='ToolsMenuItem', + name="ToolsMenuItem", 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', models.URLField(blank=True)), - ('text', models.CharField(blank=True, max_length=255)), - ('model', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='tools_menu_items', to='utils.SecondaryMenu')), - ('page', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailcore.Page')), + ( + "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", models.URLField(blank=True)), + ("text", models.CharField(blank=True, max_length=255)), + ( + "model", + modelcluster.fields.ParentalKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="tools_menu_items", + to="utils.SecondaryMenu", + ), + ), + ( + "page", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailcore.Page", + ), + ), ], options={ - 'ordering': ['sort_order'], - 'abstract': False, + "ordering": ["sort_order"], + "abstract": False, }, ), migrations.AddField( - model_name='footerlinkitem', - name='model', - field=modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='footer_link_items', to='utils.FooterLinks'), + model_name="footerlinkitem", + name="model", + field=modelcluster.fields.ParentalKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="footer_link_items", + to="utils.FooterLinks", + ), ), ] diff --git a/ietf/utils/migrations/0002_auto_20211101_0113.py b/ietf/utils/migrations/0002_auto_20211101_0113.py index 25816526..fb9a1914 100644 --- a/ietf/utils/migrations/0002_auto_20211101_0113.py +++ b/ietf/utils/migrations/0002_auto_20211101_0113.py @@ -1,15 +1,15 @@ # Generated by Django 2.2.19 on 2021-11-01 01:13 -from django.db import migrations, models import django.db.models.deletion import modelcluster.fields +from django.db import migrations, models def migrate_data(apps, schema_editor): - SecondaryMenu = apps.get_model('utils', 'SecondaryMenu') - ToolsMenuItem = apps.get_model('utils', 'ToolsMenuItem') - MenuItem = apps.get_model('utils', 'MenuItem') - SubMenuItem = apps.get_model('utils', 'SubMenuItem') + SecondaryMenu = apps.get_model("utils", "SecondaryMenu") + ToolsMenuItem = apps.get_model("utils", "ToolsMenuItem") + MenuItem = apps.get_model("utils", "MenuItem") + SubMenuItem = apps.get_model("utils", "SubMenuItem") menu = SecondaryMenu.objects.first() if menu is not None: contact_menu = MenuItem(page=menu.contact_page, sort_order=1) @@ -18,58 +18,107 @@ def migrate_data(apps, schema_editor): tools_menu.save() for item in ToolsMenuItem.objects.all(): - sub_menu = SubMenuItem(parent=tools_menu, page=item.page, link=item.link, text=item.text) + sub_menu = SubMenuItem( + parent=tools_menu, page=item.page, link=item.link, text=item.text + ) sub_menu.save() class Migration(migrations.Migration): dependencies = [ - ('wagtailcore', '0059_apply_collection_ordering'), - ('utils', '0001_initial'), + ("wagtailcore", "0059_apply_collection_ordering"), + ("utils", "0001_initial"), ] operations = [ migrations.CreateModel( - name='MenuItem', + name="MenuItem", 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)), - ('text', models.CharField(blank=True, max_length=40)), - ('page', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailcore.Page')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "sort_order", + models.IntegerField(blank=True, editable=False, null=True), + ), + ("text", models.CharField(blank=True, max_length=40)), + ( + "page", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailcore.Page", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='SubMenuItem', + name="SubMenuItem", 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', models.URLField(blank=True)), - ('text', models.CharField(blank=True, max_length=40)), - ('page', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailcore.Page')), - ('parent', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='sub_menu_items', to='utils.MenuItem')), + ( + "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", models.URLField(blank=True)), + ("text", models.CharField(blank=True, max_length=40)), + ( + "page", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailcore.Page", + ), + ), + ( + "parent", + modelcluster.fields.ParentalKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="sub_menu_items", + to="utils.MenuItem", + ), + ), ], options={ - 'ordering': ['sort_order'], - 'abstract': False, + "ordering": ["sort_order"], + "abstract": False, }, ), migrations.RunPython(migrate_data), migrations.RemoveField( - model_name='toolsmenuitem', - name='model', + model_name="toolsmenuitem", + name="model", ), migrations.RemoveField( - model_name='toolsmenuitem', - name='page', + model_name="toolsmenuitem", + name="page", ), migrations.DeleteModel( - name='SecondaryMenu', + name="SecondaryMenu", ), migrations.DeleteModel( - name='ToolsMenuItem', + name="ToolsMenuItem", ), ] diff --git a/ietf/utils/migrations/0003_auto_20211105_0019.py b/ietf/utils/migrations/0003_auto_20211105_0019.py index 142b458b..586a7c7f 100644 --- a/ietf/utils/migrations/0003_auto_20211105_0019.py +++ b/ietf/utils/migrations/0003_auto_20211105_0019.py @@ -1,24 +1,24 @@ # Generated by Django 2.2.19 on 2021-11-05 00:19 -from django.db import migrations, models +from django.db import migrations + def add_missing_menu(apps, schema_editor): - MenuItem = apps.get_model('utils', 'MenuItem') - Page = apps.get_model('wagtailcore', 'Page') + MenuItem = apps.get_model("utils", "MenuItem") + Page = apps.get_model("wagtailcore", "Page") page = Page.objects.filter(pk=42).first() if page: - MenuItem.objects.create(page=page, sort_order=0, text='News & blog') + MenuItem.objects.create(page=page, sort_order=0, text="News & blog") tools_menu = MenuItem.objects.filter(page__title="Links").first() if tools_menu: tools_menu.text = "Tools" tools_menu.save() + class Migration(migrations.Migration): dependencies = [ - ('utils', '0002_auto_20211101_0113'), + ("utils", "0002_auto_20211101_0113"), ] - operations = [ - migrations.RunPython(add_missing_menu) - ] + operations = [migrations.RunPython(add_missing_menu)] diff --git a/ietf/utils/migrations/0004_alter_menuitem_options.py b/ietf/utils/migrations/0004_alter_menuitem_options.py index d294177f..39ee4cdb 100644 --- a/ietf/utils/migrations/0004_alter_menuitem_options.py +++ b/ietf/utils/migrations/0004_alter_menuitem_options.py @@ -6,12 +6,12 @@ class Migration(migrations.Migration): dependencies = [ - ('utils', '0003_auto_20211105_0019'), + ("utils", "0003_auto_20211105_0019"), ] operations = [ migrations.AlterModelOptions( - name='menuitem', - options={'verbose_name_plural': 'Secondary Menu'}, + name="menuitem", + options={"verbose_name_plural": "Secondary Menu"}, ), ] diff --git a/ietf/utils/migrations/0007_auto_20230524_0551.py b/ietf/utils/migrations/0007_auto_20230524_0551.py index e748a99b..c3651b03 100644 --- a/ietf/utils/migrations/0007_auto_20230524_0551.py +++ b/ietf/utils/migrations/0007_auto_20230524_0551.py @@ -6,28 +6,48 @@ class Migration(migrations.Migration): dependencies = [ - ('utils', '0006_textchunk'), + ("utils", "0006_textchunk"), ] operations = [ migrations.AddField( - model_name='socialmediasettings', - name='linkedin', - field=models.CharField(blank='True', help_text='Link to linkedin profile', max_length=255, verbose_name='LinkedIn link'), + model_name="socialmediasettings", + name="linkedin", + field=models.CharField( + blank="True", + help_text="Link to linkedin profile", + max_length=255, + verbose_name="LinkedIn link", + ), ), migrations.AddField( - model_name='socialmediasettings', - name='mastodon', - field=models.CharField(blank='True', help_text='Link to mastodon profile', max_length=255, verbose_name='Mastodon link'), + model_name="socialmediasettings", + name="mastodon", + field=models.CharField( + blank="True", + help_text="Link to mastodon profile", + max_length=255, + verbose_name="Mastodon link", + ), ), migrations.AddField( - model_name='socialmediasettings', - name='twitter', - field=models.CharField(blank='True', help_text='Link to twitter profile', max_length=255, verbose_name='Twitter link'), + model_name="socialmediasettings", + name="twitter", + field=models.CharField( + blank="True", + help_text="Link to twitter profile", + max_length=255, + verbose_name="Twitter link", + ), ), migrations.AddField( - model_name='socialmediasettings', - name='youtube', - field=models.CharField(blank='True', help_text='Link to youtube account', max_length=255, verbose_name='Youtube link'), + model_name="socialmediasettings", + name="youtube", + field=models.CharField( + blank="True", + help_text="Link to youtube account", + max_length=255, + verbose_name="Youtube link", + ), ), ] diff --git a/ietf/utils/migrations/0008_socialmediasettings_github_and_more.py b/ietf/utils/migrations/0008_socialmediasettings_github_and_more.py index c0445784..a6cb1d40 100644 --- a/ietf/utils/migrations/0008_socialmediasettings_github_and_more.py +++ b/ietf/utils/migrations/0008_socialmediasettings_github_and_more.py @@ -6,33 +6,58 @@ class Migration(migrations.Migration): dependencies = [ - ('utils', '0007_auto_20230524_0551'), + ("utils", "0007_auto_20230524_0551"), ] operations = [ migrations.AddField( - model_name='socialmediasettings', - name='github', - field=models.CharField(blank='True', help_text='Link to GitHub profile', max_length=255, verbose_name='GitHub link'), + model_name="socialmediasettings", + name="github", + field=models.CharField( + blank="True", + help_text="Link to GitHub profile", + max_length=255, + verbose_name="GitHub link", + ), ), migrations.AlterField( - model_name='socialmediasettings', - name='linkedin', - field=models.CharField(blank='True', help_text='Link to LinkedIn profile', max_length=255, verbose_name='LinkedIn link'), + model_name="socialmediasettings", + name="linkedin", + field=models.CharField( + blank="True", + help_text="Link to LinkedIn profile", + max_length=255, + verbose_name="LinkedIn link", + ), ), migrations.AlterField( - model_name='socialmediasettings', - name='mastodon', - field=models.CharField(blank='True', help_text='Link to Mastodon profile', max_length=255, verbose_name='Mastodon link'), + model_name="socialmediasettings", + name="mastodon", + field=models.CharField( + blank="True", + help_text="Link to Mastodon profile", + max_length=255, + verbose_name="Mastodon link", + ), ), migrations.AlterField( - model_name='socialmediasettings', - name='twitter', - field=models.CharField(blank='True', help_text='Link to Twitter profile', max_length=255, verbose_name='Twitter link'), + model_name="socialmediasettings", + name="twitter", + field=models.CharField( + blank="True", + help_text="Link to Twitter profile", + max_length=255, + verbose_name="Twitter link", + ), ), migrations.AlterField( - model_name='socialmediasettings', - name='youtube', - field=models.CharField(blank='True', help_text='Link to YouTube account', max_length=255, verbose_name='Youtube link'), + model_name="socialmediasettings", + name="youtube", + field=models.CharField( + blank="True", + help_text="Link to YouTube account", + max_length=255, + verbose_name="Youtube link", + ), ), ] diff --git a/ietf/utils/migrations/0009_megamenu.py b/ietf/utils/migrations/0009_megamenu.py index 9a581714..49decd49 100644 --- a/ietf/utils/migrations/0009_megamenu.py +++ b/ietf/utils/migrations/0009_megamenu.py @@ -2,11 +2,11 @@ import uuid -from django.db import migrations, models import django.db.models.deletion import wagtail.blocks import wagtail.fields import wagtail.models +from django.db import migrations, models def populate_main_menu(apps, schema_editor): @@ -18,7 +18,11 @@ def live_children(page): if not page: return Page.objects.none() # path of children is path of parent with 4 more characters at the end - return Page.objects.filter(path__regex=f"^{page.path}....$").filter(live=True).order_by("path") + return ( + Page.objects.filter(path__regex=f"^{page.path}....$") + .filter(live=True) + .order_by("path") + ) homepage = HomePage.objects.first() if not homepage: @@ -62,27 +66,102 @@ def live_children(page): class Migration(migrations.Migration): dependencies = [ - ('images', '0004_django_42_rendition_storage'), - ('wagtailcore', '0089_log_entry_data_json_null_to_object'), - ('utils', '0008_socialmediasettings_github_and_more'), + ("images", "0004_django_42_rendition_storage"), + ("wagtailcore", "0089_log_entry_data_json_null_to_object"), + ("utils", "0008_socialmediasettings_github_and_more"), ] operations = [ migrations.RenameModel( - old_name='MenuItem', - new_name='SecondaryMenuItem', + old_name="MenuItem", + new_name="SecondaryMenuItem", ), migrations.CreateModel( - name='MainMenuItem', + name="MainMenuItem", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('secondary_sections', wagtail.fields.StreamField([('section', wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock(label='Section title', required=True)), ('links', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('page', wagtail.blocks.PageChooserBlock(label='Page', required=False)), ('title', wagtail.blocks.CharBlock(label='Link text', required=False)), ('external_url', wagtail.blocks.URLBlock(label='External URL', required=False))])))]))], blank=True, use_json_field=True)), - ('sort_order', models.PositiveSmallIntegerField()), - ('image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.ietfimage')), - ('page', models.ForeignKey(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", + ), + ), + ( + "secondary_sections", + wagtail.fields.StreamField( + [ + ( + "section", + wagtail.blocks.StructBlock( + [ + ( + "title", + wagtail.blocks.CharBlock( + label="Section title", required=True + ), + ), + ( + "links", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "page", + wagtail.blocks.PageChooserBlock( + label="Page", + required=False, + ), + ), + ( + "title", + wagtail.blocks.CharBlock( + label="Link text", + required=False, + ), + ), + ( + "external_url", + wagtail.blocks.URLBlock( + label="External URL", + required=False, + ), + ), + ] + ) + ), + ), + ] + ), + ) + ], + blank=True, + use_json_field=True, + ), + ), + ("sort_order", models.PositiveSmallIntegerField()), + ( + "image", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="images.ietfimage", + ), + ), + ( + "page", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="+", + to="wagtailcore.page", + ), + ), ], options={ - 'ordering': ['sort_order'], + "ordering": ["sort_order"], }, bases=(wagtail.models.PreviewableMixin, models.Model), ), diff --git a/ietf/utils/migrations/0010_footercolumn.py b/ietf/utils/migrations/0010_footercolumn.py index 35d73676..69527854 100644 --- a/ietf/utils/migrations/0010_footercolumn.py +++ b/ietf/utils/migrations/0010_footercolumn.py @@ -1,28 +1,69 @@ # Generated by Django 4.2.7 on 2024-03-29 14:06 -from django.db import migrations, models import wagtail.blocks import wagtail.fields import wagtail.models +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('utils', '0009_megamenu'), + ("utils", "0009_megamenu"), ] operations = [ migrations.CreateModel( - name='FooterColumn', + name="FooterColumn", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('title', models.CharField(max_length=255)), - ('links', wagtail.fields.StreamField([('link', wagtail.blocks.StructBlock([('page', wagtail.blocks.PageChooserBlock(label='Page', required=False)), ('title', wagtail.blocks.CharBlock(label='Link text', required=False)), ('external_url', wagtail.blocks.URLBlock(label='External URL', required=False))]))], blank=True, use_json_field=True)), - ('sort_order', models.PositiveSmallIntegerField()), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("title", models.CharField(max_length=255)), + ( + "links", + wagtail.fields.StreamField( + [ + ( + "link", + wagtail.blocks.StructBlock( + [ + ( + "page", + wagtail.blocks.PageChooserBlock( + label="Page", required=False + ), + ), + ( + "title", + wagtail.blocks.CharBlock( + label="Link text", required=False + ), + ), + ( + "external_url", + wagtail.blocks.URLBlock( + label="External URL", required=False + ), + ), + ] + ), + ) + ], + blank=True, + use_json_field=True, + ), + ), + ("sort_order", models.PositiveSmallIntegerField()), ], options={ - 'ordering': ['sort_order'], + "ordering": ["sort_order"], }, bases=(wagtail.models.PreviewableMixin, models.Model), ), diff --git a/ietf/utils/models.py b/ietf/utils/models.py index 7e2ddb60..3589573d 100644 --- a/ietf/utils/models.py +++ b/ietf/utils/models.py @@ -1,6 +1,5 @@ from django.conf import settings from django.db import models -from django.utils.translation import gettext_lazy as _ from modelcluster.fields import ParentalKey from modelcluster.models import ClusterableModel from wagtail.admin.panels import FieldPanel, InlinePanel, MultiFieldPanel @@ -105,7 +104,9 @@ def get_social_text(self): class MainMenuItem(PreviewableMixin, models.Model): - page = models.ForeignKey("wagtailcore.Page", related_name="+", on_delete=models.CASCADE) + page = models.ForeignKey( + "wagtailcore.Page", related_name="+", on_delete=models.CASCADE + ) image = models.ForeignKey( "images.IETFImage", null=True, @@ -262,33 +263,33 @@ class SocialMediaSettings(BaseSiteSetting): max_length=255, help_text="Link to LinkedIn profile", blank="True", - verbose_name="LinkedIn link" + verbose_name="LinkedIn link", ) twitter = models.CharField( max_length=255, help_text="Link to Twitter profile", blank="True", - verbose_name="Twitter link" + verbose_name="Twitter link", ) youtube = models.CharField( max_length=255, help_text="Link to YouTube account", blank="True", - verbose_name="Youtube link" + verbose_name="Youtube link", ) mastodon = models.CharField( max_length=255, help_text="Link to Mastodon profile", blank="True", - verbose_name="Mastodon link" + verbose_name="Mastodon link", ) github = models.CharField( max_length=255, help_text="Link to GitHub profile", blank="True", - verbose_name="GitHub link" + verbose_name="GitHub link", ) - + panels = [ FieldPanel("twitter_handle"), FieldPanel("facebook_app_id"), diff --git a/ietf/utils/signal_handlers.py b/ietf/utils/signal_handlers.py index d607bf46..cf6eb3a8 100644 --- a/ietf/utils/signal_handlers.py +++ b/ietf/utils/signal_handlers.py @@ -11,14 +11,13 @@ def page_published_or_unpublished_handler(instance, **kwargs): home_page = instance.get_site().root_page purge_pages = set() - if not instance.pk == home_page.pk: + if instance.pk != home_page.pk: parent = instance.get_parent() purge_pages.add(parent) for obj, _ in ReferenceIndex.get_grouped_references_to(instance): - if isinstance(obj, Page): - if obj.live: - purge_pages.add(obj) + if isinstance(obj, Page) and obj.live: + purge_pages.add(obj) if isinstance(obj, MainMenuItem): purge_pages.add(home_page) diff --git a/ietf/utils/templatetags/ietf_tags.py b/ietf/utils/templatetags/ietf_tags.py index 4963487f..d31c05ef 100644 --- a/ietf/utils/templatetags/ietf_tags.py +++ b/ietf/utils/templatetags/ietf_tags.py @@ -1,7 +1,6 @@ from urllib.parse import quote from django.template import Library -from wagtail.models import Site from ..models import PromoteMixin, SocialMediaSettings diff --git a/ietf/utils/tests/test_500_page.py b/ietf/utils/tests/test_500_page.py index 4f4029c6..129e86b0 100644 --- a/ietf/utils/tests/test_500_page.py +++ b/ietf/utils/tests/test_500_page.py @@ -1,6 +1,7 @@ from unittest.mock import Mock -from django.test import Client + import pytest +from django.test import Client pytestmark = pytest.mark.django_db diff --git a/ietf/utils/tests/test_footer.py b/ietf/utils/tests/test_footer.py index fe405cda..7a2cebb2 100644 --- a/ietf/utils/tests/test_footer.py +++ b/ietf/utils/tests/test_footer.py @@ -1,5 +1,5 @@ -from bs4 import BeautifulSoup import pytest +from bs4 import BeautifulSoup from django.test import Client, RequestFactory from ietf.home.models import HomePage @@ -85,14 +85,14 @@ def test_links(self): def test_order_in_preview(self): item1 = FooterColumn.objects.create(title="One", sort_order=10) - item2 = FooterColumn.objects.create(title="Two", sort_order=20) + FooterColumn.objects.create(title="Two", sort_order=20) item1.sort_order = 30 context = item1.get_preview_context(RequestFactory().get("/"), "") assert [i.title for i in context["FOOTER"]] == ["Two", "One"] def test_order_in_preview_new_object(self): - item1 = FooterColumn.objects.create(title="One", sort_order=10) + FooterColumn.objects.create(title="One", sort_order=10) item2 = FooterColumn(title="Two", sort_order=5) context = item2.get_preview_context(RequestFactory().get("/"), "") diff --git a/ietf/utils/tests/test_iab_main_menu.py b/ietf/utils/tests/test_iab_main_menu.py index 56bec58c..9d417dce 100644 --- a/ietf/utils/tests/test_iab_main_menu.py +++ b/ietf/utils/tests/test_iab_main_menu.py @@ -1,6 +1,6 @@ +import pytest from bs4 import BeautifulSoup from django.test import Client -import pytest from ietf.home.models import IABHomePage from ietf.standard.factories import IABStandardPageFactory @@ -28,7 +28,7 @@ def test_pages_in_menu(self): soup = BeautifulSoup(html, "html.parser") def get_nav_item(item): - """ Get the menu item link, and the links within the menu. """ + """Get the menu item link, and the links within the menu.""" [main_link] = item.select("a.nav-link") child_links = item.select("ul.dropdown-menu > li > a") return ( @@ -40,5 +40,5 @@ def get_nav_item(item): assert menu == [ (page1.url, [page1a.url, page1b.url]), (page2.url, [page2a.url, page2b.url]), - ('/search', []), + ("/search", []), ] diff --git a/ietf/utils/tests/test_mega_menu.py b/ietf/utils/tests/test_mega_menu.py index 7558c2ad..bad072e1 100644 --- a/ietf/utils/tests/test_mega_menu.py +++ b/ietf/utils/tests/test_mega_menu.py @@ -1,5 +1,5 @@ -from bs4 import BeautifulSoup import pytest +from bs4 import BeautifulSoup from django.test import Client, RequestFactory from ietf.home.models import HomePage @@ -100,7 +100,7 @@ def test_secondary_section(self): def test_order_in_preview(self): item1 = MainMenuItem.objects.create(page=self.standard_index, sort_order=10) - item2 = MainMenuItem.objects.create(page=self.standard_page, sort_order=20) + MainMenuItem.objects.create(page=self.standard_page, sort_order=20) item1.sort_order = 30 context = item1.get_preview_context(RequestFactory().get("/"), "") @@ -110,7 +110,7 @@ def test_order_in_preview(self): ] def test_order_in_preview_new_object(self): - item1 = MainMenuItem.objects.create(page=self.standard_index, sort_order=10) + MainMenuItem.objects.create(page=self.standard_index, sort_order=10) item2 = MainMenuItem(page=self.standard_page, sort_order=5) context = item2.get_preview_context(RequestFactory().get("/"), "") diff --git a/ietf/utils/tests/test_secondary_menu.py b/ietf/utils/tests/test_secondary_menu.py index 83746c09..db82f685 100644 --- a/ietf/utils/tests/test_secondary_menu.py +++ b/ietf/utils/tests/test_secondary_menu.py @@ -1,5 +1,5 @@ -from django.test import Client import pytest +from django.test import Client from wagtail.test.utils import WagtailTestUtils from ietf.events.factories import EventListingPageFactory, EventPageFactory @@ -21,8 +21,12 @@ def set_up(self, home: HomePage): ) def _build_menu(self): - SecondaryMenuItem.objects.create(page=self.eventlisting, text="Menu One", sort_order=0) - SecondaryMenuItem.objects.create(page=self.eventpage, text="Menu Two", sort_order=1) + SecondaryMenuItem.objects.create( + page=self.eventlisting, text="Menu One", sort_order=0 + ) + SecondaryMenuItem.objects.create( + page=self.eventpage, text="Menu Two", sort_order=1 + ) def test_admin_menu_item_index(self, admin_client): response = admin_client.get("/admin/utils/secondarymenuitem/") diff --git a/ietf/utils/wagtail_hooks.py b/ietf/utils/wagtail_hooks.py index d75dca5c..4d818bde 100644 --- a/ietf/utils/wagtail_hooks.py +++ b/ietf/utils/wagtail_hooks.py @@ -1,8 +1,8 @@ from django.conf import settings from django.utils.html import format_html from wagtail import hooks -from wagtail.snippets.views.snippets import SnippetViewSet from wagtail.snippets.models import register_snippet +from wagtail.snippets.views.snippets import SnippetViewSet from wagtail_modeladmin.options import ModelAdmin, modeladmin_register from wagtailorderable.modeladmin.mixins import OrderableMixin diff --git a/k8s/ietfweb/local.py b/k8s/ietfweb/local.py index 3392becc..9704389e 100644 --- a/k8s/ietfweb/local.py +++ b/k8s/ietfweb/local.py @@ -1,8 +1,8 @@ # Copyright The IETF Trust 2007-2024, All Rights Reserved -# -*- coding: utf-8 -*- -from email.utils import parseaddr import os +from email.utils import parseaddr + def _multiline_to_list(s): """Helper to split at newlines and conver to list""" @@ -63,7 +63,9 @@ def _multiline_to_list(s): # Leave IETFWWW_MATOMO_SITE_ID unset to disable Matomo reporting if "IETFWWW_MATOMO_SITE_ID" in os.environ: - MATOMO_DOMAIN_PATH = os.environ.get("IETFWWW_MATOMO_DOMAIN_PATH", "analytics.ietf.org") + MATOMO_DOMAIN_PATH = os.environ.get( + "IETFWWW_MATOMO_DOMAIN_PATH", "analytics.ietf.org" + ) MATOMO_SITE_ID = os.environ.get("IETFWWW_MATOMO_SITE_ID", None) MATOMO_DISABLE_COOKIES = True diff --git a/pyproject.toml b/pyproject.toml index 99977b55..728984be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,3 +7,20 @@ filterwarnings = [ "ignore:'index_together'.*'taggit.TaggedItem':django.utils.deprecation.RemovedInDjango51Warning:", "ignore::UserWarning", ] + +[tool.ruff] +target-version = "py312" + +[tool.ruff.lint] +extend-select = [ + "E", # pycodestyle + "F", # Pyflakes + "UP", # pyupgrade + "B", # flake8-bugbear + "SIM", # flake8-simplify + "I", # isort +] + +extend-ignore = [ + "E501", # no line length errors +] diff --git a/requirements/dev.in b/requirements/dev.in index 78f9dcca..84317e8f 100644 --- a/requirements/dev.in +++ b/requirements/dev.in @@ -1,6 +1,9 @@ -c base.txt +black pip-tools +pre-commit pytest-cov pytest-django +ruff wagtail-factories diff --git a/requirements/dev.txt b/requirements/dev.txt index 52c14df4..f6225bc7 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -16,18 +16,24 @@ beautifulsoup4==4.11.2 # via # -c base.txt # wagtail +black==24.8.0 + # via -r dev.in build==1.2.1 # via pip-tools certifi==2024.7.4 # via # -c base.txt # requests +cfgv==3.4.0 + # via pre-commit charset-normalizer==3.3.2 # via # -c base.txt # requests click==8.1.7 - # via pip-tools + # via + # black + # pip-tools coverage[toml]==7.6.1 # via # coverage @@ -36,7 +42,9 @@ defusedxml==0.7.1 # via # -c base.txt # willow -django==4.2.14 +distlib==0.3.8 + # via virtualenv +django==4.2.15 # via # -c base.txt # django-filter @@ -80,8 +88,10 @@ et-xmlfile==1.1.0 # openpyxl factory-boy==3.3.0 # via wagtail-factories -faker==26.1.0 +faker==26.2.0 # via factory-boy +filelock==3.15.4 + # via virtualenv filetype==1.2.0 # via # -c base.txt @@ -90,6 +100,8 @@ html5lib==1.1 # via # -c base.txt # wagtail +identify==2.6.0 + # via pre-commit idna==3.7 # via # -c base.txt @@ -100,6 +112,10 @@ l18n==2021.3 # via # -c base.txt # wagtail +mypy-extensions==1.0.0 + # via black +nodeenv==1.9.1 + # via pre-commit openpyxl==3.1.5 # via # -c base.txt @@ -107,8 +123,11 @@ openpyxl==3.1.5 packaging==24.1 # via # -c base.txt + # black # build # pytest +pathspec==0.12.1 + # via black pillow==10.4.0 # via # -c base.txt @@ -120,8 +139,14 @@ pillow-heif==0.18.0 # willow pip-tools==7.4.1 # via -r dev.in +platformdirs==4.2.2 + # via + # black + # virtualenv pluggy==1.5.0 # via pytest +pre-commit==3.8.0 + # via -r dev.in pyproject-hooks==1.1.0 # via # build @@ -141,10 +166,14 @@ pytz==2024.1 # -c base.txt # django-modelcluster # l18n +pyyaml==6.0.2 + # via pre-commit requests==2.32.3 # via # -c base.txt # wagtail +ruff==0.5.6 + # via -r dev.in six==1.16.0 # via # -c base.txt @@ -167,6 +196,8 @@ urllib3==2.2.2 # via # -c base.txt # requests +virtualenv==20.26.3 + # via pre-commit wagtail==5.2.6 # via # -c base.txt @@ -187,4 +218,4 @@ willow[heif]==1.6.3 # The following packages are considered to be unsafe in a requirements file: # pip -# setuptools +# setuptools \ No newline at end of file