コード例 #1
0
 def test_string_single_field(self):
     exception = MissingRequiredFieldError("config file path", ["field1"],
                                           "model")
     expected_string = (
         "\n****************************ERROR****************************\n"
         "File: config file path\n\n"
         "A model requires the following field:\n"
         "  - field1\n\n"
         "For the missing field:\n"
         "  - Is the field name spelt correctly?\n"
         "  - Does the field have the correct value?\n")
     self.assertEqual(exception.__str__(), expected_string)
コード例 #2
0
    def handle(self, *args, **options):
        """Automatically called when the loadchapters command is given."""
        factory = LoaderFactory()

        # Get structure and content files
        base_loader = BaseLoader()
        base_path = settings.CHAPTERS_CONTENT_BASE_PATH

        structure_file_path = os.path.join(base_path,
                                           base_loader.structure_dir,
                                           "structure.yaml")

        structure_file = base_loader.load_yaml_file(structure_file_path)

        if "glossary-folder" in structure_file:
            glossary_directory = structure_file["glossary-folder"]
            if glossary_directory is not None:
                factory.create_glossary_terms_loader(
                    base_path=base_path,
                    content_path=glossary_directory,
                ).load()

        chapters = structure_file.get("chapters", None)
        if chapters is None:
            raise MissingRequiredFieldError(structure_file_path, ["chapters"],
                                            "Application Structure")
        else:
            for chapter_slug in chapters:
                chapter_structure_file = "{}.yaml".format(chapter_slug)

                chapter_number = chapters[chapter_slug].get(
                    "chapter-number", None)
                if chapter_number is None:
                    raise MissingRequiredFieldError(
                        structure_file_path, ["chapter_number"],
                        "Application Structure for Chapter {}".format(
                            chapter_slug))
                if isinstance(chapter_number, int) is False:
                    raise InvalidYAMLValueError(
                        structure_file_path,
                        "chapter-number - value '{}' is invalid".format(
                            chapter_number),
                        "chapter-number must be an integer value.")
                factory.create_chapter_loader(
                    base_path=base_path,
                    content_path=chapter_slug,
                    chapter_number=chapter_number,
                    structure_filename=chapter_structure_file,
                ).load()

            base_loader.log("All chapters loaded!")
            base_loader.log("")
コード例 #3
0
    def load(self):
        """Load the content for resources.

        Raise:
            MissingRequiredFieldError: when no object can be found with the matching
                attribute.
        """
        resources_structure = self.load_yaml_file(self.structure_file_path)

        for (resource_slug, resource_structure) in resources_structure.items():
            try:
                generator_module = resource_structure["generator-module"]
                resource_thumbnail = resource_structure[
                    "thumbnail-static-path"]
                resource_copies = resource_structure["copies"]
            except KeyError:
                raise MissingRequiredFieldError(
                    self.structure_file_path,
                    ["generator-module", "thumbnail-static-path", "copies"],
                    "Resource")
            resource_translations = self.get_blank_translation_dictionary()
            content_filename = "{}.md".format(resource_slug)
            content_translations = self.get_markdown_translations(
                content_filename)
            for language, content in content_translations.items():
                resource_translations[language][
                    "content"] = content.html_string
                resource_translations[language]["name"] = content.title

            # Remove .py extension if given
            if generator_module.endswith(".py"):
                generator_module = generator_module[:-3]

            # Check module can be imported
            get_resource_generator(generator_module, QueryDict())

            # Check thumbnail exists
            if not finders.find(resource_thumbnail):
                error_text = "Thumbnail image {} for resource {} could not be found."
                raise FileNotFoundError(
                    error_text.format(resource_thumbnail, resource_slug))

            # Check copies value is boolean
            if not isinstance(resource_copies, bool):
                raise InvalidYAMLValueError(self.structure_file_path, "copies",
                                            "'true' or 'false'")

            resource = Resource(
                slug=resource_slug,
                generator_module=generator_module,
                thumbnail_static_path=resource_thumbnail,
                copies=resource_copies,
            )
            self.populate_translations(resource, resource_translations)
            self.mark_translation_availability(
                resource, required_fields=["name", "content"])
            resource.save()

            self.log("Added Resource: {}".format(resource.name))
        self.log("All resources loaded!\n")
コード例 #4
0
    def check_template(self, page_data, type):
        """Check template in page_data is valid.

        Args:
            page_data (dict): Dictionary of page data.
            type (str): Name of type of page.

        Returns:
            A valid template as string.

        Raises:
            MissingRequiredFieldError: If template value not given.
            InvalidYAMLValueError: If invalid template path given.
        """
        try:
            template = page_data["template"]
        except (TypeError, KeyError):
            raise MissingRequiredFieldError(self.structure_file_path, [
                "template",
            ], type)
        try:
            get_template(template)
        except TemplateDoesNotExist:
            raise InvalidYAMLValueError(self.structure_file_path,
                                        "template ({})".format(template),
                                        "A valid template file path")
        return template
コード例 #5
0
    def load(self):
        """Load the content for resources.

        Raise:
            MissingRequiredFieldError: when no object can be found with the matching
                attribute.
        """
        resources_structure = self.load_yaml_file(
            self.BASE_PATH.format(self.structure_file))

        for (resource_slug, resource_structure) in resources_structure.items():
            try:
                resource_name = resource_structure["name"]
                resource_template = resource_structure["webpage-template"]
                resource_view = resource_structure["generation-view"]
                resource_thumbnail = resource_structure[
                    "thumbnail-static-path"]
                resource_copies = resource_structure["copies"]
            except:
                raise MissingRequiredFieldError()

            resource = Resource(
                slug=resource_slug,
                name=resource_name,
                webpage_template=resource_template,
                generation_view=resource_view,
                thumbnail_static_path=resource_thumbnail,
                copies=resource_copies,
            )
            resource.save()

            self.log("Added Resource: {}".format(resource.name))
        self.log("All resources loaded!\n")
コード例 #6
0
    def load(self):
        """Load Classic CS Unplugged pages.

        Raise:
            MissingRequiredFieldError: when no object can be found with the matching
                attribute.
        """
        classic_pages = self.load_yaml_file(self.structure_file_path)

        for (slug, page_data) in classic_pages.items():
            try:
                name = page_data["name"]
            except (TypeError, KeyError):
                raise MissingRequiredFieldError(
                    self.structure_file_path,
                    [
                        "name",
                    ],
                    "Classic CS Unplugged page"
                )

            redirect_url = urljoin("https://classic.csunplugged.org/", slug)

            classic_page = ClassicPage(
                slug=slug,
                name=name,
                redirect=redirect_url,
            )
            classic_page.save()
            self.log("Added Classic CS Unplugged page: {}".format(name))
        self.log("All Classic CS Unplugged pages loaded!\n")
コード例 #7
0
    def handle(self, *args, **options):
        """Automatically called when the loadcurriculumguides command is given."""
        factory = LoaderFactory()

        # Get structure and content files
        base_loader = BaseLoader()
        base_path = settings.CURRICULUM_GUIDES_CONTENT_BASE_PATH

        structure_file_path = os.path.join(base_path,
                                           base_loader.structure_dir,
                                           "structure.yaml")

        structure_file = base_loader.load_yaml_file(structure_file_path)

        curriculum_guides = structure_file.get("curriculum_guides", None)
        if curriculum_guides is None:
            raise MissingRequiredFieldError(structure_file_path,
                                            ["curriculum_guides"],
                                            "Application Structure")
        else:
            for curriculum_guide_slug in curriculum_guides:
                curriculum_guide_structure_file = "{}.yaml".format(
                    curriculum_guide_slug)

                curriculum_guide_number = curriculum_guides[
                    curriculum_guide_slug].get("curriculum-guide-number", None)
                if curriculum_guide_number is None:
                    raise MissingRequiredFieldError(
                        structure_file_path, ["curriculum_guide_number"],
                        "Application Structure for Curriculum Guide {}".format(
                            curriculum_guide_slug))
                if isinstance(curriculum_guide_number, int) is False:
                    raise InvalidYAMLValueError(
                        structure_file_path,
                        "curriculum-guide-number - value '{}' is invalid".
                        format(curriculum_guide_number),
                        "curriculum-guide-number must be an integer value.")
                factory.create_curriculum_guide_loader(
                    base_path=base_path,
                    content_path=curriculum_guide_slug,
                    curriculum_guide_number=curriculum_guide_number,
                    structure_filename=curriculum_guide_structure_file,
                ).load()

            base_loader.log("All curriculum guides loaded!")
            base_loader.log("")
