diff --git a/community/migrations/0013_onlineworship_drupal_body_migrated_and_more.py b/community/migrations/0013_onlineworship_drupal_body_migrated_and_more.py
new file mode 100644
index 000000000..4f2a2ab46
--- /dev/null
+++ b/community/migrations/0013_onlineworship_drupal_body_migrated_and_more.py
@@ -0,0 +1,27 @@
+# Generated by Django 4.2.1 on 2023-06-16 10:27
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("community", "0001_squashed_0012_alter_communitypage_body"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="onlineworship",
+ name="drupal_body_migrated",
+ field=models.TextField(blank=True, null=True),
+ ),
+ migrations.AddField(
+ model_name="onlineworship",
+ name="drupal_node_id",
+ field=models.IntegerField(blank=True, null=True),
+ ),
+ migrations.AddField(
+ model_name="onlineworship",
+ name="drupal_path",
+ field=models.CharField(blank=True, max_length=255, null=True),
+ ),
+ ]
diff --git a/community/migrations/0014_rename_drupal_path_onlineworship_drupal_url_path.py b/community/migrations/0014_rename_drupal_path_onlineworship_drupal_url_path.py
new file mode 100644
index 000000000..f5ef269a2
--- /dev/null
+++ b/community/migrations/0014_rename_drupal_path_onlineworship_drupal_url_path.py
@@ -0,0 +1,17 @@
+# Generated by Django 4.2.1 on 2023-06-16 11:10
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("community", "0013_onlineworship_drupal_body_migrated_and_more"),
+ ]
+
+ operations = [
+ migrations.RenameField(
+ model_name="onlineworship",
+ old_name="drupal_path",
+ new_name="drupal_url_path",
+ ),
+ ]
diff --git a/community/migrations/0015_onlineworship_online_worship_day_and_more.py b/community/migrations/0015_onlineworship_online_worship_day_and_more.py
new file mode 100644
index 000000000..284dc25a7
--- /dev/null
+++ b/community/migrations/0015_onlineworship_online_worship_day_and_more.py
@@ -0,0 +1,41 @@
+# Generated by Django 4.2.1 on 2023-06-16 11:36
+
+from django.db import migrations, models
+import timezone_field.fields
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("community", "0014_rename_drupal_path_onlineworship_drupal_url_path"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="onlineworship",
+ name="online_worship_day",
+ field=models.CharField(
+ blank=True,
+ choices=[
+ ("Sunday", "Sunday"),
+ ("Monday", "Monday"),
+ ("Tuesday", "Tuesday"),
+ ("Wednesday", "Wednesday"),
+ ("Thursday", "Thursday"),
+ ("Friday", "Friday"),
+ ("Saturday", "Saturday"),
+ ],
+ max_length=255,
+ null=True,
+ ),
+ ),
+ migrations.AddField(
+ model_name="onlineworship",
+ name="online_worship_time",
+ field=models.TimeField(blank=True, null=True),
+ ),
+ migrations.AddField(
+ model_name="onlineworship",
+ name="online_worship_timezone",
+ field=timezone_field.fields.TimeZoneField(blank=True, null=True),
+ ),
+ ]
diff --git a/community/models.py b/community/models.py
index 8b97cbddd..e7368e36f 100644
--- a/community/models.py
+++ b/community/models.py
@@ -6,6 +6,8 @@
from wagtail.models import Page
from wagtail.search import index
+from timezone_field import TimeZoneField # type: ignore
+
from blocks import blocks as wf_blocks
@@ -47,6 +49,15 @@ class CommunityPage(Page):
class OnlineWorship(Page):
+ class OnlineWorshipDayChoices(models.TextChoices):
+ SUNDAY = "Sunday", "Sunday"
+ MONDAY = "Monday", "Monday"
+ TUESDAY = "Tuesday", "Tuesday"
+ WEDNESDAY = "Wednesday", "Wednesday"
+ THURSDAY = "Thursday", "Thursday"
+ FRIDAY = "Friday", "Friday"
+ SATURDAY = "Saturday", "Saturday"
+
description = RichTextField(blank=True)
hosted_by = models.ForeignKey(
@@ -56,11 +67,27 @@ class OnlineWorship(Page):
on_delete=models.SET_NULL,
related_name="online_worship",
)
-
+ # TODO: Define a custom, orderable model for this
+ # to allow for multiple times of worship.
times_of_worship = RichTextField(blank=True)
+ online_worship_day = models.CharField(
+ max_length=255,
+ null=True,
+ blank=True,
+ choices=OnlineWorshipDayChoices.choices,
+ )
+ online_worship_time = models.TimeField(null=True, blank=True)
+ online_worship_timezone = TimeZoneField(
+ null=True,
+ blank=True,
+ )
website = models.URLField(null=True, blank=True)
+ drupal_node_id = models.IntegerField(null=True, blank=True)
+ drupal_body_migrated = models.TextField(null=True, blank=True)
+ drupal_url_path = models.CharField(max_length=255, null=True, blank=True)
+
content_panels = Page.content_panels + [
FieldPanel("description"),
PageChooserPanel("hosted_by", ["contact.Meeting", "contact.Organization"]),
diff --git a/community/templates/community/online_worship.html b/community/templates/community/online_worship.html
index a8a1a4d8d..610e615f7 100644
--- a/community/templates/community/online_worship.html
+++ b/community/templates/community/online_worship.html
@@ -6,6 +6,7 @@
{% block title %}{{ page.title }}{% endblock %}
{% block content %}
+ Online Worship Directory
{{ page.title }}
{% if page.hosted_by %}
diff --git a/community/templates/community/online_worship_index_page.html b/community/templates/community/online_worship_index_page.html
index 8808aeb33..3ac88445c 100644
--- a/community/templates/community/online_worship_index_page.html
+++ b/community/templates/community/online_worship_index_page.html
@@ -11,47 +11,58 @@
{{ page.intro | richtext }}
-
+ {% for online_worship in self.get_children|dictsort:"title" %}
+
+
+
{{ online_worship.title }}
+
+ {% if online_worship.specific.times_of_worship %}
+
+ Times of worship:
+ {{ online_worship.specific.times_of_worship | richtext }}
+
+ {% endif %}
+
+ {% if online_worship.specific.hosted_by %}
+
+ Hosted by:
+ {{ online_worship.specific.hosted_by }}
+
+ {% endif %}
+
+ {% if online_worship.specific.online_worship_day %}
+
+ Online worship day:
+ {{ online_worship.specific.online_worship_day }}
+
+ {% endif %}
+
+ {% if online_worship.specific.online_worship_time %}
+
+ Online worship time:
+ {{ online_worship.specific.online_worship_time }}
+ {% if online_worship.specific.online_worship_timezone %}
+ ({{ online_worship.specific.online_worship_timezone }})
+ {% endif %}
+
+ {% endif %}
+
+ {% if online_worship.specific.online_worship_url %}
+
+ Online worship URL:
+ {{ online_worship.specific.online_worship_url }}
+
+ {% endif %}
+
+ {% if online_worship.specific.online_worship_notes %}
+
+ Online worship notes:
+ {{ online_worship.specific.online_worship_notes }}
+
+ {% endif %}
+
View details
+
+
+ {% endfor %}
+
{% endblock %}
diff --git a/content_migration/management/commands/import_online_worship.py b/content_migration/management/commands/import_online_worship.py
new file mode 100644
index 000000000..595c58477
--- /dev/null
+++ b/content_migration/management/commands/import_online_worship.py
@@ -0,0 +1,16 @@
+"""Management command to import Online Worship content."""
+from django.core.management.base import BaseCommand
+
+from content_migration.management.import_online_worship_handler import (
+ handle_import_online_worship,
+)
+
+
+class Command(BaseCommand):
+ """Import Online Worship content."""
+
+ help = "Import Online Worship content"
+
+ def handle(self, *args: tuple, **options: dict) -> None:
+ """Import Online Worship content."""
+ handle_import_online_worship()
diff --git a/content_migration/management/import_online_worship_handler.py b/content_migration/management/import_online_worship_handler.py
new file mode 100644
index 000000000..994c559f1
--- /dev/null
+++ b/content_migration/management/import_online_worship_handler.py
@@ -0,0 +1,134 @@
+from datetime import datetime
+from tqdm import tqdm
+from community.models import OnlineWorship, OnlineWorshipIndexPage
+from content_migration.management.errors import (
+ CouldNotFindMatchingContactError,
+ CouldNotParseAuthorIdError,
+)
+from content_migration.management.shared import (
+ construct_import_file_path,
+ create_permanent_redirect,
+ get_existing_magazine_author_from_db,
+ parse_csv_file,
+)
+
+
+TIMEZONE_CONVERSIONS = {
+ "Pacific": "US/Pacific",
+ "Mountain": "US/Mountain",
+ "Central": "US/Central",
+ "Eastern": "US/Eastern",
+}
+
+
+def get_time_or_none(time_str: str) -> str | None:
+ """Take a time in 24 hour integer format and return a time ztring in HH:MM
+ format."""
+ if time_str == "":
+ return None
+
+ try:
+ time_obj = datetime.strptime(time_str, "%H%M").time()
+ except ValueError as error:
+ raise ValueError(f"Unexpected time: {time_str}") from error
+
+ return time_obj.strftime("%H:%M")
+
+
+def get_timezone_or_none(timezone: str) -> str | None:
+ """Ensure that the timezone is in the proper format."""
+ if timezone == "":
+ return None
+
+ try:
+ return TIMEZONE_CONVERSIONS[timezone]
+ except KeyError as error:
+ raise ValueError(f"Unexpected timezone: {timezone}") from error
+
+
+def handle_import_online_worship_item(
+ item: dict,
+ index_page: OnlineWorshipIndexPage,
+) -> OnlineWorship:
+ """Import a single online worship item from Drupal."""
+
+ # check if news item exists
+ online_worship_exists = OnlineWorship.objects.filter(
+ drupal_node_id=item["drupal_node_id"]
+ ).exists()
+
+ title = item["title"]
+ description = item["body"]
+ hosted_by = get_existing_magazine_author_from_db(
+ drupal_author_id=item["magazine_author_id"]
+ )
+ # times_of_worship = item["times_of_worship"]
+ website = item["online_worship_url"]
+ drupal_node_id = item["drupal_node_id"]
+ drupal_body_migrated = item["body"]
+ drupal_url_path = item["url_path"]
+ online_worship_day = item["online_worship_day"]
+ online_worship_time = get_time_or_none(item["online_worship_time"])
+ online_worship_timezone = get_timezone_or_none(item["online_worship_timezone"])
+
+ if online_worship_exists:
+ online_worship_db = OnlineWorship.objects.get(
+ drupal_node_id=item["drupal_node_id"]
+ )
+ online_worship_db.title = title
+ online_worship_db.description = description
+ online_worship_db.hosted_by = hosted_by
+ # online_worship_db.times_of_worship = item["times_of_worship"]
+ online_worship_db.website = website
+ online_worship_db.drupal_body_migrated = drupal_body_migrated
+ online_worship_db.drupal_url_path = drupal_url_path
+ online_worship_db.online_worship_day = online_worship_day
+ online_worship_db.online_worship_time = online_worship_time
+ online_worship_db.online_worship_timezone = online_worship_timezone
+
+ online_worship_db.save()
+ else:
+ online_worship_db = OnlineWorship(
+ title=title,
+ description=description,
+ hosted_by=hosted_by,
+ # times_of_worship=times_of_worship,
+ website=website,
+ drupal_node_id=drupal_node_id,
+ drupal_body_migrated=drupal_body_migrated,
+ drupal_url_path=drupal_url_path,
+ online_worship_day=online_worship_day,
+ online_worship_time=online_worship_time,
+ online_worship_timezone=online_worship_timezone,
+ )
+
+ index_page.add_child(instance=online_worship_db)
+
+ return online_worship_db
+
+
+def handle_import_online_worship() -> None:
+ """Import news from Drupal."""
+ online_worship_items_data = parse_csv_file(
+ construct_import_file_path(file_key="online_worship"),
+ )
+ index_page = OnlineWorshipIndexPage.objects.get()
+
+ for online_worship_item_data in tqdm(
+ online_worship_items_data,
+ desc="Online worship items",
+ ):
+ try:
+ online_worship_db: OnlineWorship = handle_import_online_worship_item(
+ item=online_worship_item_data,
+ index_page=index_page,
+ )
+ except CouldNotFindMatchingContactError:
+ continue
+ except CouldNotParseAuthorIdError:
+ continue
+
+ create_permanent_redirect(
+ redirect_path=online_worship_item_data["url_path"],
+ redirect_entity=online_worship_db,
+ )
diff --git a/content_migration/management/shared.py b/content_migration/management/shared.py
index 5ad5a6371..79d44c584 100644
--- a/content_migration/management/shared.py
+++ b/content_migration/management/shared.py
@@ -152,7 +152,7 @@ def create_block(generic_block: GenericBlock) -> tuple[str, str | dict]:
if generic_block.block_type == "rich_text":
return (
generic_block.block_type,
- RichText(generic_block.block_content),
+ RichText(generic_block.block_content), # type: ignore
)
elif generic_block.block_type == "image":
try:
@@ -316,11 +316,12 @@ def create_media_embed_block(url: str) -> tuple[str, Embed]:
return embed_block
-# TODO: remove this function,
+# TODO: refactor this function to make it
+# less redundant with create_image_block
def create_image_block_from_file_bytes(
file_name: str,
file_bytes: BytesIO,
-) -> tuple[str, Image]:
+) -> tuple[str, dict]:
# create image
image_file: ImageFile = ImageFile(
file_bytes,
@@ -350,7 +351,7 @@ def create_image_block_from_file_bytes(
def extract_pullquotes(item: str) -> list[str]:
"""Get a list of all pullquote strings found within the item."""
- return re.findall(r"\[pullquote\](.+?)\[\/pullquote\]", item)
+ return re.findall(r"\[pullquote\](.+?)\[\/pullquote\]", item) # type: ignore
def fetch_file_bytes(url: str) -> FileBytesWithMimeType:
@@ -473,12 +474,16 @@ def get_existing_magazine_author_from_db(
results = list(chain(person, meeting, organization))
if len(results) == 0:
- raise CouldNotFindMatchingContactError()
+ error_message = f"Could not find matching author for magazine author ID: { int(drupal_author_id) }" # noqa: E501
+ logger.error(error_message)
+
+ raise CouldNotFindMatchingContactError(error_message)
elif len(results) > 1:
- logger.error(
+ error_message = (
f"Duplicate authors found for magazine author ID: { int(drupal_author_id) }"
)
- raise DuplicateContactError()
+ logger.error(error_message)
+ raise DuplicateContactError(error_message)
else:
return results[0]