diff --git a/content_migration/management/import_archive_articles_handler.py b/content_migration/management/import_archive_articles_handler.py index 3ceae6b3b..e84c68344 100644 --- a/content_migration/management/import_archive_articles_handler.py +++ b/content_migration/management/import_archive_articles_handler.py @@ -1,6 +1,7 @@ import logging from django.core.exceptions import ObjectDoesNotExist +from django.db import IntegrityError from tqdm import tqdm from content_migration.management.errors import ( CouldNotFindMatchingContactError, @@ -41,6 +42,7 @@ def create_archive_article_authors( for drupal_author_id in authors_list: try: + # TODO: determine if this is the cause of importer slowness contact = get_existing_magazine_author_from_db( drupal_author_id, ) @@ -50,18 +52,21 @@ def create_archive_article_authors( ): continue - article_author_exists = ArchiveArticleAuthor.objects.filter( - article=archive_article, - author=contact, - ).exists() - - if not article_author_exists: + # TODO: determine if this is the cause of importer slowness + # For performance reasons, + # check if the ArchiveArticleAuthor instance already exists + # using the unique together constraint (implicit check) + try: article_author = ArchiveArticleAuthor( article=archive_article, author=contact, ) article_author.save() + # handle unique together constraint exception + except IntegrityError as e: + logger.error(e) + continue def handle_import_archive_articles(file_name: str) -> None: diff --git a/library/migrations/0017_alter_libraryitem_body.py b/library/migrations/0017_alter_libraryitem_body.py new file mode 100644 index 000000000..2c5927d5e --- /dev/null +++ b/library/migrations/0017_alter_libraryitem_body.py @@ -0,0 +1,137 @@ +# Generated by Django 4.2.1 on 2023-06-20 09:59 + +import blocks.blocks +import django.core.validators +from django.db import migrations +import documents.blocks +import re +import wagtail.blocks +import wagtail.embeds.blocks +import wagtail.fields +import wagtail.images.blocks +import wagtail_color_panel.blocks + + +class Migration(migrations.Migration): + dependencies = [ + ("library", "0001_squashed_0016_alter_libraryitem_body"), + ] + + operations = [ + migrations.AlterField( + model_name="libraryitem", + name="body", + field=wagtail.fields.StreamField( + [ + ( + "heading", + wagtail.blocks.StructBlock( + [ + ( + "heading_level", + wagtail.blocks.ChoiceBlock( + choices=[ + ("h2", "Level 2 (child of level 1)"), + ("h3", "Level 3 (child of level 2)"), + ("h4", "Level 4 (child of level 3)"), + ("h5", "Level 5 (child of level 4)"), + ("h6", "Level 6 (child of level 5)"), + ], + help_text="These different heading levels help to communicate the organization and hierarchy of the content on a page.", + ), + ), + ( + "heading_text", + wagtail.blocks.CharBlock( + help_text="The text to appear in the heading." + ), + ), + ( + "target_slug", + wagtail.blocks.CharBlock( + help_text="Used to link to a specific location within this page. A slug should only contain letters, numbers, underscore (_), or hyphen (-).", + required=False, + validators=( + django.core.validators.RegexValidator( + re.compile("^[-a-zA-Z0-9_]+\\Z"), + "Enter a valid “slug” consisting of letters, numbers, underscores or hyphens.", + "invalid", + ), + ), + ), + ), + ( + "color", + wagtail_color_panel.blocks.NativeColorBlock( + required=False + ), + ), + ] + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock( + features=["bold", "italic", "ol", "ul", "link", "hr"] + ), + ), + ( + "image", + wagtail.blocks.StructBlock( + [ + ("image", wagtail.images.blocks.ImageChooserBlock()), + ( + "width", + wagtail.blocks.IntegerBlock( + help_text="Enter the desired image width value in pixels up to 800 max.", + max_value=800, + min_value=0, + ), + ), + ( + "align", + wagtail.blocks.ChoiceBlock( + choices=[("left", "Left"), ("right", "Right")], + help_test="Optionally align image left or right", + icon="file-richtext", + required=False, + ), + ), + ( + "link", + wagtail.blocks.URLBlock( + help_text="Optional web address to use as image link.", + required=False, + ), + ), + ], + classname="full title", + ), + ), + ("document", documents.blocks.DocumentEmbedBlock()), + ("media", blocks.blocks.MediaBlock(icon="media")), + ("embed", wagtail.embeds.blocks.EmbedBlock()), + ("url", blocks.blocks.WfURLBlock()), + ("pullquote", blocks.blocks.PullQuoteBlock()), + ( + "spacer", + wagtail.blocks.StructBlock( + [ + ( + "height", + wagtail.blocks.DecimalBlock( + decimal_places=1, + help_text="The height of this spacer in 'em' values where 1 em is one uppercase M.", + min_value=0, + ), + ) + ] + ), + ), + ], + blank=True, + null=True, + use_json_field=True, + ), + ), + ] diff --git a/library/models.py b/library/models.py index 8c74d1c80..88a65d144 100644 --- a/library/models.py +++ b/library/models.py @@ -20,6 +20,7 @@ FormattedImageChooserStructBlock, HeadingBlock, MediaBlock, + PullQuoteBlock, SpacerBlock, WfURLBlock, ) @@ -42,16 +43,11 @@ class LibraryItem(Page): description = RichTextField(null=True, blank=True) body = StreamField( [ - ( - "heading", - HeadingBlock(), - ), + ("heading", HeadingBlock()), ( "rich_text", wagtail_blocks.RichTextBlock( features=[ - "h2", - "h3", "bold", "italic", "ol", @@ -67,32 +63,17 @@ class LibraryItem(Page): classname="full title", ), ), - ( - "document", - DocumentEmbedBlock(), - ), + ("document", DocumentEmbedBlock()), ( "media", MediaBlock( icon="media", ), ), - ( - "embed", - EmbedBlock(), - ), - ( - "url", - WfURLBlock(), - ), - ( - "quote", - wagtail_blocks.BlockQuoteBlock(), - ), - ( - "spacer", - SpacerBlock(), - ), + ("embed", EmbedBlock()), + ("url", WfURLBlock()), + ("pullquote", PullQuoteBlock()), + ("spacer", SpacerBlock()), ], null=True, blank=True, diff --git a/magazine/migrations/0025_alter_archivearticleauthor_options_and_more.py b/magazine/migrations/0025_alter_archivearticleauthor_options_and_more.py new file mode 100644 index 000000000..d06a15a8d --- /dev/null +++ b/magazine/migrations/0025_alter_archivearticleauthor_options_and_more.py @@ -0,0 +1,151 @@ +# Generated by Django 4.2.1 on 2023-06-20 09:59 + +import blocks.blocks +import django.core.validators +from django.db import migrations +import documents.blocks +import re +import wagtail.blocks +import wagtail.fields +import wagtail.images.blocks +import wagtail_color_panel.blocks + + +class Migration(migrations.Migration): + dependencies = [ + ("wagtailcore", "0083_workflowcontenttype"), + ("magazine", "0001_squashed_0024_magazineissue_magazine_ma_drupal__50c0bf_idx"), + ] + + operations = [ + migrations.AlterModelOptions( + name="archivearticleauthor", + options={}, + ), + migrations.AlterField( + model_name="magazinearticle", + name="body", + field=wagtail.fields.StreamField( + [ + ( + "heading", + wagtail.blocks.StructBlock( + [ + ( + "heading_level", + wagtail.blocks.ChoiceBlock( + choices=[ + ("h2", "Level 2 (child of level 1)"), + ("h3", "Level 3 (child of level 2)"), + ("h4", "Level 4 (child of level 3)"), + ("h5", "Level 5 (child of level 4)"), + ("h6", "Level 6 (child of level 5)"), + ], + help_text="These different heading levels help to communicate the organization and hierarchy of the content on a page.", + ), + ), + ( + "heading_text", + wagtail.blocks.CharBlock( + help_text="The text to appear in the heading." + ), + ), + ( + "target_slug", + wagtail.blocks.CharBlock( + help_text="Used to link to a specific location within this page. A slug should only contain letters, numbers, underscore (_), or hyphen (-).", + required=False, + validators=( + django.core.validators.RegexValidator( + re.compile("^[-a-zA-Z0-9_]+\\Z"), + "Enter a valid “slug” consisting of letters, numbers, underscores or hyphens.", + "invalid", + ), + ), + ), + ), + ( + "color", + wagtail_color_panel.blocks.NativeColorBlock( + required=False + ), + ), + ] + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock( + features=[ + "bold", + "italic", + "ol", + "ul", + "hr", + "link", + "document-link", + "superscript", + "superscript", + "strikethrough", + ] + ), + ), + ("pullquote", blocks.blocks.PullQuoteBlock()), + ("document", documents.blocks.DocumentEmbedBlock()), + ( + "image", + wagtail.blocks.StructBlock( + [ + ("image", wagtail.images.blocks.ImageChooserBlock()), + ( + "width", + wagtail.blocks.IntegerBlock( + help_text="Enter the desired image width value in pixels up to 800 max.", + max_value=800, + min_value=0, + ), + ), + ( + "align", + wagtail.blocks.ChoiceBlock( + choices=[("left", "Left"), ("right", "Right")], + help_test="Optionally align image left or right", + icon="file-richtext", + required=False, + ), + ), + ( + "link", + wagtail.blocks.URLBlock( + help_text="Optional web address to use as image link.", + required=False, + ), + ), + ], + classname="full title", + ), + ), + ( + "spacer", + wagtail.blocks.StructBlock( + [ + ( + "height", + wagtail.blocks.DecimalBlock( + decimal_places=1, + help_text="The height of this spacer in 'em' values where 1 em is one uppercase M.", + min_value=0, + ), + ) + ] + ), + ), + ], + use_json_field=True, + ), + ), + migrations.AlterUniqueTogether( + name="archivearticleauthor", + unique_together={("article", "author")}, + ), + ] diff --git a/magazine/models.py b/magazine/models.py index d892cab5d..b5b6dc653 100644 --- a/magazine/models.py +++ b/magazine/models.py @@ -18,7 +18,6 @@ MultiFieldPanel, PageChooserPanel, ) -from wagtail.documents.blocks import DocumentChooserBlock from wagtail.fields import RichTextField, StreamField from wagtail.models import Orderable, Page from wagtail.search import index @@ -29,6 +28,7 @@ PullQuoteBlock, SpacerBlock, ) +from documents.blocks import DocumentEmbedBlock from .panels import NestedInlinePanel @@ -257,12 +257,11 @@ class MagazineArticle(Page): "superscript", "superscript", "strikethrough", - "blockquote", ] ), ), ("pullquote", PullQuoteBlock()), - ("document", DocumentChooserBlock()), + ("document", DocumentEmbedBlock()), ("image", FormattedImageChooserStructBlock(classname="full title")), ("spacer", SpacerBlock()), ], @@ -404,6 +403,9 @@ class ArchiveArticleAuthor(Orderable): ) ] + class Meta: + unique_together = ("article", "author") + class ArchiveArticle(ClusterableModel): title = models.CharField(max_length=255) diff --git a/wf_pages/migrations/0018_alter_wfpage_body.py b/wf_pages/migrations/0018_alter_wfpage_body.py new file mode 100644 index 000000000..bcf493cab --- /dev/null +++ b/wf_pages/migrations/0018_alter_wfpage_body.py @@ -0,0 +1,142 @@ +# Generated by Django 4.2.1 on 2023-06-20 09:59 + +import blocks.blocks +import django.core.validators +from django.db import migrations +import documents.blocks +import re +import wagtail.blocks +import wagtail.fields +import wagtail.images.blocks +import wagtail_color_panel.blocks + + +class Migration(migrations.Migration): + dependencies = [ + ("wf_pages", "0017_mollywingateblogindexpage_mollywingateblogpage_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="wfpage", + name="body", + field=wagtail.fields.StreamField( + [ + ( + "heading", + wagtail.blocks.StructBlock( + [ + ( + "heading_level", + wagtail.blocks.ChoiceBlock( + choices=[ + ("h2", "Level 2 (child of level 1)"), + ("h3", "Level 3 (child of level 2)"), + ("h4", "Level 4 (child of level 3)"), + ("h5", "Level 5 (child of level 4)"), + ("h6", "Level 6 (child of level 5)"), + ], + help_text="These different heading levels help to communicate the organization and hierarchy of the content on a page.", + ), + ), + ( + "heading_text", + wagtail.blocks.CharBlock( + help_text="The text to appear in the heading." + ), + ), + ( + "target_slug", + wagtail.blocks.CharBlock( + help_text="Used to link to a specific location within this page. A slug should only contain letters, numbers, underscore (_), or hyphen (-).", + required=False, + validators=( + django.core.validators.RegexValidator( + re.compile("^[-a-zA-Z0-9_]+\\Z"), + "Enter a valid “slug” consisting of letters, numbers, underscores or hyphens.", + "invalid", + ), + ), + ), + ), + ( + "color", + wagtail_color_panel.blocks.NativeColorBlock( + required=False + ), + ), + ] + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock( + features=[ + "bold", + "italic", + "ol", + "ul", + "hr", + "link", + "document-link", + "superscript", + "strikethrough", + "blockquote", + ] + ), + ), + ("pullquote", blocks.blocks.PullQuoteBlock()), + ("document", documents.blocks.DocumentEmbedBlock()), + ( + "image", + wagtail.blocks.StructBlock( + [ + ("image", wagtail.images.blocks.ImageChooserBlock()), + ( + "width", + wagtail.blocks.IntegerBlock( + help_text="Enter the desired image width value in pixels up to 800 max.", + max_value=800, + min_value=0, + ), + ), + ( + "align", + wagtail.blocks.ChoiceBlock( + choices=[("left", "Left"), ("right", "Right")], + help_test="Optionally align image left or right", + icon="file-richtext", + required=False, + ), + ), + ( + "link", + wagtail.blocks.URLBlock( + help_text="Optional web address to use as image link.", + required=False, + ), + ), + ], + classname="full title", + ), + ), + ( + "spacer", + wagtail.blocks.StructBlock( + [ + ( + "height", + wagtail.blocks.DecimalBlock( + decimal_places=1, + help_text="The height of this spacer in 'em' values where 1 em is one uppercase M.", + min_value=0, + ), + ) + ] + ), + ), + ], + use_json_field=True, + ), + ), + ] diff --git a/wf_pages/models.py b/wf_pages/models.py index 622fe7bdd..ace847065 100644 --- a/wf_pages/models.py +++ b/wf_pages/models.py @@ -10,7 +10,12 @@ from wagtail.models import Page from wagtail.search import index -from blocks.blocks import FormattedImageChooserStructBlock, HeadingBlock, SpacerBlock +from blocks.blocks import ( + FormattedImageChooserStructBlock, + HeadingBlock, + PullQuoteBlock, + SpacerBlock, +) from documents.blocks import DocumentEmbedBlock @@ -79,7 +84,7 @@ class WfPage(Page): ] ), ), - ("quote", wagtail_blocks.BlockQuoteBlock()), + ("pullquote", PullQuoteBlock()), ("document", DocumentEmbedBlock()), ("image", FormattedImageChooserStructBlock(classname="full title")), ("spacer", SpacerBlock()),