コード例 #8
0
    def load(self):
        """Load the content for age groups.

        Raise:
            MissingRequiredFieldError: when no object can be found with the
                matching attribute.
        """
        age_groups_structure = self.load_yaml_file(self.structure_file_path)

        # Use same name as structure file for translations
        age_groups_translations = self.get_yaml_translations(
            self.structure_filename)

        for (age_group_slug, age_group_data) in age_groups_structure.items():
            if age_group_data is None:
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["min_age", "max_age"],
                                                "Age Range")

            translations = age_groups_translations.get(age_group_slug, dict())

            group_min_age = age_group_data.get("min_age", None)
            if group_min_age is None:
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["min_age"], "Age Range")

            group_max_age = age_group_data.get("max_age", None)
            if group_max_age is None:
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["max_age"], "Age Range")

            # Create area objects and save to database
            age_group = AgeGroup(
                slug=age_group_slug,
                ages=(int(group_min_age), int(group_max_age)),
            )
            self.populate_translations(age_group, translations)
            self.mark_translation_availability(age_group,
                                               required_fields=["description"])
            age_group.save()

            self.log("Added age group: {}".format(age_group.__str__()))

        self.log("All age groups loaded!\n")
コード例 #9
0
    def load(self):
        """Load the content for resources.

        Raise:
            MissingRequiredFieldError: when no object can be found with the matching
                attribute.
        """
        resources_structure = self.load_yaml_file(self.structure_file_path)

        for (resource_slug, resource_structure) in resources_structure.items():
            try:
                resource_name = resource_structure["name"]
                resource_template = resource_structure["webpage-template"]
                generator_module = resource_structure["generator-module"]
                resource_thumbnail = resource_structure[
                    "thumbnail-static-path"]
                resource_copies = resource_structure["copies"]
            except KeyError:
                raise MissingRequiredFieldError(self.structure_file_path, [
                    "name", "webpage-template", "generator-module",
                    "thumbnail-static-path", "copies"
                ], "Resource")

            # Check resource template file exists
            open(os.path.join("templates", resource_template),
                 encoding="UTF-8")

            # Remove .py extension if given
            if generator_module.endswith(".py"):
                generator_module = generator_module[:-3]

            # Check module can be imported
            get_resource_generator(generator_module, QueryDict())

            # Check thumbnail exists
            if not finders.find(resource_thumbnail):
                raise FileNotFoundError

            # Check copies value is boolean
            if not isinstance(resource_copies, bool):
                raise InvalidConfigValueError(self.structure_file_path,
                                              "copies", "'true' or 'false'")

            resource = Resource(
                slug=resource_slug,
                name=resource_name,
                webpage_template=resource_template,
                generator_module=generator_module,
                thumbnail_static_path=resource_thumbnail,
                copies=resource_copies,
            )
            resource.save()

            self.log("Added Resource: {}".format(resource.name))
        self.log("All resources loaded!\n")
コード例 #10
0
    def load(self):
        """Load the content for age groups.

        Raise:
            MissingRequiredFieldError: when no object can be found with the
                matching attribute.
        """
        age_groups_structure = self.load_yaml_file(
            os.path.join(self.BASE_PATH, self.structure_file_path))

        for (age_group_slug, age_group_data) in age_groups_structure.items():

            if age_group_data is None:
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["min_age", "max_age"],
                                                "Age Range")

            group_min_age = age_group_data.get("min_age", None)
            if group_min_age is None:
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["min_age"], "Age Range")

            group_max_age = age_group_data.get("max_age", None)
            if group_max_age is None:
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["max_age"], "Age Range")

            group_description = age_group_data.get("description", None)

            # Create area objects and save to database
            age_group = AgeGroup(
                slug=age_group_slug,
                ages=(int(group_min_age), int(group_max_age)),
                description=group_description,
            )
            age_group.save()

            self.log("Added age group: {}".format(age_group.__str__()))

        self.log("All age groups loaded!\n")
