예제 #1
0
 def test_models_course_field_duration_null(self):
     """The duration field can be null."""
     course = factories.CourseFactory(duration=None)
     self.assertIsNone(course.duration)
     self.assertEqual(course.get_duration_display(), "")
예제 #2
0
 def test_models_course_field_effort_display_singular(self):
     """Validate that a value of 1 time unit is displayed as expected."""
     course = factories.CourseFactory(effort=[1, "hour"])
     self.assertEqual(course.get_effort_display(), "1 hour")
예제 #3
0
 def test_models_course_field_effort_display_plural(self):
     """Validate that a plural number of time units is displayed as expected."""
     course = factories.CourseFactory(effort=[2, "hour"])
     self.assertEqual(course.get_effort_display(), "2 hours")
예제 #4
0
 def test_models_course_field_effort_null(self):
     """The effort field can be null."""
     course = factories.CourseFactory(effort=None)
     self.assertIsNone(course.effort)
     self.assertEqual(course.get_effort_display(), "")
예제 #5
0
 def test_models_course_field_effort_positive(self):
     """The first value should be a positive integer."""
     with self.assertRaises(ValidationError) as context:
         factories.CourseFactory(effort=[-1, "hour"])
     self.assertEqual(context.exception.messages[0],
                      "A composite duration should be positive.")
예제 #6
0
    def test_models_course_get_course_runs(self):
        """
        The `get_course_runs` method should return all descendants ranked by start date,
        not only direct children.
        """
        course = factories.CourseFactory(page_languages=["en", "fr"])

        # Create draft and published course runs for this course
        course_run = factories.CourseRunFactory(direct_course=course)

        self.assertTrue(course.extended_object.publish("en"))
        self.assertTrue(course.extended_object.publish("fr"))

        course_run_draft = factories.CourseRunFactory(direct_course=course)

        # Create a child course with draft and published course runs (what results from
        # snapshotting a course)
        child_course = factories.CourseFactory(
            page_languages=["en", "fr"], page_parent=course.extended_object)
        child_course_run = factories.CourseRunFactory(
            direct_course=child_course)

        self.assertTrue(child_course.extended_object.publish("en"))
        self.assertTrue(child_course.extended_object.publish("fr"))

        child_course_run_draft = factories.CourseRunFactory(
            direct_course=child_course)

        # Create another course, not related to the first one, with draft and published course runs
        other_course = factories.CourseFactory(page_languages=["en", "fr"])
        factories.CourseRunFactory(direct_course=other_course)

        self.assertTrue(other_course.extended_object.publish("en"))
        self.assertTrue(other_course.extended_object.publish("fr"))

        factories.CourseRunFactory(direct_course=other_course)

        # Check that the draft course retrieves all its descendant course runs
        # 3 draft course runs and 2 published course runs per course
        self.assertEqual(CourseRun.objects.count(), 3 * 3)

        sorted_runs = sorted(
            [
                course_run, course_run_draft, child_course_run,
                child_course_run_draft
            ],
            key=lambda o: o.start,
            reverse=True,
        )
        for run in sorted_runs:
            run.refresh_from_db()

        with self.assertNumQueries(2):
            self.assertEqual(list(course.get_course_runs()), sorted_runs)

        # Check that the published course retrieves only the published descendant course runs
        course.refresh_from_db()
        public_course = course.public_extension

        with self.assertNumQueries(3):
            result = list(public_course.get_course_runs())

        expected_public_course_runs = sorted(
            [course_run.public_course_run, child_course_run.public_course_run],
            key=lambda o: o.start,
            reverse=True,
        )
        self.assertEqual(result, expected_public_course_runs)
