209 lines
12 KiB
Python
209 lines
12 KiB
Python
from django.conf import settings
|
|
from django.db import migrations, models
|
|
from django.db.models import Q
|
|
import django.db.models.deletion
|
|
|
|
import apps.content.current
|
|
|
|
|
|
def seo_fields():
|
|
return [
|
|
("seo_title", models.CharField(blank=True, max_length=120, verbose_name="SEO title")),
|
|
("seo_description", models.CharField(blank=True, max_length=300, verbose_name="SEO description")),
|
|
("seo_image", models.ImageField(blank=True, upload_to=apps.content.current.content_upload_path, verbose_name="Social sharing image")),
|
|
("seo_image_alt", models.CharField(blank=True, max_length=180, verbose_name="Social image description")),
|
|
]
|
|
|
|
|
|
def single_id():
|
|
return [("id", models.PositiveSmallIntegerField(default=1, editable=False, primary_key=True, serialize=False))]
|
|
|
|
|
|
def strings(*names):
|
|
return [(name, models.CharField(blank=True, max_length=length)) for name, length in names]
|
|
|
|
|
|
def image(name):
|
|
return (name, models.ImageField(blank=True, upload_to=apps.content.current.content_upload_path))
|
|
|
|
|
|
def copy_image(target, name, asset_id, alt, assets):
|
|
asset = assets.get(asset_id)
|
|
if asset:
|
|
setattr(target, name, asset.file.name)
|
|
setattr(target, f"{name}_alt", alt or asset.alt)
|
|
|
|
|
|
def populate_current_content(apps, schema_editor):
|
|
db = schema_editor.connection.alias
|
|
SiteContent = apps.get_model("content", "SiteContent")
|
|
HomeContent = apps.get_model("content", "HomeContent")
|
|
AboutContent = apps.get_model("content", "AboutContent")
|
|
AboutItem = apps.get_model("content", "AboutItem")
|
|
ListingContent = apps.get_model("content", "ListingContent")
|
|
SiteIdentity = apps.get_model("content", "SiteIdentity")
|
|
EditorialPage = apps.get_model("content", "EditorialPage")
|
|
MediaAsset = apps.get_model("content", "MediaAsset")
|
|
assets = {asset.pk: asset for asset in MediaAsset.objects.using(db).all()}
|
|
|
|
site = SiteContent(id=1)
|
|
identity = SiteIdentity.objects.using(db).filter(pk=1).first()
|
|
revision = identity.published_revision if identity and identity.published_revision_id else None
|
|
if revision:
|
|
for field in ("official_name", "short_name", "faculty_subline", "description", "footer_copy", "seo_title", "seo_description"):
|
|
setattr(site, field, getattr(revision, field))
|
|
copy_image(site, "logo", revision.logo_id, revision.logo_alt, assets)
|
|
copy_image(site, "seo_image", revision.seo_image_id, "Social sharing image", assets)
|
|
for nav in revision.navigation:
|
|
if nav.get("route_id") in ("home", "about", "events", "blog"):
|
|
setattr(site, f"nav_{nav['route_id']}", nav.get("label", ""))
|
|
for contact in revision.contacts:
|
|
kind, url = contact.get("kind"), contact.get("url", "")
|
|
if kind == "email":
|
|
site.email = url.removeprefix("mailto:")
|
|
elif kind == "phone":
|
|
site.phone = url.removeprefix("tel:")
|
|
elif kind in ("telegram", "instagram", "website"):
|
|
setattr(site, f"{kind}_url", url)
|
|
site.save(using=db)
|
|
|
|
pages = {page.slug: page for page in EditorialPage.objects.using(db).all()}
|
|
for slug, Model in (("home", HomeContent), ("about", AboutContent), ("events", ListingContent), ("blog", ListingContent)):
|
|
page = pages.get(slug)
|
|
revision = page.published_revision if page and page.published_revision_id else None
|
|
record = Model(id=1) if slug in ("home", "about") else Model(slug=slug)
|
|
if revision:
|
|
for field in ("title", "intro", "seo_title", "seo_description"):
|
|
setattr(record, field, getattr(revision, field))
|
|
copy_image(record, "seo_image", revision.seo_image_id, "Social sharing image", assets)
|
|
if slug in ("home", "about"):
|
|
sections = list(revision.sections.using(db).all())
|
|
for section in sections:
|
|
prefix = section.key
|
|
if slug == "home":
|
|
if prefix in ("hero", "participation"):
|
|
setattr(record, f"{prefix}_heading", section.heading)
|
|
setattr(record, f"{prefix}_body", section.body)
|
|
setattr(record, f"{prefix}_action_label", (section.primary_action or {}).get("label", ""))
|
|
copy_image(record, f"{prefix}_image", section.image_id, section.image_alt, assets)
|
|
elif prefix in ("featured_events", "featured_posts"):
|
|
setattr(record, f"{prefix}_heading", section.heading)
|
|
setattr(record, f"{prefix}_intro", section.intro)
|
|
setattr(record, f"{prefix}_link_label", section.all_link_label)
|
|
elif prefix in ("identity", "mission", "activities", "values", "committees", "affiliations", "faq", "contact"):
|
|
setattr(record, f"{prefix}_heading", section.heading)
|
|
if hasattr(record, f"{prefix}_body"):
|
|
setattr(record, f"{prefix}_body", section.body)
|
|
record.save(using=db)
|
|
if revision and slug == "about":
|
|
for section in sections:
|
|
if section.key in ("mission", "activities", "values", "committees", "affiliations", "faq"):
|
|
for position, entry in enumerate(section.entries):
|
|
AboutItem.objects.using(db).create(about_id=1, kind=section.key, title=entry["title"], text=entry["text"], position=position)
|
|
|
|
|
|
def preserve_editor_access(apps, schema_editor):
|
|
db = schema_editor.connection.alias
|
|
ContentType = apps.get_model("contenttypes", "ContentType")
|
|
Permission = apps.get_model("auth", "Permission")
|
|
Group = apps.get_model("auth", "Group")
|
|
User = apps.get_model(*settings.AUTH_USER_MODEL.split("."))
|
|
models_to_change = ("sitecontent", "homecontent", "aboutcontent", "aboutitem", "listingcontent")
|
|
new_permissions = []
|
|
for model in models_to_change:
|
|
content_type, _ = ContentType.objects.using(db).get_or_create(app_label="content", model=model)
|
|
permission, _ = Permission.objects.using(db).get_or_create(
|
|
content_type=content_type, codename=f"change_{model}", defaults={"name": f"Can change {model}"}
|
|
)
|
|
new_permissions.append(permission)
|
|
for group in Group.objects.using(db).filter(name__in=("content_editor", "content_publisher")):
|
|
group.permissions.add(*new_permissions)
|
|
old_permissions = Permission.objects.using(db).filter(
|
|
content_type__app_label="content", codename__in=("change_content_draft", "publish_content")
|
|
)
|
|
for user in User.objects.using(db).filter(user_permissions__in=old_permissions).distinct():
|
|
user.user_permissions.add(*new_permissions)
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
dependencies = [
|
|
("content", "0003_content_groups"),
|
|
("auth", "0012_alter_user_first_name_max_length"),
|
|
("contenttypes", "0002_remove_content_type_name"),
|
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
]
|
|
|
|
operations = [
|
|
migrations.CreateModel(
|
|
name="SiteContent",
|
|
fields=single_id() + seo_fields() + strings(
|
|
("official_name", 180), ("short_name", 80), ("faculty_subline", 140),
|
|
("logo_alt", 180), ("phone", 30), ("footer_copy", 300)
|
|
) + [
|
|
("description", models.TextField(blank=True)), image("logo"),
|
|
("nav_home", models.CharField(default="Home", max_length=80, verbose_name="Home navigation label")),
|
|
("nav_about", models.CharField(default="About", max_length=80, verbose_name="About navigation label")),
|
|
("nav_events", models.CharField(default="Events", max_length=80, verbose_name="Events navigation label")),
|
|
("nav_blog", models.CharField(default="Blog", max_length=80, verbose_name="Blog navigation label")),
|
|
("email", models.EmailField(blank=True, max_length=254)),
|
|
("telegram_url", models.URLField(blank=True)),
|
|
("instagram_url", models.URLField(blank=True)),
|
|
("website_url", models.URLField(blank=True)),
|
|
("address", models.TextField(blank=True)),
|
|
],
|
|
options={"verbose_name": "Site content"},
|
|
),
|
|
migrations.CreateModel(
|
|
name="HomeContent",
|
|
fields=single_id() + seo_fields() + strings(
|
|
("title", 180), ("hero_heading", 120), ("hero_image_alt", 180),
|
|
("hero_action_label", 40), ("featured_events_heading", 120),
|
|
("featured_events_intro", 300), ("featured_events_link_label", 40),
|
|
("featured_posts_heading", 120), ("featured_posts_intro", 300),
|
|
("featured_posts_link_label", 40), ("participation_heading", 120),
|
|
("participation_image_alt", 180), ("participation_action_label", 40)
|
|
) + [
|
|
("intro", models.TextField(blank=True)), ("hero_body", models.TextField(blank=True)),
|
|
image("hero_image"), ("participation_body", models.TextField(blank=True)),
|
|
image("participation_image"),
|
|
],
|
|
options={"verbose_name": "Home page content"},
|
|
),
|
|
migrations.CreateModel(
|
|
name="AboutContent",
|
|
fields=single_id() + seo_fields() + strings(
|
|
("title", 180), ("identity_heading", 120), ("mission_heading", 120),
|
|
("activities_heading", 120), ("values_heading", 120),
|
|
("committees_heading", 120), ("affiliations_heading", 120),
|
|
("contact_heading", 120)
|
|
) + [
|
|
("faq_heading", models.CharField(blank=True, max_length=120, verbose_name="FAQ heading")),
|
|
("intro", models.TextField(blank=True)),
|
|
*[(f"{name}_body", models.TextField(blank=True)) for name in ("identity", "mission", "activities", "values", "committees", "affiliations")],
|
|
],
|
|
options={"verbose_name": "About page content"},
|
|
),
|
|
migrations.CreateModel(
|
|
name="ListingContent",
|
|
fields=[("slug", models.CharField(choices=[("events", "Events"), ("blog", "Blog")], max_length=10, primary_key=True, serialize=False))]
|
|
+ seo_fields() + strings(("title", 180)) + [("intro", models.TextField(blank=True))],
|
|
options={"verbose_name": "Listing page content", "verbose_name_plural": "Listing page content"},
|
|
),
|
|
migrations.CreateModel(
|
|
name="AboutItem",
|
|
fields=[
|
|
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
|
("kind", models.CharField(choices=[(key, key.title()) for key in ("mission", "activities", "values", "committees", "affiliations", "faq")], max_length=20)),
|
|
("title", models.CharField(max_length=120)), ("text", models.TextField()),
|
|
("position", models.PositiveSmallIntegerField(default=0)),
|
|
("about", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name="items", to="content.aboutcontent")),
|
|
],
|
|
options={"verbose_name": "About page item", "ordering": ["kind", "position", "pk"]},
|
|
),
|
|
migrations.AddConstraint(model_name="sitecontent", constraint=models.CheckConstraint(condition=Q(id=1), name="content_current_single_site")),
|
|
migrations.AddConstraint(model_name="homecontent", constraint=models.CheckConstraint(condition=Q(id=1), name="content_current_single_home")),
|
|
migrations.AddConstraint(model_name="aboutcontent", constraint=models.CheckConstraint(condition=Q(id=1), name="content_current_single_about")),
|
|
migrations.RunPython(populate_current_content, migrations.RunPython.noop),
|
|
migrations.RunPython(preserve_editor_access, migrations.RunPython.noop),
|
|
]
|