コード例 #11
0
    def load(self):
        """Load the content for a curriculum guide.

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

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

        curriculum_guide_translations = self.get_blank_translation_dictionary()

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

        # Create curriculum guide object and save to the db
        curriculum_guide = CurriculumGuide(
            slug=self.curriculum_guide_slug,
            number=self.curriculum_guide_number,
        )

        self.populate_translations(curriculum_guide,
                                   curriculum_guide_translations)
        self.mark_translation_availability(
            curriculum_guide, required_fields=["name", "introduction"])
        curriculum_guide.save()

        self.log("Added curriculum guide: {}".format(curriculum_guide.name))

        # Load curriculum guide sections
        content_path, structure_filename = os.path.split(sections)
        self.factory.create_curriculum_guide_section_loader(
            curriculum_guide,
            base_path=self.base_path,
            content_path=os.path.join(self.content_path, content_path),
            structure_filename=structure_filename).load()
コード例 #12
0
    def load(self):
        """Load general pages.

        Raise:
            MissingRequiredFieldError: when no object can be found with the matching
                attribute.
        """
        general_pages = self.load_yaml_file(self.structure_file_path)

        for (slug, page_data) in general_pages.items():
            try:
                name = page_data["name"]
                template = page_data["template"]
                url_name = page_data["url-name"]
            except (TypeError, KeyError):
                raise MissingRequiredFieldError(self.structure_file_path, [
                    "name",
                    "template",
                    "url-name",
                ], "General page")

            # Check template is valid
            try:
                get_template(template)
            except TemplateDoesNotExist:
                raise InvalidYAMLValueError(self.structure_file_path,
                                            "template",
                                            "A valid template file path")

            # Check URL name is valid
            try:
                reverse(url_name)
            except NoReverseMatch:
                raise InvalidYAMLValueError(
                    self.structure_file_path, "url-name",
                    "A URL name listed in 'csunplugged/general/urls.py'")

            general_page = GeneralPage(
                slug=slug,
                name=name,
                template=template,
                url_name=url_name,
            )
            general_page.save()
            self.log("Added general page: {}".format(name))
        self.log("All general pages loaded!\n")
コード例 #13
0
    def handle(self, *args, **options):
        """Automatically called when the loadactivities command is given.

        Raise:
            MissingRequiredFieldError: when no object can be found with the matching
                attribute.
        """
        lite_load = options.get("lite_load")
        factory = LoaderFactory()

        # Get structure and content files
        base_loader = BaseLoader()
        base_path = settings.ACTIVITIES_CONTENT_BASE_PATH

        structure_file_path = os.path.join(base_path,
                                           base_loader.structure_dir,
                                           "activities.yaml")

        structure_file = base_loader.load_yaml_file(structure_file_path)

        if structure_file.get("activities", None) is None or not isinstance(
                structure_file["activities"], dict):
            raise MissingRequiredFieldError(structure_file_path,
                                            ["activities"], "At Home")
        else:
            for activity_slug, activity_data in structure_file[
                    "activities"].items():
                activity_path = activity_slug
                activity_structure_file = "{}.yaml".format(activity_slug)
                factory.create_activity_loader(
                    base_path=base_path,
                    content_path=activity_path,
                    structure_filename=activity_structure_file,
                    lite_loader=lite_load,
                    activity_data=activity_data,
                ).load()
コード例 #14
0
    def load(self):
        """Load the content for learning outcomes.

        Raise:
            MissingRequiredFieldError: when no object can be found with the matching
                attribute.
        """
        learning_outcomes = self.load_yaml_file(
            os.path.join(self.BASE_PATH, self.structure_file_path))

        for (outcome_slug, outcome_data) in learning_outcomes.items():

            if ("text" not in outcome_data) or (outcome_data["text"] is None):
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["text"], "Learning Outcome")

            # Create outcome objects and save to db
            outcome = LearningOutcome(slug=outcome_slug,
                                      text=outcome_data["text"])
            outcome.save()

            # Add curriculum areas
            curriculum_area_slugs = outcome_data.get("curriculum-areas", [])
            for curriculum_area_slug in curriculum_area_slugs:
                try:
                    curriculum_area = CurriculumArea.objects.get(
                        slug=curriculum_area_slug)
                    outcome.curriculum_areas.add(curriculum_area)
                except:
                    raise KeyNotFoundError(self.structure_file_path,
                                           curriculum_area_slug,
                                           "Curriculum Areas")

            self.log("Added learning outcome: {}".format(outcome.__str__()))

        self.log("All learning outcomes loaded!\n")
コード例 #15
0
    def load(self):
        """Load the content for a single lesson.

        Raises:
            KeyNotFoundError: when no object can be found with the matching attribute.
            InvalidConfigValueError: when provided value is not valid.
            MissingRequiredFieldError: when a value for a required model field cannot be
                found in the config file.
        """
        lessons_structure = self.load_yaml_file(
            self.lessons_structure_file_path)

        for (lesson_slug, lesson_structure) in lessons_structure.items():

            if lesson_structure is None:
                raise MissingRequiredFieldError(
                    self.lessons_structure_file_path, ["number"], "Lesson")

            # Build the file path to the lesson"s md file
            file_path = os.path.join(self.BASE_PATH, "lessons",
                                     "{}.md".format(lesson_slug))

            lesson_content = self.convert_md_file(
                file_path,
                self.lessons_structure_file_path,
            )

            if "computational-thinking-links" in lesson_structure:
                file_name = lesson_structure["computational-thinking-links"]
                file_path = os.path.join(self.BASE_PATH, "lessons", file_name)
                ct_links_content = self.convert_md_file(
                    file_path,
                    self.lessons_structure_file_path,
                    heading_required=False,
                    remove_title=False,
                )
                ct_links = ct_links_content.html_string
            else:
                ct_links = None

            if "duration" in lesson_structure:
                lesson_duration = lesson_structure["duration"]
            else:
                lesson_duration = None

            heading_tree = None
            if lesson_content.heading_tree:
                heading_tree = convert_heading_tree_to_dict(
                    lesson_content.heading_tree)

            if "programming-challenges-description" in lesson_structure:
                file_name = lesson_structure[
                    "programming-challenges-description"]
                file_path = os.path.join(self.BASE_PATH, "lessons", file_name)
                programming_description_content = self.convert_md_file(
                    file_path,
                    self.lessons_structure_file_path,
                    heading_required=False,
                    remove_title=False,
                )
                programming_description = programming_description_content.html_string
            else:
                programming_description = None

            classroom_resources = lesson_structure.get("classroom-resources",
                                                       None)
            if isinstance(classroom_resources, list):
                for classroom_resource in classroom_resources:
                    if not isinstance(classroom_resource, str):
                        raise InvalidConfigValueError(
                            self.lessons_structure_file_path,
                            "classroom-resources list item",
                            "A string describing the classroom resource.")
                    elif len(classroom_resource) > 100:
                        raise InvalidConfigValueError(
                            self.lessons_structure_file_path,
                            "classroom-resources list item",
                            "Item description must be less than 100 characters."
                        )
            elif classroom_resources is not None:
                raise InvalidConfigValueError(self.lessons_structure_file_path,
                                              "classroom-resources",
                                              "List of strings.")

            lesson = self.topic.lessons.create(
                unit_plan=self.unit_plan,
                slug=lesson_slug,
                name=lesson_content.title,
                duration=lesson_duration,
                content=lesson_content.html_string,
                computational_thinking_links=ct_links,
                heading_tree=heading_tree,
                programming_challenges_description=programming_description,
                classroom_resources=classroom_resources,
            )
            lesson.save()

            # Add programming challenges
            if "programming-challenges" in lesson_structure:
                programming_challenge_slugs = lesson_structure[
                    "programming-challenges"]
                if programming_challenge_slugs is not None:
                    # Check all slugs are valid
                    for programming_challenge_slug in programming_challenge_slugs:
                        try:
                            ProgrammingChallenge.objects.get(
                                slug=programming_challenge_slug,
                                topic=self.topic)

                        except:
                            raise KeyNotFoundError(
                                self.lessons_structure_file_path,
                                programming_challenge_slug,
                                "Programming Challenges")

                    # Store number of challenge in relationship with lesson.
                    # If three linked challenges have numbers 1.1, 4.2, and 4.5
                    # They will be stored as 1.1, 2.1, and 2.2 respectively.

                    # Order challenges for numbering.
                    programming_challenges = ProgrammingChallenge.objects.filter(
                        slug__in=programming_challenge_slugs,
                        topic=self.topic).order_by("challenge_set_number",
                                                   "challenge_number")

                    # Setup variables for numbering.
                    display_set_number = 0
                    last_set_number = -1
                    display_number = 0
                    last_number = -1

                    # For each challenge, increment number variables if original
                    # numbers are different.
                    for programming_challenge in programming_challenges:
                        if programming_challenge.challenge_set_number > last_set_number:
                            display_set_number += 1
                            display_number = 0
                            last_number = -1
                        if programming_challenge.challenge_number > last_number:
                            display_number += 1
                        last_set_number = programming_challenge.challenge_set_number
                        last_number = programming_challenge.challenge_number

                        # Create and save relationship between lesson and
                        # challenge that contains challenge number.
                        relationship = ProgrammingChallengeNumber(
                            programming_challenge=programming_challenge,
                            lesson=lesson,
                            challenge_set_number=display_set_number,
                            challenge_number=display_number,
                        )
                        relationship.save()

            # Add learning outcomes
            if "learning-outcomes" in lesson_structure:
                learning_outcome_slugs = lesson_structure["learning-outcomes"]
                if learning_outcome_slugs is not None:
                    for learning_outcome_slug in learning_outcome_slugs:
                        try:
                            learning_outcome = LearningOutcome.objects.get(
                                slug=learning_outcome_slug)
                            lesson.learning_outcomes.add(learning_outcome)
                        except:
                            raise KeyNotFoundError(
                                self.lessons_structure_file_path,
                                learning_outcome_slug, "Learning Outcomes")

            # Add generated resources
            if "generated-resources" in lesson_structure:
                resources = lesson_structure["generated-resources"]
                if resources is not None:
                    for (resource_slug, resource_data) in resources.items():
                        if resource_data is None:
                            raise MissingRequiredFieldError(
                                self.lessons_structure_file_path,
                                ["description"], "Generated Resource")
                        try:
                            resource = Resource.objects.get(slug=resource_slug)
                        except:
                            raise KeyNotFoundError(
                                self.lessons_structure_file_path,
                                resource_slug, "Resources")
                        resource_description = resource_data.get(
                            "description", None)
                        if resource_description is None:
                            raise MissingRequiredFieldError(
                                self.lessons_structure_file_path,
                                ["description"], "Generated Resource")

                        relationship = ResourceDescription(
                            resource=resource,
                            lesson=lesson,
                            description=resource_description)
                        relationship.save()

            self.log("Added lesson: {}".format(lesson.__str__()), 2)
コード例 #16
0
    def load(self):
        """Load the content for unit plans.

        Raise:
            KeyNotFoundError: when no object can be found with the matching attribute.
            MissingRequiredFieldError: when a value for a required model field cannot
                be found in the config file.
        """
        unit_plan_structure = self.load_yaml_file(self.structure_file_path)

        unit_plan_translations = self.get_blank_translation_dictionary()

        content_filename = "{}.md".format(self.unit_plan_slug)
        content_translations = self.get_markdown_translations(content_filename)
        for language, content in content_translations.items():
            unit_plan_translations[language]["content"] = content.html_string
            unit_plan_translations[language]["name"] = content.title
            if content.heading_tree:
                heading_tree = convert_heading_tree_to_dict(
                    content.heading_tree)
                unit_plan_translations[language]["heading_tree"] = heading_tree

        if "computational-thinking-links" in unit_plan_structure:
            ct_links_filename = unit_plan_structure[
                "computational-thinking-links"]
            ct_links_translations = self.get_markdown_translations(
                ct_links_filename,
                heading_required=False,
                remove_title=False,
            )
            for language, content in ct_links_translations.items():
                unit_plan_translations[language][
                    "computational_thinking_links"] = content.html_string

        unit_plan = self.topic.unit_plans.create(
            slug=self.unit_plan_slug,
            languages=list(content_translations.keys()),
        )

        self.populate_translations(unit_plan, unit_plan_translations)
        self.mark_translation_availability(unit_plan,
                                           required_fields=["name", "content"])

        unit_plan.save()

        self.log("Added unit plan: {}".format(unit_plan.name), 1)

        # Load the lessons for the unit plan
        # Get path to lesson yaml
        lessons_yaml = unit_plan_structure.get("lessons", None)
        if lessons_yaml is None:
            raise MissingRequiredFieldError(self.structure_file_path,
                                            ["lessons", "age-groups"],
                                            "Unit Plan")

        lesson_path, lesson_structure_file = os.path.split(lessons_yaml)

        # Call the loader to save the lessons into the db
        self.factory.create_lessons_loader(
            self.topic,
            unit_plan,
            content_path=os.path.join(self.content_path, lesson_path),
            structure_filename=lesson_structure_file,
            base_path=self.base_path,
        ).load()

        # Create AgeGroup and assign to lessons
        age_groups = unit_plan_structure.get("age-groups", None)
        if age_groups is None:
            raise MissingRequiredFieldError(self.structure_file_path,
                                            ["lessons", "age-groups"],
                                            "Unit Plan")

        for (age_group_slug, age_group_data) in age_groups.items():

            try:
                age_group = AgeGroup.objects.get(slug=age_group_slug)
            except ObjectDoesNotExist:
                raise KeyNotFoundError(self.structure_file_path,
                                       age_group_slug, "Age Range")

            if age_group_data is None:
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["lesson keys"], "Unit Plan")

            for (lesson_slug, lesson_data) in age_group_data.items():
                try:
                    lesson = Lesson.objects.get(slug=lesson_slug)
                except ObjectDoesNotExist:
                    raise KeyNotFoundError(self.structure_file_path,
                                           lesson_slug, "Lesson")

                if lesson_data is None or lesson_data.get("number",
                                                          None) is None:
                    raise MissingRequiredFieldError(self.structure_file_path,
                                                    ["number"], "Unit Plan")
                else:
                    lesson_number = lesson_data.get("number", None)

                relationship = LessonNumber(
                    age_group=age_group,
                    lesson=lesson,
                    number=lesson_number,
                )
                relationship.save()
コード例 #17
0
    def load(self):
        """Load the content for programming challenges.

        Raises:
            CouldNotFindMarkdownFileError: when no file can be found with the provided filename.
            KeyNotFoundError: when no object can be found with the matching attribute.
            MissingRequiredFieldError: when no object can be found with the matching
                attribute.
        """
        programming_challenges_structure = self.load_yaml_file(self.structure_file_path)

        for (challenge_slug, challenge_structure) in programming_challenges_structure.items():

            if challenge_structure is None:
                raise MissingRequiredFieldError(
                    self.structure_file_path,
                    ["challenge-set-number", "challenge-number",
                        "programming-languages", "difficulty-level"],
                    "Programming Challenge"
                )

            # Retrieve required variables from md file
            challenge_set_number = challenge_structure.get("challenge-set-number", None)
            challenge_number = challenge_structure.get("challenge-number", None)
            challenge_languages = challenge_structure.get("programming-languages", None)
            challenge_difficulty = challenge_structure.get("difficulty-level", None)
            if None in [challenge_set_number, challenge_number, challenge_languages, challenge_difficulty]:
                raise MissingRequiredFieldError(
                    self.structure_file_path,
                    ["challenge-set-number", "challenge-number",
                        "programming-languages", "difficulty-level"],
                    "Programming Challenge"
                )

            # Build the path to the programming challenge's folder
            file_path = os.path.join(
                self.BASE_PATH,
                challenge_slug,
                "{}.md"
            )

            challenge_content = self.convert_md_file(
                file_path.format(challenge_slug),
                self.structure_file_path
            )

            challenge_extra_challenge_file = challenge_structure.get("extra-challenge", None)
            if challenge_extra_challenge_file:
                challenge_extra_challenge_content = self.convert_md_file(
                    file_path.format(challenge_extra_challenge_file[:-3]),
                    self.structure_file_path,
                    heading_required=False,
                )
                challenge_extra_challenge = challenge_extra_challenge_content.html_string
            else:
                challenge_extra_challenge = None

            try:
                difficulty_level = ProgrammingChallengeDifficulty.objects.get(
                    level=challenge_difficulty
                )
            except:
                raise KeyNotFoundError(
                    self.structure_file_path,
                    challenge_difficulty,
                    "Programming Challenge Difficulty"
                )

            programming_challenge = self.topic.programming_challenges.create(
                slug=challenge_slug,
                name=challenge_content.title,
                challenge_set_number=challenge_set_number,
                challenge_number=challenge_number,
                content=challenge_content.html_string,
                extra_challenge=challenge_extra_challenge,
                difficulty=difficulty_level
            )
            programming_challenge.save()

            LOG_TEMPLATE = "Added programming challenge: {}"
            self.log(LOG_TEMPLATE.format(programming_challenge.name), 1)

            for language in challenge_languages:
                if language is None:
                    raise MissingRequiredFieldError(
                        self.structure_file_path,
                        ["challenge-set-number", "challenge-number",
                            "programming-languages", "difficulty-level"],
                        "Programming Challenge"
                    )
                try:
                    language_object = ProgrammingChallengeLanguage.objects.get(
                        slug=language
                    )
                except:
                    raise KeyNotFoundError(
                        self.structure_file_path,
                        language,
                        "Programming Challenge Language"
                    )

                expected_result_content = self.convert_md_file(
                    file_path.format(
                        "{}-expected".format(language)
                    ),
                    self.structure_file_path,
                    heading_required=False
                )

                # Load example solution
                solution_content = self.convert_md_file(
                    file_path.format(
                        "{}-solution".format(language)
                    ),
                    self.structure_file_path,
                    heading_required=False
                )

                # Load hint if given
                try:
                    hint_content = self.convert_md_file(
                        file_path.format(
                            "{}-hints".format(language)
                        ),
                        self.structure_file_path,
                        heading_required=False
                    )
                except CouldNotFindMarkdownFileError:
                    hint_content = None

                implementation = ProgrammingChallengeImplementation(
                    expected_result=expected_result_content.html_string,
                    hints=None if hint_content is None else hint_content.html_string,
                    solution=solution_content.html_string,
                    language=language_object,
                    challenge=programming_challenge,
                    topic=self.topic
                )
                implementation.save()

                LOG_TEMPLATE = "Added language implementation: {}"
                self.log(LOG_TEMPLATE.format(implementation.language), 2)

            if "learning-outcomes" in challenge_structure:
                learning_outcomes = challenge_structure["learning-outcomes"]
                if learning_outcomes is not None:
                    for learning_outcome_slug in learning_outcomes:
                        try:
                            learning_outcome = LearningOutcome.objects.get(
                                slug=learning_outcome_slug
                            )
                            programming_challenge.learning_outcomes.add(learning_outcome)
                        except:
                            raise KeyNotFoundError(
                                self.structure_file_path,
                                learning_outcome_slug,
                                "Learning Outcome")
コード例 #18
0
    def load(self):
        """Load the content for a section.

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

        for (section_slug, section_structure) in chapter_sections_structure.items():

            if section_structure is None:
                raise MissingRequiredFieldError(
                    self.structure_file_path,
                    ["section-number"],
                    "ChapterSection"
                )

            section_number = section_structure.get("section-number", None)
            if section_number is None:
                raise MissingRequiredFieldError(
                    self.structure_file_path,
                    ["section-number"],
                    "ChapterSection"
                )
            if isinstance(section_number, int) is False:
                raise InvalidYAMLValueError(
                    self.structure_file_path,
                    "section-number - value '{}' is invalid".format(section_number),
                    "section-number must be an integer value."
                )

            section_numbers.append(section_number)

            chapter_section_translations = self.get_blank_translation_dictionary()

            content_filename = "{}.md".format(section_slug)
            content_translations = self.get_markdown_translations(content_filename)
            for language, content in content_translations.items():
                chapter_section_translations[language]["content"] = content.html_string
                chapter_section_translations[language]["name"] = content.title

            chapter_section = self.chapter.chapter_sections.create(
                slug=section_slug,
                number=section_number,
                languages=list(content_translations.keys()),
            )

            self.populate_translations(chapter_section, chapter_section_translations)
            self.mark_translation_availability(chapter_section, required_fields=["name", "content"])

            chapter_section.save()

            self.log("Added chapter section: {}".format(chapter_section.name), 1)

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

            # Save chapter section headings
            self.factory.create_chapter_section_heading_loader(
                chapter_section,
                content_translations,
                base_path=self.base_path,
                structure_filename=self.structure_file_path,
            ).load()

        # assumes first section number is always 1
        for counter, section_number in enumerate(section_numbers, 1):
            if section_number != counter:
                raise InvalidYAMLValueError(
                    self.structure_file_path,
                    "section-number - value '{}' is invalid".format(section_number),
                    "section-numbers must be in sequential order. The next expected number was '{}'.".format(counter)
                )
