Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#155 Integrate Wagtail Routing #395

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions cms/management/commands/setup_index_pages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"""Management command to setup courseware index pages"""
from django.core.management.base import BaseCommand
from wagtail.core.models import Site

from cms.models import CourseIndexPage, CoursePage, ProgramIndexPage, ProgramPage


class Command(BaseCommand):
"""Creates courseware index pages and moves the existing courseware pages under the index pages"""

help = "Creates courseware index pages and moves the existing courseware pages under the index pages"

def add_arguments(self, parser):
parser.add_argument(
"--revert",
action="store_true",
dest="revert",
help="Delete the index pages and move the courseware pages back under the homepage.",
)

def handle(self, *args, **options):
"""Handle command execution"""
delete = options["revert"]
site = Site.objects.filter(is_default_site=True).first()
if not site:
self.stderr.write(
self.style.ERROR(
"No default site setup. Please configure a default site before running this command."
)
)
exit(1)

home_page = site.root_page
if not home_page:
self.stderr.write(
self.style.ERROR(
"No root (home) page set up for default site. Please configure a root (home) page for the default site before running this command."
)
)
exit(1)

if not delete:
course_index = CourseIndexPage.objects.first()

if not course_index:
course_index = CourseIndexPage(title="Courses")
home_page.add_child(instance=course_index)
self.stdout.write(self.style.SUCCESS("Course index page created."))

for course_page in CoursePage.objects.all():
course_page.move(course_index, "last-child")

self.stdout.write(self.style.SUCCESS("Course pages moved under index."))
course_index.save_revision().publish()

program_index = ProgramIndexPage.objects.first()

if not program_index:
program_index = ProgramIndexPage(title="Programs")
home_page.add_child(instance=program_index)
self.stdout.write(self.style.SUCCESS("Program index page created."))

for program_page in ProgramPage.objects.all():
program_page.move(program_index, "last-child")

self.stdout.write(self.style.SUCCESS("Program pages moved under index."))
program_index.save_revision().publish()
else:
course_index = CourseIndexPage.objects.first()
if course_index:
for page in course_index.get_children():
page.move(home_page, "last-child")
self.stdout.write(
self.style.SUCCESS("Course pages moved under homepage.")
)

course_index.delete()
self.stdout.write(self.style.WARNING("Course index page removed."))

program_index = ProgramIndexPage.objects.first()
if program_index:
for page in program_index.get_children():
page.move(home_page, "last-child")
self.stdout.write(
self.style.SUCCESS("Program pages moved under homepage.")
)

program_index.delete()
self.stdout.write(self.style.WARNING("Program index page removed."))
52 changes: 52 additions & 0 deletions cms/migrations/0028_course_program_index_pages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Generated by Django 2.1.7 on 2019-05-28 12:40

import cms.models
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
("wagtailcore", "0041_group_collection_permissions_verbose_name_plural"),
("cms", "0027_imagecarouselpage"),
]

operations = [
migrations.CreateModel(
name="CourseIndexPage",
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",
),
)
],
options={"abstract": False},
bases=(cms.models.CourseObjectIndexPage, "wagtailcore.page"),
),
migrations.CreateModel(
name="ProgramIndexPage",
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",
),
)
],
options={"abstract": False},
bases=(cms.models.CourseObjectIndexPage, "wagtailcore.page"),
),
]
113 changes: 113 additions & 0 deletions cms/migrations/0029_setup_course_program_index_pages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
"""
Data migration to ensure the correct state for course/program index pages and
correct depth for course/program detail pages
"""
from django.db import migrations
from wagtail.core.models import Page

COURSE_INDEX_PAGE_PROPERTIES = dict(title="Courses")
PROGRAM_INDEX_PAGE_PROPERTIES = dict(title="Programs")


def delete_wagtail_pages(specific_page_cls, filter_dict=None):
"""
Completely deletes Wagtail CMS pages that match a filter. Wagtail overrides standard delete functionality,
making it difficult to actually delete Page objects and get information about what was deleted.
"""
page_ids_to_delete = specific_page_cls.objects.values_list("id", flat=True)
if filter_dict:
page_ids_to_delete = page_ids_to_delete.filter(**filter_dict)
num_pages = len(page_ids_to_delete)
base_pages_qset = Page.objects.filter(id__in=page_ids_to_delete)
if not base_pages_qset.exists():
return 0, {}
base_pages_qset.delete()
return (
num_pages,
{specific_page_cls._meta.label: num_pages}, # pylint: disable=protected-access
)


def get_home_page(apps):
"""
Importing the Site model from the registry means if we access the root page from this
model we will get an instance of the Page with only the basic model methods so we simply extract
the ID of the page and hand it to the Page model imported directly.
"""
Site = apps.get_model("wagtailcore", "Site")
site = Site.objects.filter(is_default_site=True).first()
if not site:
raise Exception(
"A default site is not set up. Please setup a default site before running this migration"
)
if not site.root_page:
raise Exception(
"No root (home) page set up. Please setup a root (home) page for the default site before running this migration"
)
return Page.objects.get(id=site.root_page.id)


def create_index_pages_and_nest_detail(apps, schema_editor):
"""
Create index pages for courses and programs and move the respective
course and program pages under these index pages.
"""
from cms.models import CourseIndexPage, ProgramIndexPage

CoursePage = apps.get_model("cms", "CoursePage")
ProgramPage = apps.get_model("cms", "ProgramPage")

# Home page
home_page = get_home_page(apps)

course_index = CourseIndexPage.objects.first()
if not course_index:
page_obj = CourseIndexPage(**COURSE_INDEX_PAGE_PROPERTIES)
course_index = home_page.add_child(instance=page_obj)
program_index = ProgramIndexPage.objects.first()
if not program_index:
page_obj = ProgramIndexPage(**PROGRAM_INDEX_PAGE_PROPERTIES)
program_index = home_page.add_child(instance=page_obj)
# Move course/program detail pages to be children of the course/program index pages
for page_id in CoursePage.objects.values_list("id", flat=True):
page = Page.objects.get(id=page_id)
page.move(course_index, "last-child")
for page_id in ProgramPage.objects.values_list("id", flat=True):
page = Page.objects.get(id=page_id)
page.move(program_index, "last-child")


def unnest_detail_and_delete_index_pages(apps, schema_editor):
"""
Move course and program pages under the home page and remove index pages.
"""
CourseIndexPage = apps.get_model("cms", "CourseIndexPage")
ProgramIndexPage = apps.get_model("cms", "ProgramIndexPage")
CoursePage = apps.get_model("cms", "CoursePage")
ProgramPage = apps.get_model("cms", "ProgramPage")

# Move course/program detail pages to be children of the home page
home_page = get_home_page(apps)
top_level_child_ids = [child.id for child in home_page.get_children()]
for page_id in CoursePage.objects.values_list("id", flat=True):
if page_id not in top_level_child_ids:
page = Page.objects.get(id=page_id)
page.move(home_page, "last-child")
for page_id in ProgramPage.objects.values_list("id", flat=True):
if page_id not in top_level_child_ids:
page = Page.objects.get(id=page_id)
page.move(home_page, "last-child")
# Remove the course/program index pages
delete_wagtail_pages(ProgramIndexPage)
delete_wagtail_pages(CourseIndexPage)


class Migration(migrations.Migration):

dependencies = [("cms", "0028_course_program_index_pages")]

operations = [
migrations.RunPython(
create_index_pages_and_nest_detail, unnest_detail_and_delete_index_pages
)
]
Loading