예제 #7
0
    def test_models_course_create_page_role(self, *_):
        """
        If the CMS_PERMISSIONS settings is True, a page role should be created when calling
        `create_page_role` on a course.
        Calling the method several times should not duplicate permissions.
        """
        def get_random_role_dict():
            return {
                "django_permissions": ["cms.change_page"],
                "course_page_permissions": {
                    "can_change": random.choice([True, False]),
                    "can_add": random.choice([True, False]),
                    "can_delete": random.choice([True, False]),
                    "can_change_advanced_settings":
                    random.choice([True, False]),
                    "can_publish": random.choice([True, False]),
                    "can_change_permissions": random.choice([True, False]),
                    "can_move_page": random.choice([True, False]),
                    "can_view":
                    False,  # can_view = True would make it a view restriction...
                    "grant_on": random.randint(1, 5),
                },
                "course_folder_permissions": {
                    "can_read": random.choice([True, False]),
                    "can_edit": random.choice([True, False]),
                    "can_add_children": random.choice([True, False]),
                    "type": random.randint(0, 2),
                },
            }

        page = PageFactory(title__title="My title")
        course = factories.CourseFactory(extended_object=page)
        self.assertFalse(page.roles.exists())

        role_dict = get_random_role_dict()
        with mock.patch.dict(defaults.COURSE_ADMIN_ROLE, role_dict):
            course.create_page_role()

        # Call the method another time with different permissions to check it has no effect
        with mock.patch.dict(defaults.COURSE_ADMIN_ROLE,
                             get_random_role_dict()):
            course.create_page_role()

        # A page role should have been created
        self.assertEqual(page.roles.count(), 1)
        role = page.roles.get(role="ADMIN")
        self.assertEqual(role.group.name, "Admin | My title")
        self.assertEqual(role.group.permissions.count(), 1)
        self.assertEqual(role.folder.name, "Admin | My title")

        # All expected permissions should have been assigned to the group:
        # - Django permissions
        self.assertEqual(role.group.permissions.first().codename,
                         "change_page")
        # - DjangoCMS page permissions
        self.assertEqual(
            PagePermission.objects.filter(group=role.group).count(), 1)
        page_permission = PagePermission.objects.get(group=role.group)
        for key, value in role_dict["course_page_permissions"].items():
            self.assertEqual(getattr(page_permission, key), value)
        # The Django Filer folder permissions
        self.assertEqual(
            FolderPermission.objects.filter(group_id=role.group_id).count(), 1)
        folder_permission = FolderPermission.objects.get(
            group_id=role.group_id)
        for key, value in role_dict["course_folder_permissions"].items():
            self.assertEqual(getattr(folder_permission, key), value)
예제 #8
0
 def test_models_course_unique_code_draft(self):
     """The code field should be unique among all draft courses."""
     factories.CourseFactory(code="123")
     with self.assertRaises(ValidationError):
         factories.CourseFactory(code="123")
예제 #9
0
    def test_models_course_create_permissions_for_organization(self, *_):
        """
        If the CMS_PERMISSIONS settings is True, a page and folder permission should be created
        for the course when calling the `create_permissions_for_organization` method.
        Calling the method several times should not duplicate permissions.
        """
        def get_random_role_dict():
            return {
                "courses_page_permissions": {
                    "can_change": random.choice([True, False]),
                    "can_add": random.choice([True, False]),
                    "can_delete": random.choice([True, False]),
                    "can_change_advanced_settings":
                    random.choice([True, False]),
                    "can_publish": random.choice([True, False]),
                    "can_change_permissions": random.choice([True, False]),
                    "can_move_page": random.choice([True, False]),
                    "can_view":
                    False,  # can_view = True would make it a view restriction...
                    "grant_on": random.randint(1, 5),
                },
                "courses_folder_permissions": {
                    "can_read": random.choice([True, False]),
                    "can_edit": random.choice([True, False]),
                    "can_add_children": random.choice([True, False]),
                    "type": random.randint(0, 2),
                },
            }

        course = factories.CourseFactory()
        factories.PageRoleFactory(page=course.extended_object, role="ADMIN")

        organization = factories.OrganizationFactory()
        organization_role = factories.PageRoleFactory(
            page=organization.extended_object, role="ADMIN")

        role_dict = get_random_role_dict()
        with mock.patch.dict(defaults.ORGANIZATION_ADMIN_ROLE, role_dict):
            course.create_permissions_for_organization(organization)

        # Call the method another time with different permissions to check it has no effect
        with mock.patch.dict(defaults.ORGANIZATION_ADMIN_ROLE,
                             get_random_role_dict()):
            course.create_permissions_for_organization(organization)

        # All expected permissions should have been assigned to the group:
        # - DjangoCMS page permissions
        self.assertEqual(
            PagePermission.objects.filter(
                group=organization_role.group).count(), 1)
        page_permission = PagePermission.objects.get(
            group=organization_role.group)
        for key, value in role_dict["courses_page_permissions"].items():
            self.assertEqual(getattr(page_permission, key), value)
        # The Django Filer folder permissions
        self.assertEqual(
            FolderPermission.objects.filter(
                group_id=organization_role.group_id).count(),
            1,
        )
        folder_permission = FolderPermission.objects.get(
            group_id=organization_role.group_id)
        for key, value in role_dict["courses_folder_permissions"].items():
            self.assertEqual(getattr(folder_permission, key), value)