コード例 #19
0
    def handle(self, *args, **options):
        """Automatically called when the loadresources command is given.

        Raise:
            MissingRequiredFieldError: when no object can be found with the matching
                attribute.
        """
        factory = LoaderFactory()
        # Get structure and content files
        base_loader = BaseLoader()
        BASE_PATH = "topics/content/en/"

        structure_file_path = os.path.join(BASE_PATH, "structure.yaml")

        structure_file = base_loader.load_yaml_file(structure_file_path)

        if "curriculum-areas" in structure_file:
            curriculum_areas_structure_file_path = structure_file[
                "curriculum-areas"]
            if curriculum_areas_structure_file_path is not None:
                factory.create_curriculum_areas_loader(
                    curriculum_areas_structure_file_path, BASE_PATH).load()

        if "learning-outcomes" in structure_file:
            learning_outcomes_structure_file_path = structure_file[
                "learning-outcomes"]
            if learning_outcomes_structure_file_path is not None:
                factory.create_learning_outcomes_loader(
                    learning_outcomes_structure_file_path, BASE_PATH).load()

        if "programming-challenges-structure" in structure_file:
            programming_challenges_structure_file_path = structure_file[
                "programming-challenges-structure"]
            if programming_challenges_structure_file_path is not None:
                factory.create_programming_challenges_structure_loader(
                    programming_challenges_structure_file_path,
                    BASE_PATH).load()

        if "glossary-folder" in structure_file:
            glossary_folder_path = structure_file["glossary-folder"]
            if glossary_folder_path is not None:
                factory.create_glossary_terms_loader(glossary_folder_path,
                                                     structure_file_path,
                                                     BASE_PATH).load()

        if structure_file["age-groups"] is None:
            raise MissingRequiredFieldError(structure_file_path,
                                            ["age-groups"],
                                            "Application Structure")
        else:
            age_groups_path = structure_file["age-groups"]
            if age_groups_path is not None:
                factory.create_age_groups_loader(age_groups_path,
                                                 BASE_PATH).load()

        if structure_file["topics"] is None:
            raise MissingRequiredFieldError(structure_file_path, ["topics"],
                                            "Application Structure")

        for topic in structure_file["topics"]:
            topic_structure_file = "{0}/{0}.yaml".format(topic)
            factory.create_topic_loader(topic_structure_file, BASE_PATH).load()
