uccser/cs-field-guide

View on GitHub
csfieldguide/chapters/management/commands/_ChaptersLoader.py

Summary

Maintainability
A
45 mins
Test Coverage
"""Custom loader for loading a chapter."""

import os.path
from django.db import transaction
from utils.TranslatableModelLoader import TranslatableModelLoader
from utils.errors.MissingRequiredFieldError import MissingRequiredFieldError
from utils.language_utils import get_default_language
from utils.check_required_files import check_interactives
from chapters.models import Chapter


class ChaptersLoader(TranslatableModelLoader):
    """Custom loader for loading chapters."""

    extra_converter_templates_directory = "chapter"

    def __init__(self, factory, chapter_number, **kwargs):
        """Create the loader for loading a Chapter.

        Args:
            factory (LoaderFactory): Object for creating other loaders.
        """
        super().__init__(**kwargs)
        self.factory = factory
        self.chapter_slug = self.content_path
        self.chapter_number = chapter_number

    @transaction.atomic
    def load(self):
        """Load the content for a chapter.

        Raises:
            MissingRequiredFieldError: When a config (yaml) file is missing a required
                field.
        """
        chapter_structure = self.load_yaml_file(self.structure_file_path)

        sections = chapter_structure.get("sections", None)
        if sections is None:
            raise MissingRequiredFieldError(
                self.structure_file_path,
                ["sections"],
                "Chapter"
            )

        chapter_translations = self.get_blank_translation_dictionary()

        introduction_filename = "{}.md".format(self.chapter_slug)
        introduction_translations = self.get_markdown_translations(introduction_filename)
        for language, content in introduction_translations.items():
            chapter_translations[language]["introduction"] = content.html_string
            chapter_translations[language]["name"] = content.title

        chapter_icon = chapter_structure.get("icon", None)
        if chapter_icon is None:
            raise MissingRequiredFieldError(
                self.structure_file_path,
                ["icon"],
                "Chapter"
            )
        else:
            # TODO: Check icon exists here before path modification
            # Remove directory and extension as svg templatetag automatically adds these
            chapter_icon = chapter_icon[4:-4]

        video = chapter_structure.get("video", "")
        if video != "" and "vimeo" not in video:
            raise ValueError("Video must be a Vimeo video.")

        # Create or update chapter object and save to the db
        chapter, created = Chapter.objects.update_or_create(
            number=self.chapter_number,
            defaults={
                'slug': self.chapter_slug,
                'icon': chapter_icon,
                'video': video
            }
        )

        self.populate_translations(chapter, chapter_translations)
        self.mark_translation_availability(chapter, required_fields=["name", "introduction"])
        chapter.save()

        if created:
            term = 'Created'
        else:
            term = 'Updated'
        self.log(f'{term} chapter: {chapter.name}')

        check_interactives(
            introduction_translations[get_default_language()].required_files["interactives"],
            self.structure_file_path,
            chapter,
        )

        # Load chapter sections
        content_path, structure_filename = os.path.split(sections)
        self.factory.create_chapter_section_loader(
            chapter,
            base_path=self.base_path,
            content_path=os.path.join(self.content_path, content_path),
            structure_filename=structure_filename
        ).load()