예제 #10
0
 def test_models_course_get_pace_display_with_empty_effort(self):
     """
     If course effort is not defined, None should be return.
     """
     course = factories.CourseFactory(duration=[7, "hour"], effort=None)
     self.assertIsNone(course.get_pace_display())
예제 #11
0
 def test_models_course_get_pace_display_with_is_self_paced(self):
     """
     If course is self paced, a "Self paced" label should be display
     """
     course = factories.CourseFactory(is_self_paced=True, )
     self.assertEqual(course.get_pace_display(), "Self paced")
예제 #12
0
def create_demo_site():
    """
    Create a simple site tree structure for developpers to work in realistic environment.

    We create multilingual pages, add organizations under the related page and add
    plugins to each page.
    """
    site = Site.objects.get(id=1)
    site.domain = getattr(settings, "RICHIE_DEMO_SITE_DOMAIN",
                          defaults.DEFAULT_DEMO_SITE_DOMAIN)
    site.name = "Richie demonstration"
    site.save()

    lms_endpoint = (getattr(settings, "RICHIE_LMS_BACKENDS", None)
                    or [{
                        "BASE_URL": defaults.DEFAULT_LMS_ENDPOINT
                    }])[0]["BASE_URL"]

    # Create pages as described in PAGES_INFOS
    pages_created = recursive_page_creation(site, defaults.PAGES_INFO)

    # Create the footer links
    def create_footer_link(**link_info):
        """
        Use LinkPlugin to create a link in footer menu with link_info

        Links can be nested into a NestedItemPlugin, in this case link_info contains
        a target key.
        """
        if "internal_link" in link_info:
            link_info = link_info.copy()
            link_info["internal_link"] = pages_created[
                link_info["internal_link"]]
        add_plugin(plugin_type="LinkPlugin", **link_info)

    footer_static_ph = StaticPlaceholder.objects.get_or_create(
        code="footer")[0]
    for footer_placeholder in [
            footer_static_ph.draft, footer_static_ph.public
    ]:
        for language, content in defaults.FOOTER_CONTENT.items():
            for footer_info in content:
                if "items" in footer_info:
                    # Create the first level items for main columns
                    nest_column_plugin = add_plugin(
                        footer_placeholder,
                        plugin_type="NestedItemPlugin",
                        language=language,
                        content=footer_info.get("title", ""),
                    )

                    # Create the second level items for links
                    for item_info in footer_info.get("items", []):
                        create_footer_link(
                            language=language,
                            placeholder=footer_placeholder,
                            target=nest_column_plugin,
                            **item_info,
                        )
                else:
                    # Create link at first level
                    create_footer_link(language=language,
                                       placeholder=footer_placeholder,
                                       **footer_info)

    # Create some licences
    licences = (factories.LicenceFactory.create_batch(
        defaults.NB_OBJECTS["licences"],
        logo__file__from_path=pick_image("licence")(),
    ) if defaults.NB_OBJECTS.get("licences") else [])

    # Generate each category tree and return a list of the leaf categories
    icons = list(
        create_categories(
            **defaults.ICONS_INFO,
            fill_banner=pick_image("banner"),
            fill_logo=pick_image("category_logo"),
            page_parent=pages_created["categories"],
        ))
    levels = list(
        create_categories(
            **defaults.LEVELS_INFO,
            fill_banner=pick_image("banner"),
            fill_logo=pick_image("category_logo"),
            page_parent=pages_created["categories"],
        ))
    subjects = list(
        create_categories(
            **defaults.SUBJECTS_INFO,
            fill_banner=pick_image("banner"),
            fill_logo=pick_image("category_logo"),
            page_parent=pages_created["categories"],
        ))
    partnerships = list(
        create_categories(
            **defaults.PARTNERSHIPS_INFO,
            fill_banner=pick_image("banner"),
            fill_logo=pick_image("category_logo"),
            page_parent=pages_created["categories"],
        ))
    tags = list(
        create_categories(
            **defaults.TAGS_INFO,
            fill_banner=pick_image("banner"),
            fill_logo=pick_image("category_logo"),
            page_parent=pages_created["categories"],
        ))

    # Create organizations under the `Organizations` page
    organizations = []
    for i in range(defaults.NB_OBJECTS["organizations"]):
        # Randomly assign each organization to a partnership level category
        organizations.append(
            factories.OrganizationFactory(
                page_in_navigation=True,
                page_languages=["en", "fr"],
                page_parent=pages_created["organizations"],
                fill_banner=pick_image("banner"),
                fill_categories=[random.choice(partnerships)]  # nosec
                if (i % 2 == 0) else [],
                fill_description=True,
                fill_logo=pick_image("logo"),
                should_publish=True,
                with_permissions=True,
            ))

    # Create persons under the `persons` page
    persons = []
    persons_for_organization = defaultdict(list)
    for _i in range(defaults.NB_OBJECTS["persons"]):
        # Randomly assign each person to a set of organizations
        person_organizations = random.sample(
            organizations,
            random.randint(
                1, defaults.NB_OBJECTS["person_organizations"]),  # nosec
        )
        person = factories.PersonFactory(
            page_in_navigation=True,
            page_languages=["en", "fr"],
            page_parent=pages_created["persons"],
            fill_categories=random.sample(
                subjects,
                random.randint(
                    1, defaults.NB_OBJECTS["person_subjects"]),  # nosec
            ),
            fill_organizations=person_organizations,
            fill_portrait=pick_image("portrait"),
            fill_bio=True,
            fill_maincontent=True,
            should_publish=True,
        )
        persons.append(person)
        for organization in person_organizations:
            persons_for_organization[organization.id].append(person)

    # Assign each person randomly to an organization so that our course are tagged realistically
    # If organizations and persons are tagged randomly on courses, each organizations will
    # in the end be related to most persons... not what we want.

    # Create courses under the `Course` page with categories and organizations
    # relations
    courses = []
    for _i in range(defaults.NB_OBJECTS["courses"]):
        video_sample = random.choice(factories.VIDEO_SAMPLE_LINKS)  # nosec

        # Randomly assign each course to a set of organizations
        course_organizations = random.sample(
            organizations, defaults.NB_OBJECTS["course_organizations"])

        # Only the persons members of these organizations are eligible to be part
        # of the course team
        eligible_persons = set(person for o in course_organizations
                               for person in persons_for_organization[o.id])

        course_licences = ([
            ("course_license_content", random.choice(licences)),  # nosec
            ("course_license_participation", random.choice(licences)),  # nosec
        ] if licences else [])

        course = factories.CourseFactory(
            page_in_navigation=True,
            page_languages=["en", "fr"],
            page_parent=pages_created["courses"],
            fill_licences=course_licences,
            fill_team=random.sample(
                eligible_persons,
                min(
                    random.randint(
                        1, defaults.NB_OBJECTS["course_persons"]),  # nosec
                    len(eligible_persons),
                ),
            ),
            fill_teaser=video_sample,
            fill_cover=pick_image("cover")(video_sample.image),
            fill_categories=[
                *random.sample(
                    subjects,
                    random.randint(
                        1, defaults.NB_OBJECTS["course_subjects"]),  # nosec
                ),
                random.choice(levels),  # nosec
            ],
            fill_icons=random.sample(icons, get_number_of_icons()),
            fill_organizations=course_organizations,
            fill_plan=True,
            fill_texts={
                "course_assessment": "CKEditorPlugin",
                "course_description": "CKEditorPlugin",
                "course_introduction": "PlainTextPlugin",
                "course_format": "CKEditorPlugin",
                "course_prerequisites": "CKEditorPlugin",
                "course_skills": "CKEditorPlugin",
            },
        )
        course.create_permissions_for_organization(course_organizations[0])
        courses.append(course)

        # Add extra information
        for language in course.extended_object.get_languages():
            placeholder = course.extended_object.placeholders.get(
                slot="course_information")
            nb_half_rows = 2 * random.randint(0, 1)  # nosec
            nb_full_rows = random.randint(0, 2)  # nosec
            nb_cards = 4 * random.randint(0, 1)  # nosec

            # Partners
            if nb_half_rows or nb_full_rows:
                partner_section = add_plugin(
                    language=language,
                    placeholder=placeholder,
                    plugin_type="SectionPlugin",
                    title=defaults.COURSE_CONTENT[language]["partners_title"],
                )
            for _i in range(nb_half_rows):
                glimpse_data = factory.build(
                    dict,
                    FACTORY_CLASS=GlimpseFactory,
                    variant=glimpse_defaults.ROW_HALF,
                    image=image_getter(pick_image("logo")()),
                )
                glimpse_data["image"].save()
                add_plugin(
                    language=language,
                    placeholder=placeholder,
                    plugin_type="GlimpsePlugin",
                    target=partner_section,
                    **glimpse_data,
                )
            for _i in range(nb_full_rows):
                glimpse_data = factory.build(
                    dict,
                    FACTORY_CLASS=GlimpseFactory,
                    variant=glimpse_defaults.ROW_FULL,
                    image=image_getter(pick_image("logo")()),
                )
                glimpse_data["image"].save()
                add_plugin(
                    language=language,
                    placeholder=placeholder,
                    plugin_type="GlimpsePlugin",
                    target=partner_section,
                    **glimpse_data,
                )
            # Sponsors
            if nb_cards:
                sponsor_section = add_plugin(
                    language=language,
                    placeholder=placeholder,
                    plugin_type="SectionPlugin",
                    title=defaults.COURSE_CONTENT[language]["sponsors_title"],
                )
            for _i in range(nb_cards):
                glimpse_data = factory.build(
                    dict,
                    FACTORY_CLASS=GlimpseFactory,
                    variant=glimpse_defaults.CARD_SQUARE,
                    image=image_getter(pick_image("logo")()),
                )
                glimpse_data["image"].save()
                add_plugin(
                    language=language,
                    placeholder=placeholder,
                    plugin_type="GlimpsePlugin",
                    target=sponsor_section,
                    **glimpse_data,
                )

        # Add a random number of course runs to the course
        nb_course_runs = get_number_of_course_runs()
        # pick a subset of languages for this course (otherwise all courses will have more or
        # less all the languages across their course runs!)
        languages_subset = random.sample(
            ["de", "en", "es", "fr", "it", "nl"],
            random.randint(1, 4)  # nosec
        )
        for i in range(nb_course_runs):
            course_run = factories.CourseRunFactory(
                __sequence=i,
                languages=random.sample(
                    languages_subset,
                    random.randint(1, len(languages_subset))  # nosec
                ),
                direct_course=course,
                resource_link=
                f"{lms_endpoint}/courses/course-v1:edX+DemoX+Demo_Course/info",
            )
            for language in course.extended_object.get_languages():
                with translation.override(language):
                    models.CourseRunTranslation.objects.update_or_create(
                        master=course_run,
                        language_code=language,
                        defaults={"title": _(f"Run {i:d}")},
                    )

        # Publish the course in all languages
        for language in course.extended_object.get_languages():
            course.extended_object.publish(language)

    # Create blog posts under the `News` page
    blogposts = []
    for _i in range(defaults.NB_OBJECTS["blogposts"]):
        post = factories.BlogPostFactory.create(
            page_in_navigation=True,
            page_languages=["en", "fr"],
            page_parent=pages_created["blogposts"],
            fill_cover=pick_image("cover"),
            fill_excerpt=True,
            fill_body=True,
            fill_categories=[
                *random.sample(levels, defaults.NB_OBJECTS["blogpost_levels"]),
                *random.sample(tags, defaults.NB_OBJECTS["blogpost_tags"]),
            ],
            fill_author=random.sample(persons, 1),
            should_publish=True,
        )
        blogposts.append(post)

    # Create programs under the `Programs` page
    programs = []
    for _i in range(defaults.NB_OBJECTS["programs"]):
        program = factories.ProgramFactory.create(
            page_in_navigation=True,
            page_languages=["en", "fr"],
            page_parent=pages_created["programs"],
            fill_cover=pick_image("cover"),
            fill_excerpt=True,
            fill_body=True,
            fill_courses=[
                *random.sample(courses,
                               defaults.NB_OBJECTS["programs_courses"])
            ],
            should_publish=True,
        )
        programs.append(program)

    # Create some content on the programs list page
    placeholder = pages_created["programs"].placeholders.get(
        slot="maincontent")

    for language in pages_created["programs"].get_languages():
        create_text_plugin(
            pages_created["programs"],
            placeholder,
            nb_paragraphs=random.randint(3, 4),  # nosec
            languages=[language],
            plugin_type="TextPlugin",
        )

        # Once content has been added we must publish again homepage
        pages_created["programs"].publish(language)

    # Once everything has been created, use some content to create a homepage
    placeholder = pages_created["home"].placeholders.get(slot="maincontent")

    # - Get a banner image
    banner = image_getter(pick_image("banner")())

    # - Get a logo image
    logo = image_getter(pick_image("logo")())

    # - Create the home page in each language
    for language, content in defaults.HOMEPAGE_CONTENT.items():
        # Add a banner
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="LargeBannerPlugin",
            title=content["banner_title"],
            background_image=banner,
            content=content["banner_content"],
            template=content["banner_template"],
        )
        # Add highlighted courses with a button
        courses_section = add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="SectionPlugin",
            title=content["courses_title"],
            template=content["section_template"],
        )
        for course in random.sample(courses,
                                    defaults.NB_OBJECTS["home_courses"]):
            add_plugin(
                language=language,
                placeholder=placeholder,
                plugin_type="CoursePlugin",
                target=courses_section,
                page=course.extended_object,
            )
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="LinkPlugin",
            target=courses_section,
            name=content["courses_button_title"],
            template=content["button_template_name"],
            internal_link=pages_created["courses"],
        )

        # Add highlighted blogposts
        blogposts_section = add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="SectionPlugin",
            title=content["blogposts_title"],
            template=content["section_template"],
        )
        for blogpost in random.sample(blogposts,
                                      defaults.NB_OBJECTS["home_blogposts"]):
            add_plugin(
                language=language,
                placeholder=placeholder,
                plugin_type="BlogPostPlugin",
                target=blogposts_section,
                page=blogpost.extended_object,
            )
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="LinkPlugin",
            target=blogposts_section,
            name=content["blogposts_button_title"],
            template=content["button_template_name"],
            internal_link=pages_created["blogposts"],
        )

        # Add highlighted programs
        programs_section = add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="SectionPlugin",
            title=content["programs_title"],
            template=content["section_template"],
        )
        for program in random.sample(programs,
                                     defaults.NB_OBJECTS["home_programs"]):
            add_plugin(
                language=language,
                placeholder=placeholder,
                plugin_type="ProgramPlugin",
                target=programs_section,
                page=program.extended_object,
            )
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="LinkPlugin",
            target=programs_section,
            name=content["programs_button_title"],
            template=content["button_template_name"],
            internal_link=pages_created["programs"],
        )

        # Add highlighted organizations
        organizations_section = add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="SectionPlugin",
            title=content["organizations_title"],
            template=content["section_template"],
        )
        for organization in random.sample(
                organizations, defaults.NB_OBJECTS["home_organizations"]):
            add_plugin(
                language=language,
                placeholder=placeholder,
                plugin_type="OrganizationPlugin",
                target=organizations_section,
                page=organization.extended_object,
            )
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="LinkPlugin",
            target=organizations_section,
            name=content["organizations_button_title"],
            template=content["button_template_name"],
            internal_link=pages_created["organizations"],
        )

        # Add highlighted subjects
        subjects_section = add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="SectionPlugin",
            title=content["subjects_title"],
            template=content["section_template"],
        )
        for subject in random.sample(subjects,
                                     defaults.NB_OBJECTS["home_subjects"]):
            add_plugin(
                language=language,
                placeholder=placeholder,
                plugin_type="CategoryPlugin",
                target=subjects_section,
                page=subject.extended_object,
            )
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="LinkPlugin",
            target=subjects_section,
            name=content["subjects_button_title"],
            template=content["button_template_name"],
            internal_link=pages_created["categories"],
        )

        # Add highlighted persons
        persons_section = add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="SectionPlugin",
            title=content["persons_title"],
            template=content["section_template"],
        )
        for person in random.sample(persons,
                                    defaults.NB_OBJECTS["home_persons"]):
            add_plugin(
                language=language,
                placeholder=placeholder,
                plugin_type="PersonPlugin",
                target=persons_section,
                page=person.extended_object,
            )
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="LinkPlugin",
            target=persons_section,
            name=content["persons_button_title"],
            template=content["button_template_name"],
            internal_link=pages_created["persons"],
        )

        # Add Glimpse quotes with empty title
        quotes_section = add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="SectionPlugin",
            title="",
        )
        for _i in range(3):
            glimpse_data = factory.build(
                dict,
                FACTORY_CLASS=GlimpseFactory,
                variant=glimpse_defaults.QUOTE,
                title=None,
                image=image_getter(pick_image("portrait")()),
            )
            glimpse_data["image"].save()
            add_plugin(
                language=language,
                placeholder=placeholder,
                plugin_type="GlimpsePlugin",
                target=quotes_section,
                **glimpse_data,
            )

        # Add Glimpse cards with empty content
        cards_section = add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="SectionPlugin",
            title="",
        )
        for _i in range(4):
            glimpse_data = factory.build(
                dict,
                FACTORY_CLASS=GlimpseFactory,
                variant=glimpse_defaults.CARD_SQUARE,
                content=None,
                image=image_getter(pick_image("cover")()),
            )
            glimpse_data["image"].save()
            add_plugin(
                language=language,
                placeholder=placeholder,
                plugin_type="GlimpsePlugin",
                target=cards_section,
                **glimpse_data,
            )

        # Once content has been added we must publish again homepage
        pages_created["home"].publish(language)

    # Fill the single column sample page
    placeholder = pages_created["annex__about"].placeholders.get(
        slot="maincontent")

    # - Get a banner image
    banner = image_getter(pick_image("banner")())

    # - Get a logo image
    logo = image_getter(pick_image("logo")())

    # - Get a video
    video_sample = random.choice(factories.VIDEO_SAMPLE_LINKS)  # nosec

    # - Create sample page in each language
    for language, content in defaults.SINGLECOLUMN_CONTENT.items():
        # Add a banner
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="LargeBannerPlugin",
            title=content["banner_title"],
            background_image=banner,
            content=content["banner_content"],
            template=content["banner_template"],
        )
        # HTML paragraphs
        create_text_plugin(
            pages_created["annex__about"],
            placeholder,
            nb_paragraphs=random.randint(3, 4),  # nosec
            languages=[language],
            plugin_type="TextPlugin",
        )
        # A large video sample
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="VideoPlayerPlugin",
            label=video_sample.label,
            embed_link=video_sample.url,
            template="full-width",
        )
        # Section with some various plugins
        sample_section = add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="SectionPlugin",
            title=content["section_sample_title"],
            template=content["section_sample_template"],
        )
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="OrganizationPlugin",
            target=sample_section,
            page=random.choice(organizations).extended_object,  # nosec
        )
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="CoursePlugin",
            target=sample_section,
            page=random.choice(courses).extended_object,  # nosec
        )
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="OrganizationPlugin",
            target=sample_section,
            page=random.choice(organizations).extended_object,  # nosec
        )
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="BlogPostPlugin",
            target=sample_section,
            page=random.choice(blogposts).extended_object,  # nosec
        )
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="LinkPlugin",
            target=sample_section,
            name=content["section_sample_button_title"],
            template=content["button_template_name"],
            internal_link=pages_created["home"],
        )
        # Add a licence
        if licences:
            add_plugin(
                language=language,
                placeholder=placeholder,
                plugin_type="LicencePlugin",
                licence=random.choice(licences),  # nosec
            )
        # Add a simple picture entry
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="SimplePicturePlugin",
            picture=logo,
        )
        # Add a plain text
        text = factory.Faker(
            "text",
            max_nb_chars=random.randint(150, 250)  # nosec
        ).evaluate(None, None, {"locale": language})
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="PlainTextPlugin",
            body=text,
        )

        # Once content has been added we must publish again the about page
        pages_created["annex__about"].publish(language)

    # Create a sitemap page
    placeholder = pages_created["annex__sitemap"].placeholders.get(
        slot="maincontent")

    for language in pages_created["annex__sitemap"].get_languages():
        parent_instance = add_plugin(language=language,
                                     placeholder=placeholder,
                                     plugin_type="HTMLSitemapPlugin")
        for name, params in defaults.SITEMAP_PAGE_PARAMS.items():
            add_plugin(
                language=language,
                placeholder=placeholder,
                plugin_type="HTMLSitemapPagePlugin",
                target=parent_instance,
                root_page=pages_created[name],
                **params,
            )

        # Once content has been added we must publish again the sitemap
        pages_created["annex__sitemap"].publish(language)