コード例 #20
0
    def load(self):
        """Load the content for a topic.

        Raise:
            MissingRequiredFieldError: when no object can be found with the matching
                attribute.
        """
        topic_structure = self.load_yaml_file(self.structure_file_path)

        unit_plans = topic_structure.get("unit-plans", None)
        if unit_plans is None:
            raise MissingRequiredFieldError(self.structure_file_path,
                                            ["unit-plans"], "Topic")

        topic_translations = self.get_blank_translation_dictionary()

        content_filename = "{}.md".format(self.topic_slug)
        content_translations = self.get_markdown_translations(content_filename)
        for language, content in content_translations.items():
            topic_translations[language]["content"] = content.html_string
            topic_translations[language]["name"] = content.title

        if "other-resources" in topic_structure and topic_structure[
                "other-resources"] is not None:
            other_resources_filename = topic_structure["other-resources"]
            other_resources_translations = self.get_markdown_translations(
                other_resources_filename)
            for language, content in other_resources_translations.items():
                topic_translations[language][
                    "other_resources"] = content.html_string

        # Check if icon is given
        if "icon" in topic_structure:
            topic_icon = topic_structure["icon"]
            if topic_icon is not None:
                find_image_files([topic_icon], self.structure_file_path)
            else:
                topic_icon = None
        else:
            topic_icon = None

        # Create topic objects and save to the db
        topic = Topic(
            slug=self.topic_slug,
            icon=topic_icon,
        )

        self.populate_translations(topic, topic_translations)
        self.mark_translation_availability(topic,
                                           required_fields=["name", "content"])
        topic.save()

        self.log("Added Topic: {}".format(topic.name))

        # Load programming challenges
        if "programming-challenges" in topic_structure:
            programming_challenges_structure_file_path = topic_structure[
                "programming-challenges"]
            if programming_challenges_structure_file_path is not None:
                programming_challenges_path, structure_filename = os.path.split(
                    programming_challenges_structure_file_path)
                self.factory.create_programming_challenges_loader(
                    topic,
                    base_path=self.base_path,
                    content_path=os.path.join(self.content_path,
                                              programming_challenges_path),
                    structure_filename=structure_filename).load()

        # Load unit plans
        for unit_plan_file_path in unit_plans:
            content_path, structure_filename = os.path.split(
                unit_plan_file_path)
            self.factory.create_unit_plan_loader(
                topic,
                base_path=self.base_path,
                content_path=os.path.join(self.content_path, content_path),
                structure_filename=structure_filename).load()

        if "curriculum-integrations" in topic_structure:
            curriculum_integrations_structure_file_path = topic_structure[
                "curriculum-integrations"]
            if curriculum_integrations_structure_file_path is not None:
                curriculum_integrations_path, structure_filename = os.path.split(
                    curriculum_integrations_structure_file_path)
                self.factory.create_curriculum_integrations_loader(
                    topic,
                    base_path=self.base_path,
                    content_path=os.path.join(self.content_path,
                                              curriculum_integrations_path),
                    structure_filename=structure_filename).load()

        self.log("")
コード例 #21
0
    def load(self):
        """Load the content for curriculum integrations.

        Raise:
            KeyNotFoundError: when no object can be found with the matching attribute.
            MissingRequiredFieldError: when a value for a required model field cannot be
                found in the config file.
        """
        structure = self.load_yaml_file(self.structure_file_path)

        for (integration_slug, integration_data) in structure.items():

            if integration_data is None:
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["number", "curriculum-areas"],
                                                "Curriculum Integration")

            integration_number = integration_data.get("number", None)
            integration_curriculum_areas = integration_data.get(
                "curriculum-areas", None)
            if None in [integration_number, integration_curriculum_areas]:
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["number", "curriculum-areas"],
                                                "Curriculum Integration")

            integration_content = self.convert_md_file(
                os.path.join(self.BASE_PATH, "{}.md".format(integration_slug)),
                self.structure_file_path)

            integration = self.topic.curriculum_integrations.create(
                slug=integration_slug,
                number=integration_number,
                name=integration_content.title,
                content=integration_content.html_string,
            )
            integration.save()

            # Add curriculum areas
            for curriculum_area_slug in integration_curriculum_areas:
                try:
                    curriculum_area = CurriculumArea.objects.get(
                        slug=curriculum_area_slug)
                    integration.curriculum_areas.add(curriculum_area)
                except:
                    raise KeyNotFoundError(self.structure_file_path,
                                           curriculum_area_slug,
                                           "Curriculum Areas")

            # Add prerequisite lessons
            if "prerequisite-lessons" in integration_data:
                prerequisite_lessons = integration_data["prerequisite-lessons"]
                if prerequisite_lessons is not None:
                    for (unit_plan_slug,
                         lessons) in prerequisite_lessons.items():
                        if lessons is None:
                            raise MissingRequiredFieldError(
                                self.structure_file_path, ["unit-plan"],
                                "Prerequisite Lesson")
                        for lesson_slug in lessons:
                            try:
                                lesson = Lesson.objects.get(slug=lesson_slug)
                                integration.prerequisite_lessons.add(lesson)
                            except:
                                raise KeyNotFoundError(
                                    self.structure_file_path, lesson_slug,
                                    "Lessons")

            self.log(
                "Added curriculum integration: {}".format(integration.name), 1)
コード例 #22
0
    def load(self):
        """Load the content for unit plans.

        Raise:
            KeyNotFoundError: when no object can be found with the matching attribute.
            MissingRequiredFieldError: when a value for a required model field cannot
                be found in the config file.
        """
        unit_plan_structure = self.load_yaml_file(self.structure_file_path)

        # Convert the content to HTML
        unit_plan_content = self.convert_md_file(
            os.path.join(self.BASE_PATH, "{}.md".format(self.unit_plan_slug)),
            self.structure_file_path)

        heading_tree = None
        if unit_plan_content.heading_tree:
            heading_tree = convert_heading_tree_to_dict(
                unit_plan_content.heading_tree)

        if "computational-thinking-links" in unit_plan_structure:
            file_name = unit_plan_structure["computational-thinking-links"]
            file_path = os.path.join(self.BASE_PATH, file_name)
            ct_links_content = self.convert_md_file(
                file_path,
                self.structure_file_path,
                heading_required=False,
                remove_title=False,
            )
            ct_links = ct_links_content.html_string
        else:
            ct_links = None

        unit_plan = self.topic.unit_plans.create(
            slug=self.unit_plan_slug,
            name=unit_plan_content.title,
            content=unit_plan_content.html_string,
            heading_tree=heading_tree,
            computational_thinking_links=ct_links,
        )
        unit_plan.save()

        self.log("Added unit plan: {}".format(unit_plan.name), 1)

        # Load the lessons for the unit plan
        # Get path to lesson yaml
        lessons_yaml = unit_plan_structure.get("lessons", None)
        if lessons_yaml is None:
            raise MissingRequiredFieldError(self.structure_file_path,
                                            ["lessons", "age-groups"],
                                            "Unit Plan")
        lessons_structure_file_path = os.path.join(self.BASE_PATH,
                                                   lessons_yaml)

        # Call the loader to save the lessons into the db
        self.factory.create_lessons_loader(lessons_structure_file_path,
                                           self.topic, unit_plan,
                                           self.BASE_PATH).load()

        # Create AgeGroup and assign to lessons
        age_groups = unit_plan_structure.get("age-groups", None)
        if age_groups is None:
            raise MissingRequiredFieldError(self.structure_file_path,
                                            ["lessons", "age-groups"],
                                            "Unit Plan")

        for (age_group_slug, age_group_data) in age_groups.items():

            try:
                age_group = AgeGroup.objects.get(slug=age_group_slug)
            except:
                raise KeyNotFoundError(self.structure_file_path,
                                       age_group_slug, "Age Range")

            if age_group_data is None:
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["lesson keys"], "Unit Plan")

            for (lesson_slug, lesson_data) in age_group_data.items():
                try:
                    lesson = Lesson.objects.get(slug=lesson_slug)
                except:
                    raise KeyNotFoundError(self.structure_file_path,
                                           lesson_slug, "Lesson")

                if lesson_data is None or lesson_data.get("number",
                                                          None) is None:
                    raise MissingRequiredFieldError(self.structure_file_path,
                                                    ["number"], "Unit Plan")
                else:
                    lesson_number = lesson_data.get("number", None)

                relationship = LessonNumber(
                    age_group=age_group,
                    lesson=lesson,
                    number=lesson_number,
                )
                relationship.save()
コード例 #23
0
    def load(self):
        """Load the content for programming challenges.

        Raises:
            CouldNotFindMarkdownFileError: when no file can be found with the provided filename.
            KeyNotFoundError: when no object can be found with the matching attribute.
            MissingRequiredFieldError: when no object can be found with the matching
                attribute.
        """
        programming_challenges_structure = self.load_yaml_file(
            self.structure_file_path)

        for (challenge_slug,
             challenge_structure) in programming_challenges_structure.items():

            if challenge_structure is None:
                raise MissingRequiredFieldError(self.structure_file_path, [
                    "challenge-set-number", "challenge-number",
                    "programming-languages", "difficulty-level"
                ], "Programming Challenge")

            challenge_translations = self.get_blank_translation_dictionary()

            # Retrieve required variables from md file
            challenge_set_number = challenge_structure.get(
                "challenge-set-number", None)
            challenge_number = challenge_structure.get("challenge-number",
                                                       None)
            challenge_prog_languages = challenge_structure.get(
                "programming-languages", None)
            challenge_difficulty = challenge_structure.get(
                "difficulty-level", None)
            if None in [
                    challenge_set_number, challenge_number,
                    challenge_prog_languages, challenge_difficulty
            ]:
                raise MissingRequiredFieldError(self.structure_file_path, [
                    "challenge-set-number", "challenge-number",
                    "programming-languages", "difficulty-level"
                ], "Programming Challenge")

            content_filename = "{0}.md".format(challenge_slug)
            content_translations = self.get_markdown_translations(
                os.path.join(challenge_slug, content_filename))

            for language, content in content_translations.items():
                challenge_translations[language][
                    "content"] = content.html_string
                challenge_translations[language]["name"] = content.title

            challenge_extra_challenge_file = challenge_structure.get(
                "extra-challenge", None)
            if challenge_extra_challenge_file:
                extra_challenge_translations = self.get_markdown_translations(
                    os.path.join(challenge_slug,
                                 challenge_extra_challenge_file),
                    heading_required=False,
                )
                for language, content in extra_challenge_translations.items():
                    challenge_translations[language][
                        "extra_challenge"] = content.html_string

            try:
                difficulty_level = ProgrammingChallengeDifficulty.objects.get(
                    level=challenge_difficulty)
            except ObjectDoesNotExist:
                raise KeyNotFoundError(self.structure_file_path,
                                       challenge_difficulty,
                                       "Programming Challenge Difficulty")

            programming_challenge = self.topic.programming_challenges.create(
                slug=challenge_slug,
                challenge_set_number=challenge_set_number,
                challenge_number=challenge_number,
                difficulty=difficulty_level)
            self.populate_translations(programming_challenge,
                                       challenge_translations)
            self.mark_translation_availability(
                programming_challenge, required_fields=["name", "content"])

            programming_challenge.save()

            LOG_TEMPLATE = "Added programming challenge: {}"
            self.log(LOG_TEMPLATE.format(programming_challenge.name), 1)

            for prog_language in challenge_prog_languages:
                if prog_language is None:
                    raise MissingRequiredFieldError(self.structure_file_path, [
                        "challenge-set-number", "challenge-number",
                        "programming-languages", "difficulty-level"
                    ], "Programming Challenge")
                try:
                    prog_language_object = ProgrammingChallengeLanguage.objects.get(
                        slug=prog_language)
                except ObjectDoesNotExist:
                    raise KeyNotFoundError(self.structure_file_path,
                                           prog_language,
                                           "Programming Challenge Language")

                implementation_translations = self.get_blank_translation_dictionary(
                )

                filename_template = os.path.join(
                    challenge_slug, "{}-{{}}.md".format(prog_language))

                expected_result_translations = self.get_markdown_translations(
                    filename_template.format("expected"),
                    heading_required=False)
                for language, content in expected_result_translations.items():
                    implementation_translations[language][
                        "expected_result"] = content.html_string

                solution_translations = self.get_markdown_translations(
                    filename_template.format("solution"),
                    heading_required=False)
                for language, content in solution_translations.items():
                    implementation_translations[language][
                        "solution"] = content.html_string

                hints_translations = self.get_markdown_translations(
                    filename_template.format("hints"),
                    heading_required=False,
                    required=False)
                for language, content in hints_translations.items():
                    implementation_translations[language][
                        "hints"] = content.html_string

                implementation = ProgrammingChallengeImplementation(
                    language=prog_language_object,
                    challenge=programming_challenge,
                    topic=self.topic)

                self.populate_translations(implementation,
                                           implementation_translations)
                self.mark_translation_availability(
                    implementation,
                    required_fields=["solution", "expected_result"])

                implementation.save()

                LOG_TEMPLATE = "Added language implementation: {}"
                self.log(LOG_TEMPLATE.format(implementation.language), 2)

            test_cases = challenge_structure.get("test-cases", None)
            if (test_cases is not None):
                for (testcase_id, testcase_type) in test_cases.items():
                    test_case_translations = self.get_blank_translation_dictionary(
                    )

                    testcase_filename_template = os.path.join(
                        challenge_slug, 'test-cases',
                        "test-case-{}-{{}}.txt".format(testcase_id))

                    testcase_input = open(self.get_localised_file(
                        "en",
                        testcase_filename_template.format(testcase_type)),
                                          encoding='UTF-8').read()

                    testcase_output = open(self.get_localised_file(
                        "en", testcase_filename_template.format("output")),
                                           encoding='UTF-8').read()

                    test_case = TestCase(number=testcase_id,
                                         test_input=testcase_input,
                                         expected_output=testcase_output,
                                         question_type=testcase_type,
                                         challenge=programming_challenge)

                    required_fields = [
                        'test_input', 'expected_output', 'question_type'
                    ]

                    self.populate_translations(test_case,
                                               test_case_translations)
                    self.mark_translation_availability(
                        test_case, required_fields=required_fields)
                    test_case.save()

                    LOG_TEMPLATE = "Added Programming Challenge Test Case: {}"
                    self.log(LOG_TEMPLATE.format(testcase_id), 2)

            if "learning-outcomes" in challenge_structure:
                learning_outcomes = challenge_structure["learning-outcomes"]
                if learning_outcomes is not None:
                    for learning_outcome_slug in learning_outcomes:
                        try:
                            learning_outcome = LearningOutcome.objects.get(
                                slug=learning_outcome_slug)
                            programming_challenge.learning_outcomes.add(
                                learning_outcome)
                        except ObjectDoesNotExist:
                            raise KeyNotFoundError(self.structure_file_path,
                                                   learning_outcome_slug,
                                                   "Learning Outcome")
コード例 #24
0
    def load(self):
        """Load the content for curriculum areas.

        Raise:
            MissingRequiredFieldError: when no object can be found with the matching
                attribute.
        """
        curriculum_areas_structure = self.load_yaml_file(
            os.path.join(self.BASE_PATH, self.structure_file_path))

        for (curriculum_area_slug,
             curriculum_area_data) in curriculum_areas_structure.items():

            if curriculum_area_data is None:
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["name"], "Curriculum Area")

            curriculum_area_name = curriculum_area_data.get("name", None)
            if curriculum_area_name is None:
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["name"], "Curriculum Area")

            curriculum_area_colour = curriculum_area_data.get("colour", None)
            if curriculum_area_colour is None:
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["colour"], "Curriculum Area")

            curriculum_area_number = curriculum_area_data.get("number", None)
            if curriculum_area_number is None:
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["number"], "Curriculum Area")

            # Create area objects and save to database
            new_area = CurriculumArea(
                slug=curriculum_area_slug,
                name=curriculum_area_name,
                colour=curriculum_area_colour,
                number=curriculum_area_number,
            )
            new_area.save()

            self.log("Added curriculum area: {}".format(new_area.__str__()))

            # Create children curriculum areas with reference to parent
            if "children" in curriculum_area_data:
                children_curriculum_areas = curriculum_area_data["children"]
                if children_curriculum_areas is None:
                    raise MissingRequiredFieldError(self.structure_file_path,
                                                    ["slug"],
                                                    "Child Curriculum Area")
                for (child_slug,
                     child_data) in children_curriculum_areas.items():
                    if child_data is None:
                        raise MissingRequiredFieldError(
                            self.structure_file_path, ["name"],
                            "Child Curriculum Area")
                    child_name = child_data.get("name", None)
                    if child_name is None:
                        raise MissingRequiredFieldError(
                            self.structure_file_path, ["name"],
                            "Child Curriculum Area")

                    new_child = CurriculumArea(
                        slug=child_slug,
                        name=child_name,
                        colour=curriculum_area_colour,
                        number=curriculum_area_number,
                        parent=new_area,
                    )
                    new_child.save()

                    self.log(
                        "Added child curriculum area: {}".format(
                            new_child.__str__()), 1)

        self.log("All curriculum areas loaded!\n")
コード例 #25
0
    def handle(self, *args, **options):
        """Automatically called when the loadresources command is given.

        Raise:
            MissingRequiredFieldError: when no object can be found with the matching
                attribute.
        """
        factory = LoaderFactory()
        lite_load = options.get("lite_load")

        # Get structure and content files
        base_loader = BaseLoader()
        base_path = settings.TOPICS_CONTENT_BASE_PATH

        structure_file_path = os.path.join(base_path,
                                           base_loader.structure_dir,
                                           "structure.yaml")

        structure_file = base_loader.load_yaml_file(structure_file_path)

        if "curriculum-areas" in structure_file:
            curriculum_areas_structure_file_path = structure_file[
                "curriculum-areas"]
            if curriculum_areas_structure_file_path is not None:
                curriculum_areas_path, structure_filename = os.path.split(
                    curriculum_areas_structure_file_path)
                factory.create_curriculum_areas_loader(
                    base_path=base_path,
                    content_path=curriculum_areas_path,
                    structure_filename=structure_filename).load()

        if "learning-outcomes" in structure_file:
            learning_outcomes_structure_file_path = structure_file[
                "learning-outcomes"]
            if learning_outcomes_structure_file_path is not None:
                learning_outcomes_path, structure_filename = os.path.split(
                    learning_outcomes_structure_file_path)
                factory.create_learning_outcomes_loader(
                    base_path=base_path,
                    content_path=learning_outcomes_path,
                    structure_filename=structure_filename).load()

        if "programming-challenges-structure" in structure_file:
            programming_challenges_structure_file_path = structure_file[
                "programming-challenges-structure"]
            if programming_challenges_structure_file_path is not None:
                programming_challenges_path, structure_filename = os.path.split(
                    programming_challenges_structure_file_path)
                factory.create_programming_challenges_structure_loader(
                    base_path=base_path,
                    content_path=programming_challenges_path,
                    structure_filename=structure_filename).load()

        if "classroom-resources" in structure_file:
            classroom_resources_structure_file_path = structure_file[
                "classroom-resources"]
            if classroom_resources_structure_file_path is not None:
                classroom_resources_path, structure_filename = os.path.split(
                    classroom_resources_structure_file_path)
                factory.create_classroom_resources_loader(
                    base_path=base_path,
                    content_path=classroom_resources_path,
                    structure_filename=structure_filename).load()

        if "glossary-folder" in structure_file:
            glossary_folder_path = structure_file["glossary-folder"]
            if glossary_folder_path is not None:
                factory.create_glossary_terms_loader(
                    base_path=base_path,
                    content_path=glossary_folder_path,
                ).load()

        age_groups_structure_file_path = structure_file.get("age-groups", None)
        if age_groups_structure_file_path is None:
            raise MissingRequiredFieldError(structure_file_path,
                                            ["age-groups"],
                                            "Application Structure")
        else:
            age_groups_path, structure_filename = os.path.split(
                age_groups_structure_file_path)
            factory.create_age_groups_loader(
                content_path=age_groups_path,
                base_path=base_path,
                structure_filename=structure_filename).load()

        if structure_file.get("topics", None) is None or not isinstance(
                structure_file["topics"], list):
            raise MissingRequiredFieldError(structure_file_path, ["topics"],
                                            "Application Structure")
        else:
            for topic in structure_file["topics"]:
                topic_path = topic
                topic_structure_file = "{}.yaml".format(topic)
                factory.create_topic_loader(
                    base_path=base_path,
                    content_path=topic_path,
                    structure_filename=topic_structure_file,
                    lite_loader=lite_load,
                ).load()
コード例 #26
0
    def load(self):
        """Load the content for structure of programming challenges.

        Raises:
            MissingRequiredFieldError: when no object can be found with the matching
                attribute.
        """
        structure = self.load_yaml_file(
            os.path.join(
                self.BASE_PATH,
                self.structure_file_path
            )
        )

        languages = structure.get("languages", None)
        difficulty_levels = structure.get("difficulties", None)
        if None in [languages, difficulty_levels]:
            raise MissingRequiredFieldError(
                self.structure_file_path,
                ["lanugages", "difficulties"],
                "Programming Challenge Structure"
            )

        for (language, language_data) in languages.items():

            if language_data is None:
                raise MissingRequiredFieldError(
                    self.structure_file_path,
                    ["name", "number"],
                    "Programming Challenge Language"
                )

            # Check for required fields
            language_name = language_data.get("name", None)
            language_number = language_data.get("number", None)
            if language_name is None or language_number is None:
                raise MissingRequiredFieldError(
                    self.structure_file_path,
                    ["name", "number"],
                    "Programming Challenge Language"
                )

            # Check if icon is given
            if "icon" in language_data:
                language_icon = language_data["icon"]
            else:
                language_icon = None

            new_language = ProgrammingChallengeLanguage(
                slug=language,
                name=language_name,
                number=language_number,
                icon=language_icon
            )

            new_language.save()

            self.log("Added programming langauge: {}".format(new_language.__str__()))

        for (difficulty, difficulty_data) in difficulty_levels.items():

            if difficulty_data is None:
                raise MissingRequiredFieldError(
                    self.structure_file_path,
                    ["name"],
                    "Programming Challenge Difficulty"
                )

            difficulty_name = difficulty_data.get("name", None)
            if difficulty_name is None:
                raise MissingRequiredFieldError(
                    self.structure_file_path,
                    ["name"],
                    "Programming Challenge Difficulty"
                )

            new_difficulty = ProgrammingChallengeDifficulty(
                level=difficulty,
                name=difficulty_name
            )
            new_difficulty.save()

            self.log("Added programming difficulty level: {}".format(new_difficulty.__str__()))

        self.log("")
コード例 #27
0
 def test_attributes(self):
     exception = MissingRequiredFieldError("config file path",
                                           ["field1", "field2"], "model")
     self.assertEqual(exception.config_file_path, "config file path")
     self.assertEqual(exception.required_fields, ["field1", "field2"])
     self.assertEqual(exception.model, "model")
コード例 #28
0
    def load(self):
        """Load the content for curriculum areas.

        Raise:
            MissingRequiredFieldError: when no object can be found with the matching
                attribute.
        """
        curriculum_areas_structure = self.load_yaml_file(
            self.structure_file_path)
        curriculum_areas_translations = self.get_yaml_translations(
            self.structure_filename,
            required_fields=["name"],
            required_slugs=curriculum_areas_structure.keys())

        for (curriculum_area_slug,
             curriculum_area_data) in curriculum_areas_structure.items():

            if curriculum_area_data is None:
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["name"], "Curriculum Area")
            translations = curriculum_areas_translations.get(
                curriculum_area_slug, dict())

            curriculum_area_colour = curriculum_area_data.get("colour", None)
            if curriculum_area_colour is None:
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["colour"], "Curriculum Area")

            curriculum_area_number = curriculum_area_data.get("number", None)
            if curriculum_area_number is None:
                raise MissingRequiredFieldError(self.structure_file_path,
                                                ["number"], "Curriculum Area")

            # Create area objects and save to database
            new_area = CurriculumArea(
                slug=curriculum_area_slug,
                colour=curriculum_area_colour,
                number=curriculum_area_number,
            )
            self.populate_translations(new_area, translations)
            self.mark_translation_availability(new_area,
                                               required_fields=["name"])

            new_area.save()

            self.log("Added curriculum area: {}".format(new_area.__str__()))

            # Create children curriculum areas with reference to parent
            if "children" in curriculum_area_data:
                children_curriculum_areas = curriculum_area_data["children"]
                if children_curriculum_areas is None:
                    raise MissingRequiredFieldError(self.structure_file_path,
                                                    ["slug"],
                                                    "Child Curriculum Area")
                for child_slug in children_curriculum_areas:
                    translations = curriculum_areas_translations.get(
                        child_slug, dict())

                    new_child = CurriculumArea(
                        slug=child_slug,
                        colour=curriculum_area_colour,
                        number=curriculum_area_number,
                        parent=new_area,
                    )
                    self.populate_translations(new_child, translations)
                    self.mark_translation_availability(
                        new_child, required_fields=["name"])

                    new_child.save()

                    self.log(
                        "Added child curriculum area: {}".format(
                            new_child.__str__()), 1)

        self.log("All curriculum areas loaded!\n")
コード例 #29
0
    def load(self):
        """Load the content for structure of programming challenges.

        Raises:
            MissingRequiredFieldError: when no object can be found with the matching
                attribute.
        """
        structure = self.load_yaml_file(self.structure_file_path)

        prog_languages = structure.get("languages", None)
        difficulty_levels = structure.get("difficulties", None)
        if None in [prog_languages, difficulty_levels]:
            raise MissingRequiredFieldError(
                self.structure_file_path,
                ["lanugages", "difficulties"],
                "Programming Challenge Structure"
            )

        # Add "-languages" to the structure filename
        prog_languages_translation_filename = "{}-languages.yaml".format(
            os.path.splitext(self.structure_filename)[0]
        )
        prog_languages_translations = self.get_yaml_translations(
            prog_languages_translation_filename,
            required_slugs=prog_languages.keys(),
            required_fields=["name"]
        )

        for (prog_language, prog_language_data) in prog_languages.items():

            if prog_language_data is None:
                raise MissingRequiredFieldError(
                    self.structure_file_path,
                    ["number"],
                    "Programming Challenge Language"
                )

            # Check for required fields
            prog_language_number = prog_language_data.get("number", None)
            if prog_language_number is None:
                raise MissingRequiredFieldError(
                    self.structure_file_path,
                    ["number"],
                    "Programming Challenge Language"
                )

            # Check if icon is given
            if "icon" in prog_language_data:
                prog_language_icon = prog_language_data["icon"]
            else:
                prog_language_icon = None

            new_prog_language = ProgrammingChallengeLanguage(
                slug=prog_language,
                number=prog_language_number,
                icon=prog_language_icon
            )

            translations = prog_languages_translations.get(prog_language, dict())
            self.populate_translations(new_prog_language, translations)
            self.mark_translation_availability(new_prog_language, required_fields=["name"])
            new_prog_language.save()

            self.log("Added programming language: {}".format(new_prog_language.__str__()))

        # Add "-languages" to the structure filename
        difficulties_translation_filename = "{}-difficulties.yaml".format(
            os.path.splitext(self.structure_filename)[0]
        )
        difficulties_translations = self.get_yaml_translations(
            difficulties_translation_filename,
            required_slugs=difficulty_levels,
            required_fields=["name"],
        )

        for level, difficulty_slug in enumerate(difficulty_levels):

            new_difficulty = ProgrammingChallengeDifficulty(
                level=level,
            )

            translations = difficulties_translations.get(difficulty_slug, dict())
            self.populate_translations(new_difficulty, translations)
            self.mark_translation_availability(new_difficulty, required_fields=["name"])
            new_difficulty.save()

            self.log("Added programming difficulty level: {}".format(new_difficulty.__str__()))

        self.log("")
コード例 #30
0
    def load(self):
        """Load the content for an activity.

        Raise:
            MissingRequiredFieldError: when no object can be found with the matching attribute.
        """
        activity_translations = self.get_blank_translation_dictionary()

        try:
            order_number = self.activity_data['order-number']
            activity_icon = self.activity_data['icon']
        except KeyError:
            raise MissingRequiredFieldError(
                self.structure_file_path,
                [
                    "order-number",
                    "icon"
                ],
                "Activity"
            )

        # Check if icon is available
        find_image_files([activity_icon], self.structure_file_path)

        # Introduction content
        content_translations = self.get_markdown_translations(INTRODUCTION_FILENAME)
        for language, content in content_translations.items():
            activity_translations[language]['name'] = content.title
            activity_translations[language]['introduction'] = content.html_string

        activity_steps_translations = self.get_activity_step_translations()
        for language, content in activity_steps_translations.items():
            activity_translations[language]['activity_steps'] = content

        activity_extra_info_md_file_path = self.get_localised_file(
            language,
            ACTIVITY_EXTRA_INFORMATION_FILENMAE,
        )
        activity_extra_info_exists = os.path.exists(activity_extra_info_md_file_path)
        if activity_extra_info_exists:
            activity_extra_info_translations = self.get_markdown_translations(
                ACTIVITY_EXTRA_INFORMATION_FILENMAE,
                heading_required=False,
                remove_title=False,
            )
            for language, content in activity_extra_info_translations.items():
                activity_translations[language]['activity_extra_information'] = content.html_string

        inside_computer_translations = self.get_markdown_translations(
            INSIDE_THE_COMPUTER_FILENAME,
            heading_required=False,
            remove_title=False,
        )
        for language, content in inside_computer_translations.items():
            activity_translations[language]['inside_the_computer'] = content.html_string

        project_md_file_path = self.get_localised_file(
            language,
            PROJECT_FILENAME,
        )
        project_exists = os.path.exists(project_md_file_path)
        if project_exists:
            project_translations = self.get_markdown_translations(
                PROJECT_FILENAME,
                heading_required=False,
                remove_title=False,
            )
            for language, content in project_translations.items():
                activity_translations[language]['project'] = content.html_string

        more_information_translations = self.get_markdown_translations(
            MORE_INFORMATION_FILENAME,
            heading_required=False,
            remove_title=False,
        )
        for language, content in more_information_translations.items():
            activity_translations[language]['more_information'] = content.html_string

        # Create or update activity objects and save to the database
        activity, created = Activity.objects.update_or_create(
            slug=self.activity_slug,
            defaults={
                'order_number': order_number,
                'icon': activity_icon,
            }
        )

        self.populate_translations(activity, activity_translations)
        self.mark_translation_availability(activity, required_fields=['name', 'introduction'])
        activity.save()

        if created:
            self.log('Added Activity: {}'.format(activity.name))
        else:
            self.log('Updated Activity: {}'.format(activity.name))

        # structure_filename = os.path.join(unit_plan_file_path)
        self.factory.create_challenge_loader(
            activity,
            base_path=self.base_path,
            content_path=self.content_path,
            structure_filename=self.structure_filename,
            lite_loader=self.lite_loader,
        ).load()